├── .github └── FUNDING.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── bestline.c ├── bestline.gif ├── bestline.h ├── example.c └── multi.c /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [jart] 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | ape.lds 3 | history.txt 4 | cosmopolitan.h 5 | cosmopolitan.a 6 | bestline_example 7 | bestline_example.com 8 | bestline_example.com.dbg 9 | bestline_multi 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Bestline is released under the 2-clause BSD license. 2 | 3 | Copyright (c) 2018-2021 Justine Tunney 4 | Copyright (c) 2010-2016 Salvatore Sanfilippo 5 | Copyright (c) 2010-2013 Pieter Noordhuis 6 | 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are 11 | met: 12 | 13 | * Redistributions of source code must retain the above copyright 14 | notice, this list of conditions and the following disclaimer. 15 | 16 | * Redistributions in binary form must reproduce the above copyright 17 | notice, this list of conditions and the following disclaimer in the 18 | documentation and/or other materials provided with the distribution. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: bestline_example bestline_multi 2 | 3 | bestline_example: bestline.o example.o 4 | $(CC) $(LDFLAGS) bestline.o example.o -o $@ 5 | 6 | bestline_multi: bestline.o multi.o 7 | $(CC) $(LDFLAGS) bestline.o multi.o -o $@ 8 | 9 | bestline.o: bestline.c bestline.h Makefile 10 | example.o: example.c bestline.h Makefile 11 | multi.o: multi.c bestline.h Makefile 12 | 13 | libbestline.so: bestline.c 14 | $(CC) $(LDFLAGS) -fPIC -shared bestline.c -o $@ 15 | 16 | clean: 17 | rm -f bestline_example bestline.o example.o bestline_example.com bestline_example.com.dbg multi.o bestline_multi libbestline.so 18 | 19 | ################################################################################ 20 | # compile on linux the demo as a binary that runs on seven operating systems 21 | 22 | bestline_example.com: bestline_example.com.dbg 23 | objcopy -S -O binary $< $@ 24 | bestline_example.com.dbg: bestline.c example.c crt.o ape.o ape.lds cosmopolitan.a cosmopolitan.h 25 | gcc -g -Os -static -fno-pie -no-pie -mno-red-zone -nostdlib -nostdinc -fno-omit-frame-pointer -pg -mnop-mcount -o $@ bestline.c example.c -Wl,--gc-sections -fuse-ld=bfd -Wl,-T,ape.lds -include cosmopolitan.h crt.o ape.o cosmopolitan.a 26 | bestline_multi.com: bestline_multi.com.dbg 27 | objcopy -S -O binary $< $@ 28 | bestline_multi.com.dbg: bestline.c multi.c crt.o ape.o ape.lds cosmopolitan.a cosmopolitan.h 29 | gcc -g -Os -static -fno-pie -no-pie -mno-red-zone -nostdlib -nostdinc -fno-omit-frame-pointer -pg -mnop-mcount -o $@ bestline.c example.c -Wl,--gc-sections -fuse-ld=bfd -Wl,-T,ape.lds -include cosmopolitan.h crt.o ape.o cosmopolitan.a 30 | crt.o:; wget --compression=gzip https://justine.lol/cosmopolitan/crt.o 31 | ape.o:; wget --compression=gzip https://justine.lol/cosmopolitan/ape.o 32 | ape.lds:; wget --compression=gzip https://justine.lol/cosmopolitan/ape.lds 33 | cosmopolitan.h:; wget --compression=gzip https://justine.lol/cosmopolitan/cosmopolitan.h 34 | cosmopolitan.a:; wget --compression=gzip https://justine.lol/cosmopolitan/cosmopolitan.a 35 | 36 | ################################################################################ 37 | # make sure it compiles in weird environments 38 | 39 | check: 40 | gcc -c -Wall -Wextra -O3 -o /tmp/bestline.o bestline.c 41 | g++ -xc++ -c -Wall -Wextra -O3 -o /tmp/bestline.o bestline.c 42 | gcc -pedantic -std=c99 -c -Wall -Wextra -O3 -o /tmp/bestline.o bestline.c 43 | clang -c -Wall -Wextra -Wall -Wextra -O3 -o /tmp/bestline.o bestline.c 44 | clang++ -xc++ -c -Wall -Wextra -Wall -Wextra -O3 -o /tmp/bestline.o bestline.c 45 | clang -pedantic -std=c99 -c -Wall -Wextra -O3 -o /tmp/bestline.o bestline.c 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bestline 2 | 3 | Library for interactive pseudoteletypewriter command 4 | sessions using ANSI Standard X3.64 control sequences. 5 | 6 | ![Bestline Demo Video GIF](bestline.gif) 7 | 8 | ## Overview 9 | 10 | This is a single-file, no-dependencies C or C++ library that makes it as 11 | easy as possible to display a command prompt that asks the user for 12 | input. It supports Emacs editing shortcuts, history search, completion / 13 | hint callback, and UTF-8 editing under a BSD-2 license. 14 | 15 | Bestline is a fork of [linenoise](https://github.com/antirez/linenoise/) 16 | (a popular GNU Readline alternative) that fixes its bugs and adds the 17 | missing features while reducing binary footprint (surprisingly) by 18 | removing bloated dependencies, which means you can finally have a 19 | permissively-licensed command prompt w/ a 38kb footprint that's nearly 20 | as good as GNU Readline. 21 | 22 | ``` 23 | $ CC="cc -s -static -Os -DNDEBUG" make 24 | $ ls -hal bestline_example 25 | -rwxr-xr-x 1 jart jart 38K Sep 19 21:41 bestline_example 26 | ``` 27 | 28 | # Example 29 | 30 | This example will save history to `~/.foo_history`. It's 50kb when 31 | statically linked with Cosmopolitan Libc. 32 | 33 | ```c 34 | #include 35 | #include "bestline.h" 36 | main() { 37 | char *line; 38 | while ((line = bestlineWithHistory("IN> ", "foo"))) { 39 | fputs("OUT> ", stdout); 40 | fputs(line, stdout); 41 | fputs("\n", stdout); 42 | free(line); 43 | } 44 | } 45 | ``` 46 | 47 | ## Shortcuts 48 | 49 | ``` 50 | CTRL-E END 51 | CTRL-A START 52 | CTRL-B BACK 53 | CTRL-F FORWARD 54 | CTRL-L CLEAR 55 | CTRL-H BACKSPACE 56 | CTRL-D DELETE 57 | CTRL-Y YANK 58 | CTRL-D EOF (IF EMPTY) 59 | CTRL-N NEXT HISTORY 60 | CTRL-P PREVIOUS HISTORY 61 | CTRL-R SEARCH HISTORY 62 | CTRL-G CANCEL SEARCH 63 | ALT-< BEGINNING OF HISTORY 64 | ALT-> END OF HISTORY 65 | ALT-F FORWARD WORD 66 | ALT-B BACKWARD WORD 67 | CTRL-ALT-F FORWARD EXPR 68 | CTRL-ALT-B BACKWARD EXPR 69 | ALT-RIGHT FORWARD EXPR 70 | ALT-LEFT BACKWARD EXPR 71 | CTRL-K KILL LINE FORWARDS 72 | CTRL-U KILL LINE BACKWARDS 73 | ALT-H KILL WORD BACKWARDS 74 | CTRL-W KILL WORD BACKWARDS 75 | CTRL-ALT-H KILL WORD BACKWARDS 76 | ALT-D KILL WORD FORWARDS 77 | ALT-Y ROTATE KILL RING AND YANK AGAIN 78 | ALT-\ SQUEEZE ADJACENT WHITESPACE 79 | CTRL-T TRANSPOSE 80 | ALT-T TRANSPOSE WORD 81 | ALT-U UPPERCASE WORD 82 | ALT-L LOWERCASE WORD 83 | ALT-C CAPITALIZE WORD 84 | CTRL-C INTERRUPT PROCESS 85 | CTRL-Z SUSPEND PROCESS 86 | CTRL-\ QUIT PROCESS 87 | CTRL-S PAUSE OUTPUT 88 | CTRL-Q UNPAUSE OUTPUT (IF PAUSED) 89 | CTRL-Q ESCAPED INSERT 90 | CTRL-SPACE SET MARK 91 | CTRL-X CTRL-X GOTO MARK 92 | CTRL-Z SUSPEND PROCESS 93 | ``` 94 | 95 | ### ProTip 96 | 97 | Remap CAPS LOCK to CTRL. 98 | 99 | ## Requirements 100 | 101 | You have to use an ANSI UTF-8 terminal that supports VT100 codes. 102 | 103 | ## Changes 104 | 105 | Here's what we've changed compared to 106 | [linenoise](https://github.com/antirez/linenoise/): 107 | 108 | - Remove bell 109 | - Add kill ring 110 | - Fix flickering 111 | - Add UTF-8 editing 112 | - Add CTRL-R search 113 | - React to terminal resizing 114 | - Don't generate .data section 115 | - Support terminal flow control 116 | - Make history loading 10x faster 117 | - Make multiline mode the only mode 118 | - Support unlimited input line length 119 | - Accommodate O_NONBLOCK file descriptors 120 | - Restore raw mode on process foregrounding 121 | - Make source code compatible with C++ compilers 122 | - Fix corruption issues by using generalized parsing 123 | - Implement nearly all GNU Readline editing shortcuts 124 | - Remove heavyweight dependencies like printf/sprintf 125 | - Remove ISIG→^C→EAGAIN hack and catch signals properly 126 | - Support running on Windows in MinTTY or CMD.EXE on Win10+ 127 | - Support diacritics, русский, Ελληνικά, 漢字, 仮名, 한글 128 | 129 | ## Readability 130 | 131 | This codebase aims to follow in antirez's tradition of writing beautiful 132 | programs, that solve extremely difficult technical problems in the most 133 | elegant way possible. The original Linenoise source code is sort of like 134 | an old DeLorean where it's simple and beautiful, but has a lot of things 135 | broken about it that need to be fixed, which gives you plenty of reasons 136 | to sit down and fix things to fully appreciate its beauty. 137 | 138 | There are, however, some differences in style. antirez generally optimizes 139 | for fewer lines of code even if it makes the binary footprint larger and 140 | with poor edge case handling and cultural biases presumably to preserve 141 | its accessibility and value as an educational tool. For example, one of 142 | the biggest issues with Linenoise, was that pressing the wrong key on 143 | the keyboard would mess with the state and garble input since it didn't 144 | actually parse ANSI codes or even multibyte characters. 145 | 146 | While this project has addressed many of Linenoise's shortcomings, we've 147 | sought to do it in a way that carries on the antirez's tradition of simple 148 | elegant hackable code. It is our hope that should you find opportunities 149 | for improvement in this codebase that you'll find it equally pleasurable 150 | to work with. 151 | 152 | ## Portability 153 | 154 | Bestline is written in portable ANSI C99 that conforms to POSIX. We 155 | recommend using Cosmopolitan Libc since it produces binaries that work 156 | on any operating system including Windows. 157 | 158 | Portability across terminals is achieved because literally everything 159 | these days supports VT100 control codes which were standardized by ANSI 160 | back in the 1970s. This library ignores platform-specific norms for 161 | multibyte encoding and it also ignores antiquated terminal capability 162 | databases. Libraries like ncurses were designed to reduce bandwidth on 163 | 300 bit per second modems. They're bloated and huge because they needed 164 | to implement workarounds to all the "incompatible by design" engineering 165 | practices used by terminal platforms in the '70s in '80s. 166 | 167 | Corporate America has long since moved on to making GUI platforms 168 | incompatible instead. Even the Windows command prompt supports VT100 and 169 | XTERM sequences these days. Seriously. It's 2021 and everyone in the 170 | world finally agrees on UTF-8 and ANSI VT100 style command sequences. 171 | That's why Bestline is now, for the first time in history, able to offer 172 | you a fully featured experience using simple bloat-free code. 173 | 174 | ## Contributing 175 | 176 | We'd love to accept your pull requests! Please send an email beforehand 177 | to Justine Tunney saying that you intend to assign 178 | her the copyright to the changes you contribute to Bestline. 179 | 180 | Please do not contribute changes that have `#ifdef` statements. We don't 181 | care if MSVC printed a warning, and we won't accept Windows torture code 182 | since Windows compatibility can be abstracted by Cosmopolitan Libc which 183 | does C on Windows better than Windows does considering how there's about 184 | ten different incompatible libc implementations, provided by the Windows 185 | platform, and they have a history of doing things like adding telemetry. 186 | 187 | ## License 188 | 189 | Bestline is released under the 2-clause BSD license. You have the 190 | freedom to copy the Bestline source code into your codebase, but you 191 | have to keep the license notice at the top of the file. You also have 192 | the freedom to distribute your app as a closed-source binary, but you 193 | have to embed the copyright notice in the executable. We've added an 194 | `.ident` assembly directive to the top of the source code file which 195 | should automatically take care of binary notice compliance. 196 | 197 | ``` 198 | The BSD-2 License 199 | 200 | Copyright 2018-2021 Justine Tunney 201 | Copyright 2010-2016 Salvatore Sanfilippo 202 | Copyright 2010-2013 Pieter Noordhuis 203 | 204 | All rights reserved. 205 | 206 | Redistribution and use in source and binary forms, with or without 207 | modification, are permitted provided that the following conditions are 208 | met: 209 | 210 | * Redistributions of source code must retain the above copyright 211 | notice, this list of conditions and the following disclaimer. 212 | 213 | * Redistributions in binary form must reproduce the above copyright 214 | notice, this list of conditions and the following disclaimer in the 215 | documentation and/or other materials provided with the distribution. 216 | 217 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 218 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 219 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 220 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 221 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 222 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 223 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 224 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 225 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 226 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 227 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 228 | ``` 229 | 230 | ## Donations 231 | 232 | Please consider tipping the author at 233 | since she needs your support in order to keep going building cool tools 234 | and libraries that serve the public interest. So if you like what you've 235 | seen and want to encourage more, please consider granting recognition. 236 | -------------------------------------------------------------------------------- /bestline.c: -------------------------------------------------------------------------------- 1 | /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8 -*-│ 2 | │ vi: set et 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 | │ CTRL-J INSERT NEWLINE │ 68 | │ ALT-< BEGINNING OF HISTORY │ 69 | │ ALT-> END OF HISTORY │ 70 | │ ALT-F FORWARD WORD │ 71 | │ ALT-B BACKWARD WORD │ 72 | │ CTRL-ALT-F FORWARD EXPR │ 73 | │ CTRL-ALT-B BACKWARD EXPR │ 74 | │ ALT-RIGHT FORWARD EXPR │ 75 | │ ALT-LEFT BACKWARD EXPR │ 76 | │ ALT-SHIFT-B BARF EXPR │ 77 | │ ALT-SHIFT-S SLURP EXPR │ 78 | │ ALT-SHIFT-R RAISE EXPR │ 79 | │ CTRL-K KILL LINE FORWARDS │ 80 | │ CTRL-U KILL LINE BACKWARDS │ 81 | │ ALT-H KILL WORD BACKWARDS │ 82 | │ CTRL-W KILL WORD BACKWARDS │ 83 | │ CTRL-ALT-H KILL WORD BACKWARDS │ 84 | │ ALT-D KILL WORD FORWARDS │ 85 | │ ALT-Y ROTATE KILL RING AND YANK AGAIN │ 86 | │ ALT-\ SQUEEZE ADJACENT WHITESPACE │ 87 | │ CTRL-T TRANSPOSE │ 88 | │ ALT-T TRANSPOSE WORD │ 89 | │ ALT-U UPPERCASE WORD │ 90 | │ ALT-L LOWERCASE WORD │ 91 | │ ALT-C CAPITALIZE WORD │ 92 | │ CTRL-C CTRL-C INTERRUPT PROCESS │ 93 | │ CTRL-Z SUSPEND PROCESS │ 94 | │ CTRL-\ QUIT PROCESS │ 95 | │ CTRL-S PAUSE OUTPUT │ 96 | │ CTRL-Q UNPAUSE OUTPUT (IF PAUSED) │ 97 | │ CTRL-Q ESCAPED INSERT │ 98 | │ CTRL-SPACE SET MARK │ 99 | │ CTRL-X CTRL-X GOTO MARK │ 100 | │ PROTIP REMAP CAPS LOCK TO CTRL │ 101 | │ │ 102 | ╞══════════════════════════════════════════════════════════════════════════════╡ 103 | │ │ 104 | │ Copyright 2018-2021 Justine Tunney │ 105 | │ Copyright 2010-2016 Salvatore Sanfilippo │ 106 | │ Copyright 2010-2013 Pieter Noordhuis │ 107 | │ │ 108 | │ All rights reserved. │ 109 | │ │ 110 | │ Redistribution and use in source and binary forms, with or without │ 111 | │ modification, are permitted provided that the following conditions are │ 112 | │ met: │ 113 | │ │ 114 | │ * Redistributions of source code must retain the above copyright │ 115 | │ notice, this list of conditions and the following disclaimer. │ 116 | │ │ 117 | │ * Redistributions in binary form must reproduce the above copyright │ 118 | │ notice, this list of conditions and the following disclaimer in the │ 119 | │ documentation and/or other materials provided with the distribution. │ 120 | │ │ 121 | │ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS │ 122 | │ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT │ 123 | │ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR │ 124 | │ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT │ 125 | │ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, │ 126 | │ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT │ 127 | │ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, │ 128 | │ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY │ 129 | │ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT │ 130 | │ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE │ 131 | │ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. │ 132 | │ │ 133 | ╚─────────────────────────────────────────────────────────────────────────────*/ 134 | #include "bestline.h" 135 | 136 | #define _POSIX_C_SOURCE 1 /* so GCC builds in ANSI mode */ 137 | #define _XOPEN_SOURCE 700 /* so GCC builds in ANSI mode */ 138 | #define _DARWIN_C_SOURCE 1 /* so SIGWINCH / IUTF8 on XNU */ 139 | #include 140 | #include 141 | #include 142 | #include 143 | #include 144 | #include 145 | #include 146 | #include 147 | #include 148 | #include 149 | #include 150 | #include 151 | #include 152 | #include 153 | #include 154 | #include 155 | #include 156 | #include 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 | 164 | __asm__(".ident\t\"\\n\\n\ 165 | Bestline (BSD-2)\\n\ 166 | Copyright 2018-2020 Justine Tunney \\n\ 167 | Copyright 2010-2016 Salvatore Sanfilippo \\n\ 168 | Copyright 2010-2013 Pieter Noordhuis \""); 169 | 170 | #ifndef BESTLINE_MAX_RING 171 | #define BESTLINE_MAX_RING 8 172 | #endif 173 | 174 | #ifndef BESTLINE_MAX_HISTORY 175 | #define BESTLINE_MAX_HISTORY 1024 176 | #endif 177 | 178 | #define BESTLINE_HISTORY_PREV +1 179 | #define BESTLINE_HISTORY_NEXT -1 180 | 181 | #define Ctrl(C) ((C) ^ 0100) 182 | #define Min(X, Y) ((Y) > (X) ? (X) : (Y)) 183 | #define Max(X, Y) ((Y) < (X) ? (X) : (Y)) 184 | #define Case(X, Y) \ 185 | case X: \ 186 | Y; \ 187 | break 188 | #define Read16le(X) ((255 & (X)[0]) << 000 | (255 & (X)[1]) << 010) 189 | #define Read32le(X) \ 190 | ((unsigned)(255 & (X)[0]) << 000 | (unsigned)(255 & (X)[1]) << 010 | \ 191 | (unsigned)(255 & (X)[2]) << 020 | (unsigned)(255 & (X)[3]) << 030) 192 | 193 | struct abuf { 194 | char *b; 195 | unsigned len; 196 | unsigned cap; 197 | }; 198 | 199 | struct rune { 200 | unsigned c; 201 | unsigned n; 202 | }; 203 | 204 | struct bestlineRing { 205 | unsigned i; 206 | char *p[BESTLINE_MAX_RING]; 207 | }; 208 | 209 | /* The bestlineState structure represents the state during line editing. 210 | * We pass this state to functions implementing specific editing 211 | * functionalities. */ 212 | struct bestlineState { 213 | int ifd; /* terminal stdin file descriptor */ 214 | int ofd; /* terminal stdout file descriptor */ 215 | struct winsize ws; /* rows and columns in terminal */ 216 | char *buf; /* edited line buffer */ 217 | const char *prompt; /* prompt to display */ 218 | int hindex; /* history index */ 219 | int rows; /* rows being used */ 220 | int oldpos; /* previous refresh cursor position */ 221 | unsigned buflen; /* edited line buffer size */ 222 | unsigned pos; /* current buffer index */ 223 | unsigned len; /* current edited line length */ 224 | unsigned mark; /* saved cursor position */ 225 | unsigned yi, yj; /* boundaries of last yank */ 226 | char seq[2][16]; /* keystroke history for yanking code */ 227 | char final; /* set to true on last update */ 228 | char dirty; /* if an update was squashed */ 229 | struct abuf full; /* used for multiline mode */ 230 | }; 231 | 232 | static const char *const kUnsupported[] = {"dumb", "cons25", "emacs"}; 233 | 234 | static int gotint; 235 | static int gotcont; 236 | static int gotwinch; 237 | static signed char rawmode; 238 | static char maskmode; 239 | static char emacsmode; 240 | static char llamamode; 241 | static char balancemode; 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 | /** 275 | * Returns monospace character width. 276 | * 277 | * This will be zero for control characters, combining marks, etc. 278 | * Chinese, Korean, Japanese, Emoji, etc. will have a width of 2, and 279 | * all other characters will be 1. 280 | * 281 | * This implementation is consistent with wcwidth() on Linux, except 282 | * that this won't return -1 for various character ranges. 283 | */ 284 | int bestlineCharacterWidth(int c) { 285 | if ((0x000 <= c && c <= 0x01F) || (0x07F <= c && c <= 0x09F) || 286 | (0x300 <= c && c <= 0x36f) || (0x483 <= c && c <= 0x489) || 287 | (0x591 <= c && c <= 0x5bd) || (0x5bf <= c && c <= 0x5bf) || 288 | (0x5c1 <= c && c <= 0x5c2) || (0x5c4 <= c && c <= 0x5c5) || 289 | (0x5c7 <= c && c <= 0x5c7) || (0x610 <= c && c <= 0x61a) || 290 | (0x61c <= c && c <= 0x61c) || (0x64b <= c && c <= 0x65f) || 291 | (0x670 <= c && c <= 0x670) || (0x6d6 <= c && c <= 0x6dc) || 292 | (0x6df <= c && c <= 0x6e4) || (0x6e7 <= c && c <= 0x6e8) || 293 | (0x6ea <= c && c <= 0x6ed) || (0x711 <= c && c <= 0x711) || 294 | (0x730 <= c && c <= 0x74a) || (0x7a6 <= c && c <= 0x7b0) || 295 | (0x7eb <= c && c <= 0x7f3) || (0x7fd <= c && c <= 0x7fd) || 296 | (0x816 <= c && c <= 0x819) || (0x81b <= c && c <= 0x823) || 297 | (0x825 <= c && c <= 0x827) || (0x829 <= c && c <= 0x82d) || 298 | (0x859 <= c && c <= 0x85b) || (0x898 <= c && c <= 0x89f) || 299 | (0x8ca <= c && c <= 0x8e1) || (0x8e3 <= c && c <= 0x902) || 300 | (0x93a <= c && c <= 0x93a) || (0x93c <= c && c <= 0x93c) || 301 | (0x941 <= c && c <= 0x948) || (0x94d <= c && c <= 0x94d) || 302 | (0x951 <= c && c <= 0x957) || (0x962 <= c && c <= 0x963) || 303 | (0x981 <= c && c <= 0x981) || (0x9bc <= c && c <= 0x9bc) || 304 | (0x9c1 <= c && c <= 0x9c4) || (0x9cd <= c && c <= 0x9cd) || 305 | (0x9e2 <= c && c <= 0x9e3) || (0x9fe <= c && c <= 0x9fe) || 306 | (0xa01 <= c && c <= 0xa02) || (0xa3c <= c && c <= 0xa3c) || 307 | (0xa41 <= c && c <= 0xa42) || (0xa47 <= c && c <= 0xa48) || 308 | (0xa4b <= c && c <= 0xa4d) || (0xa51 <= c && c <= 0xa51) || 309 | (0xa70 <= c && c <= 0xa71) || (0xa75 <= c && c <= 0xa75) || 310 | (0xa81 <= c && c <= 0xa82) || (0xabc <= c && c <= 0xabc) || 311 | (0xac1 <= c && c <= 0xac5) || (0xac7 <= c && c <= 0xac8) || 312 | (0xacd <= c && c <= 0xacd) || (0xae2 <= c && c <= 0xae3) || 313 | (0xafa <= c && c <= 0xaff) || (0xb01 <= c && c <= 0xb01) || 314 | (0xb3c <= c && c <= 0xb3c) || (0xb3f <= c && c <= 0xb3f) || 315 | (0xb41 <= c && c <= 0xb44) || (0xb4d <= c && c <= 0xb4d) || 316 | (0xb55 <= c && c <= 0xb56) || (0xb62 <= c && c <= 0xb63) || 317 | (0xb82 <= c && c <= 0xb82) || (0xbc0 <= c && c <= 0xbc0) || 318 | (0xbcd <= c && c <= 0xbcd) || (0xc00 <= c && c <= 0xc00) || 319 | (0xc04 <= c && c <= 0xc04) || (0xc3c <= c && c <= 0xc3c) || 320 | (0xc3e <= c && c <= 0xc40) || (0xc46 <= c && c <= 0xc48) || 321 | (0xc4a <= c && c <= 0xc4d) || (0xc55 <= c && c <= 0xc56) || 322 | (0xc62 <= c && c <= 0xc63) || (0xc81 <= c && c <= 0xc81) || 323 | (0xcbc <= c && c <= 0xcbc) || (0xcbf <= c && c <= 0xcbf) || 324 | (0xcc6 <= c && c <= 0xcc6) || (0xccc <= c && c <= 0xccd) || 325 | (0xce2 <= c && c <= 0xce3) || (0xd00 <= c && c <= 0xd01) || 326 | (0xd3b <= c && c <= 0xd3c) || (0xd41 <= c && c <= 0xd44) || 327 | (0xd4d <= c && c <= 0xd4d) || (0xd62 <= c && c <= 0xd63) || 328 | (0xd81 <= c && c <= 0xd81) || (0xdca <= c && c <= 0xdca) || 329 | (0xdd2 <= c && c <= 0xdd4) || (0xdd6 <= c && c <= 0xdd6) || 330 | (0xe31 <= c && c <= 0xe31) || (0xe34 <= c && c <= 0xe3a) || 331 | (0xe47 <= c && c <= 0xe4e) || (0xeb1 <= c && c <= 0xeb1) || 332 | (0xeb4 <= c && c <= 0xebc) || (0xec8 <= c && c <= 0xece) || 333 | (0xf18 <= c && c <= 0xf19) || (0xf35 <= c && c <= 0xf35) || 334 | (0xf37 <= c && c <= 0xf37) || (0xf39 <= c && c <= 0xf39) || 335 | (0xf71 <= c && c <= 0xf7e) || (0xf80 <= c && c <= 0xf84) || 336 | (0xf86 <= c && c <= 0xf87) || (0xf8d <= c && c <= 0xf97) || 337 | (0xf99 <= c && c <= 0xfbc) || (0xfc6 <= c && c <= 0xfc6) || 338 | (0x102d <= c && c <= 0x1030) || (0x1032 <= c && c <= 0x1037) || 339 | (0x1039 <= c && c <= 0x103a) || (0x103d <= c && c <= 0x103e) || 340 | (0x1058 <= c && c <= 0x1059) || (0x105e <= c && c <= 0x1060) || 341 | (0x1071 <= c && c <= 0x1074) || (0x1082 <= c && c <= 0x1082) || 342 | (0x1085 <= c && c <= 0x1086) || (0x108d <= c && c <= 0x108d) || 343 | (0x109d <= c && c <= 0x109d) || (0x1160 <= c && c <= 0x11ff) || 344 | (0x135d <= c && c <= 0x135f) || (0x1712 <= c && c <= 0x1714) || 345 | (0x1732 <= c && c <= 0x1733) || (0x1752 <= c && c <= 0x1753) || 346 | (0x1772 <= c && c <= 0x1773) || (0x17b4 <= c && c <= 0x17b5) || 347 | (0x17b7 <= c && c <= 0x17bd) || (0x17c6 <= c && c <= 0x17c6) || 348 | (0x17c9 <= c && c <= 0x17d3) || (0x17dd <= c && c <= 0x17dd) || 349 | (0x180b <= c && c <= 0x180f) || (0x1885 <= c && c <= 0x1886) || 350 | (0x18a9 <= c && c <= 0x18a9) || (0x1920 <= c && c <= 0x1922) || 351 | (0x1927 <= c && c <= 0x1928) || (0x1932 <= c && c <= 0x1932) || 352 | (0x1939 <= c && c <= 0x193b) || (0x1a17 <= c && c <= 0x1a18) || 353 | (0x1a1b <= c && c <= 0x1a1b) || (0x1a56 <= c && c <= 0x1a56) || 354 | (0x1a58 <= c && c <= 0x1a5e) || (0x1a60 <= c && c <= 0x1a60) || 355 | (0x1a62 <= c && c <= 0x1a62) || (0x1a65 <= c && c <= 0x1a6c) || 356 | (0x1a73 <= c && c <= 0x1a7c) || (0x1a7f <= c && c <= 0x1a7f) || 357 | (0x1ab0 <= c && c <= 0x1ace) || (0x1b00 <= c && c <= 0x1b03) || 358 | (0x1b34 <= c && c <= 0x1b34) || (0x1b36 <= c && c <= 0x1b3a) || 359 | (0x1b3c <= c && c <= 0x1b3c) || (0x1b42 <= c && c <= 0x1b42) || 360 | (0x1b6b <= c && c <= 0x1b73) || (0x1b80 <= c && c <= 0x1b81) || 361 | (0x1ba2 <= c && c <= 0x1ba5) || (0x1ba8 <= c && c <= 0x1ba9) || 362 | (0x1bab <= c && c <= 0x1bad) || (0x1be6 <= c && c <= 0x1be6) || 363 | (0x1be8 <= c && c <= 0x1be9) || (0x1bed <= c && c <= 0x1bed) || 364 | (0x1bef <= c && c <= 0x1bf1) || (0x1c2c <= c && c <= 0x1c33) || 365 | (0x1c36 <= c && c <= 0x1c37) || (0x1cd0 <= c && c <= 0x1cd2) || 366 | (0x1cd4 <= c && c <= 0x1ce0) || (0x1ce2 <= c && c <= 0x1ce8) || 367 | (0x1ced <= c && c <= 0x1ced) || (0x1cf4 <= c && c <= 0x1cf4) || 368 | (0x1cf8 <= c && c <= 0x1cf9) || (0x1dc0 <= c && c <= 0x1dff) || 369 | (0x200b <= c && c <= 0x200f) || (0x202a <= c && c <= 0x202e) || 370 | (0x2060 <= c && c <= 0x2064) || (0x2066 <= c && c <= 0x206f) || 371 | (0x20d0 <= c && c <= 0x20f0) || (0x2cef <= c && c <= 0x2cf1) || 372 | (0x2d7f <= c && c <= 0x2d7f) || (0x2de0 <= c && c <= 0x2dff) || 373 | (0x302a <= c && c <= 0x302d) || (0x3099 <= c && c <= 0x309a) || 374 | (0xa66f <= c && c <= 0xa672) || (0xa674 <= c && c <= 0xa67d) || 375 | (0xa69e <= c && c <= 0xa69f) || (0xa6f0 <= c && c <= 0xa6f1) || 376 | (0xa802 <= c && c <= 0xa802) || (0xa806 <= c && c <= 0xa806) || 377 | (0xa80b <= c && c <= 0xa80b) || (0xa825 <= c && c <= 0xa826) || 378 | (0xa82c <= c && c <= 0xa82c) || (0xa8c4 <= c && c <= 0xa8c5) || 379 | (0xa8e0 <= c && c <= 0xa8f1) || (0xa8ff <= c && c <= 0xa8ff) || 380 | (0xa926 <= c && c <= 0xa92d) || (0xa947 <= c && c <= 0xa951) || 381 | (0xa980 <= c && c <= 0xa982) || (0xa9b3 <= c && c <= 0xa9b3) || 382 | (0xa9b6 <= c && c <= 0xa9b9) || (0xa9bc <= c && c <= 0xa9bd) || 383 | (0xa9e5 <= c && c <= 0xa9e5) || (0xaa29 <= c && c <= 0xaa2e) || 384 | (0xaa31 <= c && c <= 0xaa32) || (0xaa35 <= c && c <= 0xaa36) || 385 | (0xaa43 <= c && c <= 0xaa43) || (0xaa4c <= c && c <= 0xaa4c) || 386 | (0xaa7c <= c && c <= 0xaa7c) || (0xaab0 <= c && c <= 0xaab0) || 387 | (0xaab2 <= c && c <= 0xaab4) || (0xaab7 <= c && c <= 0xaab8) || 388 | (0xaabe <= c && c <= 0xaabf) || (0xaac1 <= c && c <= 0xaac1) || 389 | (0xaaec <= c && c <= 0xaaed) || (0xaaf6 <= c && c <= 0xaaf6) || 390 | (0xabe5 <= c && c <= 0xabe5) || (0xabe8 <= c && c <= 0xabe8) || 391 | (0xabed <= c && c <= 0xabed) || (0xd7b0 <= c && c <= 0xd7c6) || 392 | (0xd7cb <= c && c <= 0xd7fb) || (0xfb1e <= c && c <= 0xfb1e) || 393 | (0xfe00 <= c && c <= 0xfe0f) || (0xfe20 <= c && c <= 0xfe2f) || 394 | (0xfeff <= c && c <= 0xfeff) || (0xfff9 <= c && c <= 0xfffb) || 395 | (0x101fd <= c && c <= 0x101fd) || (0x102e0 <= c && c <= 0x102e0) || 396 | (0x10376 <= c && c <= 0x1037a) || (0x10a01 <= c && c <= 0x10a03) || 397 | (0x10a05 <= c && c <= 0x10a06) || (0x10a0c <= c && c <= 0x10a0f) || 398 | (0x10a38 <= c && c <= 0x10a3a) || (0x10a3f <= c && c <= 0x10a3f) || 399 | (0x10ae5 <= c && c <= 0x10ae6) || (0x10d24 <= c && c <= 0x10d27) || 400 | (0x10eab <= c && c <= 0x10eac) || (0x10efd <= c && c <= 0x10eff) || 401 | (0x10f46 <= c && c <= 0x10f50) || (0x10f82 <= c && c <= 0x10f85) || 402 | (0x11001 <= c && c <= 0x11001) || (0x11038 <= c && c <= 0x11046) || 403 | (0x11070 <= c && c <= 0x11070) || (0x11073 <= c && c <= 0x11074) || 404 | (0x1107f <= c && c <= 0x11081) || (0x110b3 <= c && c <= 0x110b6) || 405 | (0x110b9 <= c && c <= 0x110ba) || (0x110c2 <= c && c <= 0x110c2) || 406 | (0x11100 <= c && c <= 0x11102) || (0x11127 <= c && c <= 0x1112b) || 407 | (0x1112d <= c && c <= 0x11134) || (0x11173 <= c && c <= 0x11173) || 408 | (0x11180 <= c && c <= 0x11181) || (0x111b6 <= c && c <= 0x111be) || 409 | (0x111c9 <= c && c <= 0x111cc) || (0x111cf <= c && c <= 0x111cf) || 410 | (0x1122f <= c && c <= 0x11231) || (0x11234 <= c && c <= 0x11234) || 411 | (0x11236 <= c && c <= 0x11237) || (0x1123e <= c && c <= 0x1123e) || 412 | (0x11241 <= c && c <= 0x11241) || (0x112df <= c && c <= 0x112df) || 413 | (0x112e3 <= c && c <= 0x112ea) || (0x11300 <= c && c <= 0x11301) || 414 | (0x1133b <= c && c <= 0x1133c) || (0x11340 <= c && c <= 0x11340) || 415 | (0x11366 <= c && c <= 0x1136c) || (0x11370 <= c && c <= 0x11374) || 416 | (0x11438 <= c && c <= 0x1143f) || (0x11442 <= c && c <= 0x11444) || 417 | (0x11446 <= c && c <= 0x11446) || (0x1145e <= c && c <= 0x1145e) || 418 | (0x114b3 <= c && c <= 0x114b8) || (0x114ba <= c && c <= 0x114ba) || 419 | (0x114bf <= c && c <= 0x114c0) || (0x114c2 <= c && c <= 0x114c3) || 420 | (0x115b2 <= c && c <= 0x115b5) || (0x115bc <= c && c <= 0x115bd) || 421 | (0x115bf <= c && c <= 0x115c0) || (0x115dc <= c && c <= 0x115dd) || 422 | (0x11633 <= c && c <= 0x1163a) || (0x1163d <= c && c <= 0x1163d) || 423 | (0x1163f <= c && c <= 0x11640) || (0x116ab <= c && c <= 0x116ab) || 424 | (0x116ad <= c && c <= 0x116ad) || (0x116b0 <= c && c <= 0x116b5) || 425 | (0x116b7 <= c && c <= 0x116b7) || (0x1171d <= c && c <= 0x1171f) || 426 | (0x11722 <= c && c <= 0x11725) || (0x11727 <= c && c <= 0x1172b) || 427 | (0x1182f <= c && c <= 0x11837) || (0x11839 <= c && c <= 0x1183a) || 428 | (0x1193b <= c && c <= 0x1193c) || (0x1193e <= c && c <= 0x1193e) || 429 | (0x11943 <= c && c <= 0x11943) || (0x119d4 <= c && c <= 0x119d7) || 430 | (0x119da <= c && c <= 0x119db) || (0x119e0 <= c && c <= 0x119e0) || 431 | (0x11a01 <= c && c <= 0x11a0a) || (0x11a33 <= c && c <= 0x11a38) || 432 | (0x11a3b <= c && c <= 0x11a3e) || (0x11a47 <= c && c <= 0x11a47) || 433 | (0x11a51 <= c && c <= 0x11a56) || (0x11a59 <= c && c <= 0x11a5b) || 434 | (0x11a8a <= c && c <= 0x11a96) || (0x11a98 <= c && c <= 0x11a99) || 435 | (0x11c30 <= c && c <= 0x11c36) || (0x11c38 <= c && c <= 0x11c3d) || 436 | (0x11c3f <= c && c <= 0x11c3f) || (0x11c92 <= c && c <= 0x11ca7) || 437 | (0x11caa <= c && c <= 0x11cb0) || (0x11cb2 <= c && c <= 0x11cb3) || 438 | (0x11cb5 <= c && c <= 0x11cb6) || (0x11d31 <= c && c <= 0x11d36) || 439 | (0x11d3a <= c && c <= 0x11d3a) || (0x11d3c <= c && c <= 0x11d3d) || 440 | (0x11d3f <= c && c <= 0x11d45) || (0x11d47 <= c && c <= 0x11d47) || 441 | (0x11d90 <= c && c <= 0x11d91) || (0x11d95 <= c && c <= 0x11d95) || 442 | (0x11d97 <= c && c <= 0x11d97) || (0x11ef3 <= c && c <= 0x11ef4) || 443 | (0x11f00 <= c && c <= 0x11f01) || (0x11f36 <= c && c <= 0x11f3a) || 444 | (0x11f40 <= c && c <= 0x11f40) || (0x11f42 <= c && c <= 0x11f42) || 445 | (0x13430 <= c && c <= 0x13440) || (0x13447 <= c && c <= 0x13455) || 446 | (0x16af0 <= c && c <= 0x16af4) || (0x16b30 <= c && c <= 0x16b36) || 447 | (0x16f4f <= c && c <= 0x16f4f) || (0x16f8f <= c && c <= 0x16f92) || 448 | (0x16fe4 <= c && c <= 0x16fe4) || (0x1bc9d <= c && c <= 0x1bc9e) || 449 | (0x1bca0 <= c && c <= 0x1bca3) || (0x1cf00 <= c && c <= 0x1cf2d) || 450 | (0x1cf30 <= c && c <= 0x1cf46) || (0x1d167 <= c && c <= 0x1d169) || 451 | (0x1d173 <= c && c <= 0x1d182) || (0x1d185 <= c && c <= 0x1d18b) || 452 | (0x1d1aa <= c && c <= 0x1d1ad) || (0x1d242 <= c && c <= 0x1d244) || 453 | (0x1da00 <= c && c <= 0x1da36) || (0x1da3b <= c && c <= 0x1da6c) || 454 | (0x1da75 <= c && c <= 0x1da75) || (0x1da84 <= c && c <= 0x1da84) || 455 | (0x1da9b <= c && c <= 0x1da9f) || (0x1daa1 <= c && c <= 0x1daaf) || 456 | (0x1e000 <= c && c <= 0x1e006) || (0x1e008 <= c && c <= 0x1e018) || 457 | (0x1e01b <= c && c <= 0x1e021) || (0x1e023 <= c && c <= 0x1e024) || 458 | (0x1e026 <= c && c <= 0x1e02a) || (0x1e08f <= c && c <= 0x1e08f) || 459 | (0x1e130 <= c && c <= 0x1e136) || (0x1e2ae <= c && c <= 0x1e2ae) || 460 | (0x1e2ec <= c && c <= 0x1e2ef) || (0x1e4ec <= c && c <= 0x1e4ef) || 461 | (0x1e8d0 <= c && c <= 0x1e8d6) || (0x1e944 <= c && c <= 0x1e94a) || 462 | (0xe0001 <= c && c <= 0xe0001) || (0xe0020 <= c && c <= 0xe007f) || 463 | (0xe0100 <= c && c <= 0xe01ef)) 464 | return 0; 465 | if ((0x1100 <= c && c <= 0x115f) || (0x231a <= c && c <= 0x231b) || 466 | (0x2329 <= c && c <= 0x232a) || (0x23e9 <= c && c <= 0x23ec) || 467 | (0x23f0 <= c && c <= 0x23f0) || (0x23f3 <= c && c <= 0x23f3) || 468 | (0x25fd <= c && c <= 0x25fe) || (0x2614 <= c && c <= 0x2615) || 469 | (0x2648 <= c && c <= 0x2653) || (0x267f <= c && c <= 0x267f) || 470 | (0x2693 <= c && c <= 0x2693) || (0x26a1 <= c && c <= 0x26a1) || 471 | (0x26aa <= c && c <= 0x26ab) || (0x26bd <= c && c <= 0x26be) || 472 | (0x26c4 <= c && c <= 0x26c5) || (0x26ce <= c && c <= 0x26ce) || 473 | (0x26d4 <= c && c <= 0x26d4) || (0x26ea <= c && c <= 0x26ea) || 474 | (0x26f2 <= c && c <= 0x26f3) || (0x26f5 <= c && c <= 0x26f5) || 475 | (0x26fa <= c && c <= 0x26fa) || (0x26fd <= c && c <= 0x26fd) || 476 | (0x2705 <= c && c <= 0x2705) || (0x270a <= c && c <= 0x270b) || 477 | (0x2728 <= c && c <= 0x2728) || (0x274c <= c && c <= 0x274c) || 478 | (0x274e <= c && c <= 0x274e) || (0x2753 <= c && c <= 0x2755) || 479 | (0x2757 <= c && c <= 0x2757) || (0x2795 <= c && c <= 0x2797) || 480 | (0x27b0 <= c && c <= 0x27b0) || (0x27bf <= c && c <= 0x27bf) || 481 | (0x2b1b <= c && c <= 0x2b1c) || (0x2b50 <= c && c <= 0x2b50) || 482 | (0x2b55 <= c && c <= 0x2b55) || (0x2e80 <= c && c <= 0x2e99) || 483 | (0x2e9b <= c && c <= 0x2ef3) || (0x2f00 <= c && c <= 0x2fd5) || 484 | (0x2ff0 <= c && c <= 0x3029) || (0x302e <= c && c <= 0x303e) || 485 | (0x3041 <= c && c <= 0x3096) || (0x309b <= c && c <= 0x30ff) || 486 | (0x3105 <= c && c <= 0x312f) || (0x3131 <= c && c <= 0x318e) || 487 | (0x3190 <= c && c <= 0x31e3) || (0x31ef <= c && c <= 0x321e) || 488 | (0x3220 <= c && c <= 0xa48c) || (0xa490 <= c && c <= 0xa4c6) || 489 | (0xa960 <= c && c <= 0xa97c) || (0xac00 <= c && c <= 0xd7a3) || 490 | (0xf900 <= c && c <= 0xfa6d) || (0xfa70 <= c && c <= 0xfad9) || 491 | (0xfe10 <= c && c <= 0xfe19) || (0xfe30 <= c && c <= 0xfe52) || 492 | (0xfe54 <= c && c <= 0xfe66) || (0xfe68 <= c && c <= 0xfe6b) || 493 | (0xff01 <= c && c <= 0xff60) || (0xffe0 <= c && c <= 0xffe6) || 494 | (0x16fe0 <= c && c <= 0x16fe3) || (0x16ff0 <= c && c <= 0x16ff1) || 495 | (0x17000 <= c && c <= 0x187f7) || (0x18800 <= c && c <= 0x18cd5) || 496 | (0x18d00 <= c && c <= 0x18d08) || (0x1aff0 <= c && c <= 0x1aff3) || 497 | (0x1aff5 <= c && c <= 0x1affb) || (0x1affd <= c && c <= 0x1affe) || 498 | (0x1b000 <= c && c <= 0x1b122) || (0x1b132 <= c && c <= 0x1b132) || 499 | (0x1b150 <= c && c <= 0x1b152) || (0x1b155 <= c && c <= 0x1b155) || 500 | (0x1b164 <= c && c <= 0x1b167) || (0x1b170 <= c && c <= 0x1b2fb) || 501 | (0x1f004 <= c && c <= 0x1f004) || (0x1f0cf <= c && c <= 0x1f0cf) || 502 | (0x1f18e <= c && c <= 0x1f18e) || (0x1f191 <= c && c <= 0x1f19a) || 503 | (0x1f200 <= c && c <= 0x1f202) || (0x1f210 <= c && c <= 0x1f23b) || 504 | (0x1f240 <= c && c <= 0x1f248) || (0x1f250 <= c && c <= 0x1f251) || 505 | (0x1f260 <= c && c <= 0x1f265) || (0x1f300 <= c && c <= 0x1f320) || 506 | (0x1f32d <= c && c <= 0x1f335) || (0x1f337 <= c && c <= 0x1f37c) || 507 | (0x1f37e <= c && c <= 0x1f393) || (0x1f3a0 <= c && c <= 0x1f3ca) || 508 | (0x1f3cf <= c && c <= 0x1f3d3) || (0x1f3e0 <= c && c <= 0x1f3f0) || 509 | (0x1f3f4 <= c && c <= 0x1f3f4) || (0x1f3f8 <= c && c <= 0x1f43e) || 510 | (0x1f440 <= c && c <= 0x1f440) || (0x1f442 <= c && c <= 0x1f4fc) || 511 | (0x1f4ff <= c && c <= 0x1f53d) || (0x1f54b <= c && c <= 0x1f54e) || 512 | (0x1f550 <= c && c <= 0x1f567) || (0x1f57a <= c && c <= 0x1f57a) || 513 | (0x1f595 <= c && c <= 0x1f596) || (0x1f5a4 <= c && c <= 0x1f5a4) || 514 | (0x1f5fb <= c && c <= 0x1f64f) || (0x1f680 <= c && c <= 0x1f6c5) || 515 | (0x1f6cc <= c && c <= 0x1f6cc) || (0x1f6d0 <= c && c <= 0x1f6d2) || 516 | (0x1f6d5 <= c && c <= 0x1f6d7) || (0x1f6dc <= c && c <= 0x1f6df) || 517 | (0x1f6eb <= c && c <= 0x1f6ec) || (0x1f6f4 <= c && c <= 0x1f6fc) || 518 | (0x1f7e0 <= c && c <= 0x1f7eb) || (0x1f7f0 <= c && c <= 0x1f7f0) || 519 | (0x1f90c <= c && c <= 0x1f93a) || (0x1f93c <= c && c <= 0x1f945) || 520 | (0x1f947 <= c && c <= 0x1f9ff) || (0x1fa70 <= c && c <= 0x1fa7c) || 521 | (0x1fa80 <= c && c <= 0x1fa88) || (0x1fa90 <= c && c <= 0x1fabd) || 522 | (0x1fabf <= c && c <= 0x1fac5) || (0x1face <= c && c <= 0x1fadb) || 523 | (0x1fae0 <= c && c <= 0x1fae8) || (0x1faf0 <= c && c <= 0x1faf8) || 524 | (0x20000 <= c && c <= 0x2a6df) || (0x2a700 <= c && c <= 0x2b739) || 525 | (0x2b740 <= c && c <= 0x2b81d) || (0x2b820 <= c && c <= 0x2cea1) || 526 | (0x2ceb0 <= c && c <= 0x2ebe0) || (0x2ebf0 <= c && c <= 0x2ee5d) || 527 | (0x2f800 <= c && c <= 0x2fa1d) || (0x30000 <= c && c <= 0x3134a) || 528 | (0x31350 <= c && c <= 0x323af)) 529 | return 2; 530 | return 1; 531 | } 532 | 533 | /** 534 | * Returns nonzero if 𝑐 isn't alphanumeric. 535 | * 536 | * Line reading interfaces generally define this operation as UNICODE 537 | * characters that aren't in the letter category (Lu, Ll, Lt, Lm, Lo) 538 | * and aren't in the number categorie (Nd, Nl, No). We also add a few 539 | * other things like blocks and emoji (So). 540 | */ 541 | char bestlineIsSeparator(unsigned c) { 542 | int m, l, r, n; 543 | if (c < 0200) { 544 | return !(('0' <= c && c <= '9') || ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')); 545 | } 546 | if (c <= 0xffff) { 547 | static const unsigned short kGlyphs[][2] = { 548 | {0x00aa, 0x00aa}, /* 1x English */ 549 | {0x00b2, 0x00b3}, /* 2x English Arabic */ 550 | {0x00b5, 0x00b5}, /* 1x Greek */ 551 | {0x00b9, 0x00ba}, /* 2x English Arabic */ 552 | {0x00bc, 0x00be}, /* 3x Vulgar English Arabic */ 553 | {0x00c0, 0x00d6}, /* 23x Watin */ 554 | {0x00d8, 0x00f6}, /* 31x Watin */ 555 | {0x0100, 0x02c1}, /* 450x Watin-AB,IPA,Spacemod */ 556 | {0x02c6, 0x02d1}, /* 12x Spacemod */ 557 | {0x02e0, 0x02e4}, /* 5x Spacemod */ 558 | {0x02ec, 0x02ec}, /* 1x Spacemod */ 559 | {0x02ee, 0x02ee}, /* 1x Spacemod */ 560 | {0x0370, 0x0374}, /* 5x Greek */ 561 | {0x0376, 0x0377}, /* 2x Greek */ 562 | {0x037a, 0x037d}, /* 4x Greek */ 563 | {0x037f, 0x037f}, /* 1x Greek */ 564 | {0x0386, 0x0386}, /* 1x Greek */ 565 | {0x0388, 0x038a}, /* 3x Greek */ 566 | {0x038c, 0x038c}, /* 1x Greek */ 567 | {0x038e, 0x03a1}, /* 20x Greek */ 568 | {0x03a3, 0x03f5}, /* 83x Greek */ 569 | {0x03f7, 0x0481}, /* 139x Greek */ 570 | {0x048a, 0x052f}, /* 166x Cyrillic */ 571 | {0x0531, 0x0556}, /* 38x Armenian */ 572 | {0x0560, 0x0588}, /* 41x Armenian */ 573 | {0x05d0, 0x05ea}, /* 27x Hebrew */ 574 | {0x0620, 0x064a}, /* 43x Arabic */ 575 | {0x0660, 0x0669}, /* 10x Arabic */ 576 | {0x0671, 0x06d3}, /* 99x Arabic */ 577 | {0x06ee, 0x06fc}, /* 15x Arabic */ 578 | {0x0712, 0x072f}, /* 30x Syriac */ 579 | {0x074d, 0x07a5}, /* 89x Syriac,Arabic2,Thaana */ 580 | {0x07c0, 0x07ea}, /* 43x NKo */ 581 | {0x0800, 0x0815}, /* 22x Samaritan */ 582 | {0x0840, 0x0858}, /* 25x Mandaic */ 583 | {0x0904, 0x0939}, /* 54x Devanagari */ 584 | {0x0993, 0x09a8}, /* 22x Bengali */ 585 | {0x09e6, 0x09f1}, /* 12x Bengali */ 586 | {0x0a13, 0x0a28}, /* 22x Gurmukhi */ 587 | {0x0a66, 0x0a6f}, /* 10x Gurmukhi */ 588 | {0x0a93, 0x0aa8}, /* 22x Gujarati */ 589 | {0x0b13, 0x0b28}, /* 22x Oriya */ 590 | {0x0c92, 0x0ca8}, /* 23x Kannada */ 591 | {0x0caa, 0x0cb3}, /* 10x Kannada */ 592 | {0x0ce6, 0x0cef}, /* 10x Kannada */ 593 | {0x0d12, 0x0d3a}, /* 41x Malayalam */ 594 | {0x0d85, 0x0d96}, /* 18x Sinhala */ 595 | {0x0d9a, 0x0db1}, /* 24x Sinhala */ 596 | {0x0de6, 0x0def}, /* 10x Sinhala */ 597 | {0x0e01, 0x0e30}, /* 48x Thai */ 598 | {0x0e8c, 0x0ea3}, /* 24x Lao */ 599 | {0x0f20, 0x0f33}, /* 20x Tibetan */ 600 | {0x0f49, 0x0f6c}, /* 36x Tibetan */ 601 | {0x109e, 0x10c5}, /* 40x Myanmar,Georgian */ 602 | {0x10d0, 0x10fa}, /* 43x Georgian */ 603 | {0x10fc, 0x1248}, /* 333x Georgian,Hangul,Ethiopic */ 604 | {0x13a0, 0x13f5}, /* 86x Cherokee */ 605 | {0x1401, 0x166d}, /* 621x Aboriginal */ 606 | {0x16a0, 0x16ea}, /* 75x Runic */ 607 | {0x1700, 0x170c}, /* 13x Tagalog */ 608 | {0x1780, 0x17b3}, /* 52x Khmer */ 609 | {0x1820, 0x1878}, /* 89x Mongolian */ 610 | {0x1a00, 0x1a16}, /* 23x Buginese */ 611 | {0x1a20, 0x1a54}, /* 53x Tai Tham */ 612 | {0x1a80, 0x1a89}, /* 10x Tai Tham */ 613 | {0x1a90, 0x1a99}, /* 10x Tai Tham */ 614 | {0x1b05, 0x1b33}, /* 47x Balinese */ 615 | {0x1b50, 0x1b59}, /* 10x Balinese */ 616 | {0x1b83, 0x1ba0}, /* 30x Sundanese */ 617 | {0x1bae, 0x1be5}, /* 56x Sundanese */ 618 | {0x1c90, 0x1cba}, /* 43x Georgian2 */ 619 | {0x1cbd, 0x1cbf}, /* 3x Georgian2 */ 620 | {0x1e00, 0x1f15}, /* 278x Watin-C,Greek2 */ 621 | {0x2070, 0x2071}, /* 2x Supersub */ 622 | {0x2074, 0x2079}, /* 6x Supersub */ 623 | {0x207f, 0x2089}, /* 11x Supersub */ 624 | {0x2090, 0x209c}, /* 13x Supersub */ 625 | {0x2100, 0x2117}, /* 24x Letterlike */ 626 | {0x2119, 0x213f}, /* 39x Letterlike */ 627 | {0x2145, 0x214a}, /* 6x Letterlike */ 628 | {0x214c, 0x218b}, /* 64x Letterlike,Numbery */ 629 | {0x21af, 0x21cd}, /* 31x Arrows */ 630 | {0x21d5, 0x21f3}, /* 31x Arrows */ 631 | {0x230c, 0x231f}, /* 20x Technical */ 632 | {0x232b, 0x237b}, /* 81x Technical */ 633 | {0x237d, 0x239a}, /* 30x Technical */ 634 | {0x23b4, 0x23db}, /* 40x Technical */ 635 | {0x23e2, 0x2426}, /* 69x Technical,ControlPictures */ 636 | {0x2460, 0x25b6}, /* 343x Enclosed,Boxes,Blocks,Shapes */ 637 | {0x25c2, 0x25f7}, /* 54x Shapes */ 638 | {0x2600, 0x266e}, /* 111x Symbols */ 639 | {0x2670, 0x2767}, /* 248x Symbols,Dingbats */ 640 | {0x2776, 0x27bf}, /* 74x Dingbats */ 641 | {0x2800, 0x28ff}, /* 256x Braille */ 642 | {0x2c00, 0x2c2e}, /* 47x Glagolitic */ 643 | {0x2c30, 0x2c5e}, /* 47x Glagolitic */ 644 | {0x2c60, 0x2ce4}, /* 133x Watin-D */ 645 | {0x2d00, 0x2d25}, /* 38x Georgian2 */ 646 | {0x2d30, 0x2d67}, /* 56x Tifinagh */ 647 | {0x2d80, 0x2d96}, /* 23x Ethiopic2 */ 648 | {0x2e2f, 0x2e2f}, /* 1x Punctuation2 */ 649 | {0x3005, 0x3007}, /* 3x CJK Symbols & Punctuation */ 650 | {0x3021, 0x3029}, /* 9x CJK Symbols & Punctuation */ 651 | {0x3031, 0x3035}, /* 5x CJK Symbols & Punctuation */ 652 | {0x3038, 0x303c}, /* 5x CJK Symbols & Punctuation */ 653 | {0x3041, 0x3096}, /* 86x Hiragana */ 654 | {0x30a1, 0x30fa}, /* 90x Katakana */ 655 | {0x3105, 0x312f}, /* 43x Bopomofo */ 656 | {0x3131, 0x318e}, /* 94x Hangul Compatibility Jamo */ 657 | {0x31a0, 0x31ba}, /* 27x Bopomofo Extended */ 658 | {0x31f0, 0x31ff}, /* 16x Katakana Phonetic Extensions */ 659 | {0x3220, 0x3229}, /* 10x Enclosed CJK Letters & Months */ 660 | {0x3248, 0x324f}, /* 8x Enclosed CJK Letters & Months */ 661 | {0x3251, 0x325f}, /* 15x Enclosed CJK Letters & Months */ 662 | {0x3280, 0x3289}, /* 10x Enclosed CJK Letters & Months */ 663 | {0x32b1, 0x32bf}, /* 15x Enclosed CJK Letters & Months */ 664 | {0x3400, 0x4db5}, /* 6582x CJK Unified Ideographs Extension A */ 665 | {0x4dc0, 0x9fef}, /* 21040x Yijing Hexagram, CJK Unified Ideographs */ 666 | {0xa000, 0xa48c}, /* 1165x Yi Syllables */ 667 | {0xa4d0, 0xa4fd}, /* 46x Lisu */ 668 | {0xa500, 0xa60c}, /* 269x Vai */ 669 | {0xa610, 0xa62b}, /* 28x Vai */ 670 | {0xa6a0, 0xa6ef}, /* 80x Bamum */ 671 | {0xa80c, 0xa822}, /* 23x Syloti Nagri */ 672 | {0xa840, 0xa873}, /* 52x Phags-pa */ 673 | {0xa882, 0xa8b3}, /* 50x Saurashtra */ 674 | {0xa8d0, 0xa8d9}, /* 10x Saurashtra */ 675 | {0xa900, 0xa925}, /* 38x Kayah Li */ 676 | {0xa930, 0xa946}, /* 23x Rejang */ 677 | {0xa960, 0xa97c}, /* 29x Hangul Jamo Extended-A */ 678 | {0xa984, 0xa9b2}, /* 47x Javanese */ 679 | {0xa9cf, 0xa9d9}, /* 11x Javanese */ 680 | {0xaa00, 0xaa28}, /* 41x Cham */ 681 | {0xaa50, 0xaa59}, /* 10x Cham */ 682 | {0xabf0, 0xabf9}, /* 10x Meetei Mayek */ 683 | {0xac00, 0xd7a3}, /* 11172x Hangul Syllables */ 684 | {0xf900, 0xfa6d}, /* 366x CJK Compatibility Ideographs */ 685 | {0xfa70, 0xfad9}, /* 106x CJK Compatibility Ideographs */ 686 | {0xfb1f, 0xfb28}, /* 10x Alphabetic Presentation Forms */ 687 | {0xfb2a, 0xfb36}, /* 13x Alphabetic Presentation Forms */ 688 | {0xfb46, 0xfbb1}, /* 108x Alphabetic Presentation Forms */ 689 | {0xfbd3, 0xfd3d}, /* 363x Arabic Presentation Forms-A */ 690 | {0xfe76, 0xfefc}, /* 135x Arabic Presentation Forms-B */ 691 | {0xff10, 0xff19}, /* 10x Dubs */ 692 | {0xff21, 0xff3a}, /* 26x Dubs */ 693 | {0xff41, 0xff5a}, /* 26x Dubs */ 694 | {0xff66, 0xffbe}, /* 89x Dubs */ 695 | {0xffc2, 0xffc7}, /* 6x Dubs */ 696 | {0xffca, 0xffcf}, /* 6x Dubs */ 697 | {0xffd2, 0xffd7}, /* 6x Dubs */ 698 | {0xffda, 0xffdc}, /* 3x Dubs */ 699 | }; 700 | l = 0; 701 | r = n = sizeof(kGlyphs) / sizeof(kGlyphs[0]); 702 | while (l < r) { 703 | unsigned m = (l & r) + ((l ^ r) >> 1); 704 | if (c < kGlyphs[m][0]) { 705 | r = m; 706 | } else if (c > kGlyphs[m][1]) { 707 | l = m + 1; 708 | } else { 709 | return 0; 710 | } 711 | } 712 | return 1; 713 | } else { 714 | static const unsigned kAstralGlyphs[][2] = { 715 | {0x10107, 0x10133}, /* 45x Aegean */ 716 | {0x10140, 0x10178}, /* 57x Ancient Greek Numbers */ 717 | {0x1018a, 0x1018b}, /* 2x Ancient Greek Numbers */ 718 | {0x10280, 0x1029c}, /* 29x Lycian */ 719 | {0x102a0, 0x102d0}, /* 49x Carian */ 720 | {0x102e1, 0x102fb}, /* 27x Coptic Epact Numbers */ 721 | {0x10300, 0x10323}, /* 36x Old Italic */ 722 | {0x1032d, 0x1034a}, /* 30x Old Italic, Gothic */ 723 | {0x10350, 0x10375}, /* 38x Old Permic */ 724 | {0x10380, 0x1039d}, /* 30x Ugaritic */ 725 | {0x103a0, 0x103c3}, /* 36x Old Persian */ 726 | {0x103c8, 0x103cf}, /* 8x Old Persian */ 727 | {0x103d1, 0x103d5}, /* 5x Old Persian */ 728 | {0x10400, 0x1049d}, /* 158x Deseret, Shavian, Osmanya */ 729 | {0x104b0, 0x104d3}, /* 36x Osage */ 730 | {0x104d8, 0x104fb}, /* 36x Osage */ 731 | {0x10500, 0x10527}, /* 40x Elbasan */ 732 | {0x10530, 0x10563}, /* 52x Caucasian Albanian */ 733 | {0x10600, 0x10736}, /* 311x Linear A */ 734 | {0x10800, 0x10805}, /* 6x Cypriot Syllabary */ 735 | {0x1080a, 0x10835}, /* 44x Cypriot Syllabary */ 736 | {0x10837, 0x10838}, /* 2x Cypriot Syllabary */ 737 | {0x1083f, 0x1089e}, /* 86x Cypriot,ImperialAramaic,Palmyrene,Nabataean */ 738 | {0x108e0, 0x108f2}, /* 19x Hatran */ 739 | {0x108f4, 0x108f5}, /* 2x Hatran */ 740 | {0x108fb, 0x1091b}, /* 33x Hatran */ 741 | {0x10920, 0x10939}, /* 26x Lydian */ 742 | {0x10980, 0x109b7}, /* 56x Meroitic Hieroglyphs */ 743 | {0x109bc, 0x109cf}, /* 20x Meroitic Cursive */ 744 | {0x109d2, 0x10a00}, /* 47x Meroitic Cursive */ 745 | {0x10a10, 0x10a13}, /* 4x Kharoshthi */ 746 | {0x10a15, 0x10a17}, /* 3x Kharoshthi */ 747 | {0x10a19, 0x10a35}, /* 29x Kharoshthi */ 748 | {0x10a40, 0x10a48}, /* 9x Kharoshthi */ 749 | {0x10a60, 0x10a7e}, /* 31x Old South Arabian */ 750 | {0x10a80, 0x10a9f}, /* 32x Old North Arabian */ 751 | {0x10ac0, 0x10ac7}, /* 8x Manichaean */ 752 | {0x10ac9, 0x10ae4}, /* 28x Manichaean */ 753 | {0x10aeb, 0x10aef}, /* 5x Manichaean */ 754 | {0x10b00, 0x10b35}, /* 54x Avestan */ 755 | {0x10b40, 0x10b55}, /* 22x Inscriptional Parthian */ 756 | {0x10b58, 0x10b72}, /* 27x Inscriptional Parthian and Pahlavi */ 757 | {0x10b78, 0x10b91}, /* 26x Inscriptional Pahlavi, Psalter Pahlavi */ 758 | {0x10c00, 0x10c48}, /* 73x Old Turkic */ 759 | {0x10c80, 0x10cb2}, /* 51x Old Hungarian */ 760 | {0x10cc0, 0x10cf2}, /* 51x Old Hungarian */ 761 | {0x10cfa, 0x10d23}, /* 42x Old Hungarian, Hanifi Rohingya */ 762 | {0x10d30, 0x10d39}, /* 10x Hanifi Rohingya */ 763 | {0x10e60, 0x10e7e}, /* 31x Rumi Numeral Symbols */ 764 | {0x10f00, 0x10f27}, /* 40x Old Sogdian */ 765 | {0x10f30, 0x10f45}, /* 22x Sogdian */ 766 | {0x10f51, 0x10f54}, /* 4x Sogdian */ 767 | {0x10fe0, 0x10ff6}, /* 23x Elymaic */ 768 | {0x11003, 0x11037}, /* 53x Brahmi */ 769 | {0x11052, 0x1106f}, /* 30x Brahmi */ 770 | {0x11083, 0x110af}, /* 45x Kaithi */ 771 | {0x110d0, 0x110e8}, /* 25x Sora Sompeng */ 772 | {0x110f0, 0x110f9}, /* 10x Sora Sompeng */ 773 | {0x11103, 0x11126}, /* 36x Chakma */ 774 | {0x11136, 0x1113f}, /* 10x Chakma */ 775 | {0x11144, 0x11144}, /* 1x Chakma */ 776 | {0x11150, 0x11172}, /* 35x Mahajani */ 777 | {0x11176, 0x11176}, /* 1x Mahajani */ 778 | {0x11183, 0x111b2}, /* 48x Sharada */ 779 | {0x111c1, 0x111c4}, /* 4x Sharada */ 780 | {0x111d0, 0x111da}, /* 11x Sharada */ 781 | {0x111dc, 0x111dc}, /* 1x Sharada */ 782 | {0x111e1, 0x111f4}, /* 20x Sinhala Archaic Numbers */ 783 | {0x11200, 0x11211}, /* 18x Khojki */ 784 | {0x11213, 0x1122b}, /* 25x Khojki */ 785 | {0x11280, 0x11286}, /* 7x Multani */ 786 | {0x11288, 0x11288}, /* 1x Multani */ 787 | {0x1128a, 0x1128d}, /* 4x Multani */ 788 | {0x1128f, 0x1129d}, /* 15x Multani */ 789 | {0x1129f, 0x112a8}, /* 10x Multani */ 790 | {0x112b0, 0x112de}, /* 47x Khudawadi */ 791 | {0x112f0, 0x112f9}, /* 10x Khudawadi */ 792 | {0x11305, 0x1130c}, /* 8x Grantha */ 793 | {0x1130f, 0x11310}, /* 2x Grantha */ 794 | {0x11313, 0x11328}, /* 22x Grantha */ 795 | {0x1132a, 0x11330}, /* 7x Grantha */ 796 | {0x11332, 0x11333}, /* 2x Grantha */ 797 | {0x11335, 0x11339}, /* 5x Grantha */ 798 | {0x1133d, 0x1133d}, /* 1x Grantha */ 799 | {0x11350, 0x11350}, /* 1x Grantha */ 800 | {0x1135d, 0x11361}, /* 5x Grantha */ 801 | {0x11400, 0x11434}, /* 53x Newa */ 802 | {0x11447, 0x1144a}, /* 4x Newa */ 803 | {0x11450, 0x11459}, /* 10x Newa */ 804 | {0x1145f, 0x1145f}, /* 1x Newa */ 805 | {0x11480, 0x114af}, /* 48x Tirhuta */ 806 | {0x114c4, 0x114c5}, /* 2x Tirhuta */ 807 | {0x114c7, 0x114c7}, /* 1x Tirhuta */ 808 | {0x114d0, 0x114d9}, /* 10x Tirhuta */ 809 | {0x11580, 0x115ae}, /* 47x Siddham */ 810 | {0x115d8, 0x115db}, /* 4x Siddham */ 811 | {0x11600, 0x1162f}, /* 48x Modi */ 812 | {0x11644, 0x11644}, /* 1x Modi */ 813 | {0x11650, 0x11659}, /* 10x Modi */ 814 | {0x11680, 0x116aa}, /* 43x Takri */ 815 | {0x116b8, 0x116b8}, /* 1x Takri */ 816 | {0x116c0, 0x116c9}, /* 10x Takri */ 817 | {0x11700, 0x1171a}, /* 27x Ahom */ 818 | {0x11730, 0x1173b}, /* 12x Ahom */ 819 | {0x11800, 0x1182b}, /* 44x Dogra */ 820 | {0x118a0, 0x118f2}, /* 83x Warang Citi */ 821 | {0x118ff, 0x118ff}, /* 1x Warang Citi */ 822 | {0x119a0, 0x119a7}, /* 8x Nandinagari */ 823 | {0x119aa, 0x119d0}, /* 39x Nandinagari */ 824 | {0x119e1, 0x119e1}, /* 1x Nandinagari */ 825 | {0x119e3, 0x119e3}, /* 1x Nandinagari */ 826 | {0x11a00, 0x11a00}, /* 1x Zanabazar Square */ 827 | {0x11a0b, 0x11a32}, /* 40x Zanabazar Square */ 828 | {0x11a3a, 0x11a3a}, /* 1x Zanabazar Square */ 829 | {0x11a50, 0x11a50}, /* 1x Soyombo */ 830 | {0x11a5c, 0x11a89}, /* 46x Soyombo */ 831 | {0x11a9d, 0x11a9d}, /* 1x Soyombo */ 832 | {0x11ac0, 0x11af8}, /* 57x Pau Cin Hau */ 833 | {0x11c00, 0x11c08}, /* 9x Bhaiksuki */ 834 | {0x11c0a, 0x11c2e}, /* 37x Bhaiksuki */ 835 | {0x11c40, 0x11c40}, /* 1x Bhaiksuki */ 836 | {0x11c50, 0x11c6c}, /* 29x Bhaiksuki */ 837 | {0x11c72, 0x11c8f}, /* 30x Marchen */ 838 | {0x11d00, 0x11d06}, /* 7x Masaram Gondi */ 839 | {0x11d08, 0x11d09}, /* 2x Masaram Gondi */ 840 | {0x11d0b, 0x11d30}, /* 38x Masaram Gondi */ 841 | {0x11d46, 0x11d46}, /* 1x Masaram Gondi */ 842 | {0x11d50, 0x11d59}, /* 10x Masaram Gondi */ 843 | {0x11d60, 0x11d65}, /* 6x Gunjala Gondi */ 844 | {0x11d67, 0x11d68}, /* 2x Gunjala Gondi */ 845 | {0x11d6a, 0x11d89}, /* 32x Gunjala Gondi */ 846 | {0x11d98, 0x11d98}, /* 1x Gunjala Gondi */ 847 | {0x11da0, 0x11da9}, /* 10x Gunjala Gondi */ 848 | {0x11ee0, 0x11ef2}, /* 19x Makasar */ 849 | {0x11fc0, 0x11fd4}, /* 21x Tamil Supplement */ 850 | {0x12000, 0x12399}, /* 922x Cuneiform */ 851 | {0x12400, 0x1246e}, /* 111x Cuneiform Numbers & Punctuation */ 852 | {0x12480, 0x12543}, /* 196x Early Dynastic Cuneiform */ 853 | {0x13000, 0x1342e}, /* 1071x Egyptian Hieroglyphs */ 854 | {0x14400, 0x14646}, /* 583x Anatolian Hieroglyphs */ 855 | {0x16800, 0x16a38}, /* 569x Bamum Supplement */ 856 | {0x16a40, 0x16a5e}, /* 31x Mro */ 857 | {0x16a60, 0x16a69}, /* 10x Mro */ 858 | {0x16ad0, 0x16aed}, /* 30x Bassa Vah */ 859 | {0x16b00, 0x16b2f}, /* 48x Pahawh Hmong */ 860 | {0x16b40, 0x16b43}, /* 4x Pahawh Hmong */ 861 | {0x16b50, 0x16b59}, /* 10x Pahawh Hmong */ 862 | {0x16b5b, 0x16b61}, /* 7x Pahawh Hmong */ 863 | {0x16b63, 0x16b77}, /* 21x Pahawh Hmong */ 864 | {0x16b7d, 0x16b8f}, /* 19x Pahawh Hmong */ 865 | {0x16e40, 0x16e96}, /* 87x Medefaidrin */ 866 | {0x16f00, 0x16f4a}, /* 75x Miao */ 867 | {0x16f50, 0x16f50}, /* 1x Miao */ 868 | {0x16f93, 0x16f9f}, /* 13x Miao */ 869 | {0x16fe0, 0x16fe1}, /* 2x Ideographic Symbols & Punctuation */ 870 | {0x16fe3, 0x16fe3}, /* 1x Ideographic Symbols & Punctuation */ 871 | {0x17000, 0x187f7}, /* 6136x Tangut */ 872 | {0x18800, 0x18af2}, /* 755x Tangut Components */ 873 | {0x1b000, 0x1b11e}, /* 287x Kana Supplement */ 874 | {0x1b150, 0x1b152}, /* 3x Small Kana Extension */ 875 | {0x1b164, 0x1b167}, /* 4x Small Kana Extension */ 876 | {0x1b170, 0x1b2fb}, /* 396x Nushu */ 877 | {0x1bc00, 0x1bc6a}, /* 107x Duployan */ 878 | {0x1bc70, 0x1bc7c}, /* 13x Duployan */ 879 | {0x1bc80, 0x1bc88}, /* 9x Duployan */ 880 | {0x1bc90, 0x1bc99}, /* 10x Duployan */ 881 | {0x1d2e0, 0x1d2f3}, /* 20x Mayan Numerals */ 882 | {0x1d360, 0x1d378}, /* 25x Counting Rod Numerals */ 883 | {0x1d400, 0x1d454}, /* 85x 𝐀..𝑔 Math */ 884 | {0x1d456, 0x1d49c}, /* 71x 𝑖..𝒜 Math */ 885 | {0x1d49e, 0x1d49f}, /* 2x 𝒞..𝒟 Math */ 886 | {0x1d4a2, 0x1d4a2}, /* 1x 𝒢..𝒢 Math */ 887 | {0x1d4a5, 0x1d4a6}, /* 2x 𝒥..𝒦 Math */ 888 | {0x1d4a9, 0x1d4ac}, /* 4x 𝒩..𝒬 Math */ 889 | {0x1d4ae, 0x1d4b9}, /* 12x 𝒮..𝒹 Math */ 890 | {0x1d4bb, 0x1d4bb}, /* 1x 𝒻..𝒻 Math */ 891 | {0x1d4bd, 0x1d4c3}, /* 7x 𝒽..𝓃 Math */ 892 | {0x1d4c5, 0x1d505}, /* 65x 𝓅..𝔅 Math */ 893 | {0x1d507, 0x1d50a}, /* 4x 𝔇..𝔊 Math */ 894 | {0x1d50d, 0x1d514}, /* 8x 𝔍..𝔔 Math */ 895 | {0x1d516, 0x1d51c}, /* 7x 𝔖..𝔜 Math */ 896 | {0x1d51e, 0x1d539}, /* 28x 𝔞..𝔹 Math */ 897 | {0x1d53b, 0x1d53e}, /* 4x 𝔻..𝔾 Math */ 898 | {0x1d540, 0x1d544}, /* 5x 𝕀..𝕄 Math */ 899 | {0x1d546, 0x1d546}, /* 1x 𝕆..𝕆 Math */ 900 | {0x1d54a, 0x1d550}, /* 7x 𝕊..𝕐 Math */ 901 | {0x1d552, 0x1d6a5}, /* 340x 𝕒..𝚥 Math */ 902 | {0x1d6a8, 0x1d6c0}, /* 25x 𝚨..𝛀 Math */ 903 | {0x1d6c2, 0x1d6da}, /* 25x 𝛂..𝛚 Math */ 904 | {0x1d6dc, 0x1d6fa}, /* 31x 𝛜..𝛺 Math */ 905 | {0x1d6fc, 0x1d714}, /* 25x 𝛼..𝜔 Math */ 906 | {0x1d716, 0x1d734}, /* 31x 𝜖..𝜴 Math */ 907 | {0x1d736, 0x1d74e}, /* 25x 𝜶..𝝎 Math */ 908 | {0x1d750, 0x1d76e}, /* 31x 𝝐..𝝮 Math */ 909 | {0x1d770, 0x1d788}, /* 25x 𝝰..𝞈 Math */ 910 | {0x1d78a, 0x1d7a8}, /* 31x 𝞊..𝞨 Math */ 911 | {0x1d7aa, 0x1d7c2}, /* 25x 𝞪..𝟂 Math */ 912 | {0x1d7c4, 0x1d7cb}, /* 8x 𝟄..𝟋 Math */ 913 | {0x1d7ce, 0x1d9ff}, /* 562x Math, Sutton SignWriting */ 914 | {0x1f100, 0x1f10c}, /* 13x Enclosed Alphanumeric Supplement */ 915 | {0x20000, 0x2a6d6}, /* 42711x CJK Unified Ideographs Extension B */ 916 | {0x2a700, 0x2b734}, /* 4149x CJK Unified Ideographs Extension C */ 917 | {0x2b740, 0x2b81d}, /* 222x CJK Unified Ideographs Extension D */ 918 | {0x2b820, 0x2cea1}, /* 5762x CJK Unified Ideographs Extension E */ 919 | {0x2ceb0, 0x2ebe0}, /* 7473x CJK Unified Ideographs Extension F */ 920 | {0x2f800, 0x2fa1d}, /* 542x CJK Compatibility Ideographs Supplement */ 921 | }; 922 | l = 0; 923 | r = n = sizeof(kAstralGlyphs) / sizeof(kAstralGlyphs[0]); 924 | while (l < r) { 925 | unsigned m = (l & r) + ((l ^ r) >> 1); 926 | if (c < kAstralGlyphs[m][0]) { 927 | r = m; 928 | } else if (c > kAstralGlyphs[m][1]) { 929 | l = m + 1; 930 | } else { 931 | return 0; 932 | } 933 | } 934 | return 1; 935 | } 936 | } 937 | 938 | unsigned bestlineLowercase(unsigned c) { 939 | int m, l, r, n; 940 | if (c < 0200) { 941 | if ('A' <= c && c <= 'Z') { 942 | return c + 32; 943 | } else { 944 | return c; 945 | } 946 | } else if (c <= 0xffff) { 947 | if ((0x0100 <= c && c <= 0x0176) || /* 60x Ā..ā → ā..ŵ Watin-A */ 948 | (0x01de <= c && c <= 0x01ee) || /* 9x Ǟ..Ǯ → ǟ..ǯ Watin-B */ 949 | (0x01f8 <= c && c <= 0x021e) || /* 20x Ǹ..Ȟ → ǹ..ȟ Watin-B */ 950 | (0x0222 <= c && c <= 0x0232) || /* 9x Ȣ..Ȳ → ȣ..ȳ Watin-B */ 951 | (0x1e00 <= c && c <= 0x1eff)) { /*256x Ḁ..Ỿ → ḁ..ỿ Watin-C */ 952 | if (c == 0x0130) 953 | return c - 199; 954 | if (c == 0x1e9e) 955 | return c; 956 | return c + (~c & 1); 957 | } else if (0x01cf <= c && c <= 0x01db) { 958 | return c + (c & 1); /* 7x Ǐ..Ǜ → ǐ..ǜ Watin-B */ 959 | } else if (0x13a0 <= c && c <= 0x13ef) { 960 | return c + 38864; /* 80x Ꭰ ..Ꮿ → ꭰ ..ꮿ Cherokee */ 961 | } else { 962 | static const struct { 963 | unsigned short a; 964 | unsigned short b; 965 | short d; 966 | } kLower[] = { 967 | {0x00c0, 0x00d6, +32}, /* 23x À ..Ö → à ..ö Watin */ 968 | {0x00d8, 0x00de, +32}, /* 7x Ø ..Þ → ø ..þ Watin */ 969 | {0x0178, 0x0178, -121}, /* 1x Ÿ ..Ÿ → ÿ ..ÿ Watin-A */ 970 | {0x0179, 0x0179, +1}, /* 1x Ź ..Ź → ź ..ź Watin-A */ 971 | {0x017b, 0x017b, +1}, /* 1x Ż ..Ż → ż ..ż Watin-A */ 972 | {0x017d, 0x017d, +1}, /* 1x Ž ..Ž → ž ..ž Watin-A */ 973 | {0x0181, 0x0181, +210}, /* 1x Ɓ ..Ɓ → ɓ ..ɓ Watin-B */ 974 | {0x0182, 0x0182, +1}, /* 1x Ƃ ..Ƃ → ƃ ..ƃ Watin-B */ 975 | {0x0184, 0x0184, +1}, /* 1x Ƅ ..Ƅ → ƅ ..ƅ Watin-B */ 976 | {0x0186, 0x0186, +206}, /* 1x Ɔ ..Ɔ → ɔ ..ɔ Watin-B */ 977 | {0x0187, 0x0187, +1}, /* 1x Ƈ ..Ƈ → ƈ ..ƈ Watin-B */ 978 | {0x0189, 0x018a, +205}, /* 2x Ɖ ..Ɗ → ɖ ..ɗ Watin-B */ 979 | {0x018b, 0x018b, +1}, /* 1x Ƌ ..Ƌ → ƌ ..ƌ Watin-B */ 980 | {0x018e, 0x018e, +79}, /* 1x Ǝ ..Ǝ → ǝ ..ǝ Watin-B */ 981 | {0x018f, 0x018f, +202}, /* 1x Ə ..Ə → ə ..ə Watin-B */ 982 | {0x0190, 0x0190, +203}, /* 1x Ɛ ..Ɛ → ɛ ..ɛ Watin-B */ 983 | {0x0191, 0x0191, +1}, /* 1x Ƒ ..Ƒ → ƒ ..ƒ Watin-B */ 984 | {0x0193, 0x0193, +205}, /* 1x Ɠ ..Ɠ → ɠ ..ɠ Watin-B */ 985 | {0x0194, 0x0194, +207}, /* 1x Ɣ ..Ɣ → ɣ ..ɣ Watin-B */ 986 | {0x0196, 0x0196, +211}, /* 1x Ɩ ..Ɩ → ɩ ..ɩ Watin-B */ 987 | {0x0197, 0x0197, +209}, /* 1x Ɨ ..Ɨ → ɨ ..ɨ Watin-B */ 988 | {0x0198, 0x0198, +1}, /* 1x Ƙ ..Ƙ → ƙ ..ƙ Watin-B */ 989 | {0x019c, 0x019c, +211}, /* 1x Ɯ ..Ɯ → ɯ ..ɯ Watin-B */ 990 | {0x019d, 0x019d, +213}, /* 1x Ɲ ..Ɲ → ɲ ..ɲ Watin-B */ 991 | {0x019f, 0x019f, +214}, /* 1x Ɵ ..Ɵ → ɵ ..ɵ Watin-B */ 992 | {0x01a0, 0x01a0, +1}, /* 1x Ơ ..Ơ → ơ ..ơ Watin-B */ 993 | {0x01a2, 0x01a2, +1}, /* 1x Ƣ ..Ƣ → ƣ ..ƣ Watin-B */ 994 | {0x01a4, 0x01a4, +1}, /* 1x Ƥ ..Ƥ → ƥ ..ƥ Watin-B */ 995 | {0x01a6, 0x01a6, +218}, /* 1x Ʀ ..Ʀ → ʀ ..ʀ Watin-B */ 996 | {0x01a7, 0x01a7, +1}, /* 1x Ƨ ..Ƨ → ƨ ..ƨ Watin-B */ 997 | {0x01a9, 0x01a9, +218}, /* 1x Ʃ ..Ʃ → ʃ ..ʃ Watin-B */ 998 | {0x01ac, 0x01ac, +1}, /* 1x Ƭ ..Ƭ → ƭ ..ƭ Watin-B */ 999 | {0x01ae, 0x01ae, +218}, /* 1x Ʈ ..Ʈ → ʈ ..ʈ Watin-B */ 1000 | {0x01af, 0x01af, +1}, /* 1x Ư ..Ư → ư ..ư Watin-B */ 1001 | {0x01b1, 0x01b2, +217}, /* 2x Ʊ ..Ʋ → ʊ ..ʋ Watin-B */ 1002 | {0x01b3, 0x01b3, +1}, /* 1x Ƴ ..Ƴ → ƴ ..ƴ Watin-B */ 1003 | {0x01b5, 0x01b5, +1}, /* 1x Ƶ ..Ƶ → ƶ ..ƶ Watin-B */ 1004 | {0x01b7, 0x01b7, +219}, /* 1x Ʒ ..Ʒ → ʒ ..ʒ Watin-B */ 1005 | {0x01b8, 0x01b8, +1}, /* 1x Ƹ ..Ƹ → ƹ ..ƹ Watin-B */ 1006 | {0x01bc, 0x01bc, +1}, /* 1x Ƽ ..Ƽ → ƽ ..ƽ Watin-B */ 1007 | {0x01c4, 0x01c4, +2}, /* 1x DŽ ..DŽ → dž ..dž Watin-B */ 1008 | {0x01c5, 0x01c5, +1}, /* 1x Dž ..Dž → dž ..dž Watin-B */ 1009 | {0x01c7, 0x01c7, +2}, /* 1x LJ ..LJ → lj ..lj Watin-B */ 1010 | {0x01c8, 0x01c8, +1}, /* 1x Lj ..Lj → lj ..lj Watin-B */ 1011 | {0x01ca, 0x01ca, +2}, /* 1x NJ ..NJ → nj ..nj Watin-B */ 1012 | {0x01cb, 0x01cb, +1}, /* 1x Nj ..Nj → nj ..nj Watin-B */ 1013 | {0x01cd, 0x01cd, +1}, /* 1x Ǎ ..Ǎ → ǎ ..ǎ Watin-B */ 1014 | {0x01f1, 0x01f1, +2}, /* 1x DZ ..DZ → dz ..dz Watin-B */ 1015 | {0x01f2, 0x01f2, +1}, /* 1x Dz ..Dz → dz ..dz Watin-B */ 1016 | {0x01f4, 0x01f4, +1}, /* 1x Ǵ ..Ǵ → ǵ ..ǵ Watin-B */ 1017 | {0x01f6, 0x01f6, -97}, /* 1x Ƕ ..Ƕ → ƕ ..ƕ Watin-B */ 1018 | {0x01f7, 0x01f7, -56}, /* 1x Ƿ ..Ƿ → ƿ ..ƿ Watin-B */ 1019 | {0x0220, 0x0220, -130}, /* 1x Ƞ ..Ƞ → ƞ ..ƞ Watin-B */ 1020 | {0x023b, 0x023b, +1}, /* 1x Ȼ ..Ȼ → ȼ ..ȼ Watin-B */ 1021 | {0x023d, 0x023d, -163}, /* 1x Ƚ ..Ƚ → ƚ ..ƚ Watin-B */ 1022 | {0x0241, 0x0241, +1}, /* 1x Ɂ ..Ɂ → ɂ ..ɂ Watin-B */ 1023 | {0x0243, 0x0243, -195}, /* 1x Ƀ ..Ƀ → ƀ ..ƀ Watin-B */ 1024 | {0x0244, 0x0244, +69}, /* 1x Ʉ ..Ʉ → ʉ ..ʉ Watin-B */ 1025 | {0x0245, 0x0245, +71}, /* 1x Ʌ ..Ʌ → ʌ ..ʌ Watin-B */ 1026 | {0x0246, 0x0246, +1}, /* 1x Ɇ ..Ɇ → ɇ ..ɇ Watin-B */ 1027 | {0x0248, 0x0248, +1}, /* 1x Ɉ ..Ɉ → ɉ ..ɉ Watin-B */ 1028 | {0x024a, 0x024a, +1}, /* 1x Ɋ ..Ɋ → ɋ ..ɋ Watin-B */ 1029 | {0x024c, 0x024c, +1}, /* 1x Ɍ ..Ɍ → ɍ ..ɍ Watin-B */ 1030 | {0x024e, 0x024e, +1}, /* 1x Ɏ ..Ɏ → ɏ ..ɏ Watin-B */ 1031 | {0x0386, 0x0386, +38}, /* 1x Ά ..Ά → ά ..ά Greek */ 1032 | {0x0388, 0x038a, +37}, /* 3x Έ ..Ί → έ ..ί Greek */ 1033 | {0x038c, 0x038c, +64}, /* 1x Ό ..Ό → ό ..ό Greek */ 1034 | {0x038e, 0x038f, +63}, /* 2x Ύ ..Ώ → ύ ..ώ Greek */ 1035 | {0x0391, 0x03a1, +32}, /* 17x Α ..Ρ → α ..ρ Greek */ 1036 | {0x03a3, 0x03ab, +32}, /* 9x Σ ..Ϋ → σ ..ϋ Greek */ 1037 | {0x03dc, 0x03dc, +1}, /* 1x Ϝ ..Ϝ → ϝ ..ϝ Greek */ 1038 | {0x03f4, 0x03f4, -60}, /* 1x ϴ ..ϴ → θ ..θ Greek */ 1039 | {0x0400, 0x040f, +80}, /* 16x Ѐ ..Џ → ѐ ..џ Cyrillic */ 1040 | {0x0410, 0x042f, +32}, /* 32x А ..Я → а ..я Cyrillic */ 1041 | {0x0460, 0x0460, +1}, /* 1x Ѡ ..Ѡ → ѡ ..ѡ Cyrillic */ 1042 | {0x0462, 0x0462, +1}, /* 1x Ѣ ..Ѣ → ѣ ..ѣ Cyrillic */ 1043 | {0x0464, 0x0464, +1}, /* 1x Ѥ ..Ѥ → ѥ ..ѥ Cyrillic */ 1044 | {0x0472, 0x0472, +1}, /* 1x Ѳ ..Ѳ → ѳ ..ѳ Cyrillic */ 1045 | {0x0490, 0x0490, +1}, /* 1x Ґ ..Ґ → ґ ..ґ Cyrillic */ 1046 | {0x0498, 0x0498, +1}, /* 1x Ҙ ..Ҙ → ҙ ..ҙ Cyrillic */ 1047 | {0x049a, 0x049a, +1}, /* 1x Қ ..Қ → қ ..қ Cyrillic */ 1048 | {0x0531, 0x0556, +48}, /* 38x Ա ..Ֆ → ա ..ֆ Armenian */ 1049 | {0x10a0, 0x10c5, +7264}, /* 38x Ⴀ ..Ⴥ → ⴀ ..ⴥ Georgian */ 1050 | {0x10c7, 0x10c7, +7264}, /* 1x Ⴧ ..Ⴧ → ⴧ ..ⴧ Georgian */ 1051 | {0x10cd, 0x10cd, +7264}, /* 1x Ⴭ ..Ⴭ → ⴭ ..ⴭ Georgian */ 1052 | {0x13f0, 0x13f5, +8}, /* 6x Ᏸ ..Ᏽ → ᏸ ..ᏽ Cherokee */ 1053 | {0x1c90, 0x1cba, -3008}, /* 43x Ა ..Ჺ → ა ..ჺ Georgian2 */ 1054 | {0x1cbd, 0x1cbf, -3008}, /* 3x Ჽ ..Ჿ → ჽ ..ჿ Georgian2 */ 1055 | {0x1f08, 0x1f0f, -8}, /* 8x Ἀ ..Ἇ → ἀ ..ἇ Greek2 */ 1056 | {0x1f18, 0x1f1d, -8}, /* 6x Ἐ ..Ἕ → ἐ ..ἕ Greek2 */ 1057 | {0x1f28, 0x1f2f, -8}, /* 8x Ἠ ..Ἧ → ἠ ..ἧ Greek2 */ 1058 | {0x1f38, 0x1f3f, -8}, /* 8x Ἰ ..Ἷ → ἰ ..ἷ Greek2 */ 1059 | {0x1f48, 0x1f4d, -8}, /* 6x Ὀ ..Ὅ → ὀ ..ὅ Greek2 */ 1060 | {0x1f59, 0x1f59, -8}, /* 1x Ὑ ..Ὑ → ὑ ..ὑ Greek2 */ 1061 | {0x1f5b, 0x1f5b, -8}, /* 1x Ὓ ..Ὓ → ὓ ..ὓ Greek2 */ 1062 | {0x1f5d, 0x1f5d, -8}, /* 1x Ὕ ..Ὕ → ὕ ..ὕ Greek2 */ 1063 | {0x1f5f, 0x1f5f, -8}, /* 1x Ὗ ..Ὗ → ὗ ..ὗ Greek2 */ 1064 | {0x1f68, 0x1f6f, -8}, /* 8x Ὠ ..Ὧ → ὠ ..ὧ Greek2 */ 1065 | {0x1f88, 0x1f8f, -8}, /* 8x ᾈ ..ᾏ → ᾀ ..ᾇ Greek2 */ 1066 | {0x1f98, 0x1f9f, -8}, /* 8x ᾘ ..ᾟ → ᾐ ..ᾗ Greek2 */ 1067 | {0x1fa8, 0x1faf, -8}, /* 8x ᾨ ..ᾯ → ᾠ ..ᾧ Greek2 */ 1068 | {0x1fb8, 0x1fb9, -8}, /* 2x Ᾰ ..Ᾱ → ᾰ ..ᾱ Greek2 */ 1069 | {0x1fba, 0x1fbb, -74}, /* 2x Ὰ ..Ά → ὰ ..ά Greek2 */ 1070 | {0x1fbc, 0x1fbc, -9}, /* 1x ᾼ ..ᾼ → ᾳ ..ᾳ Greek2 */ 1071 | {0x1fc8, 0x1fcb, -86}, /* 4x Ὲ ..Ή → ὲ ..ή Greek2 */ 1072 | {0x1fcc, 0x1fcc, -9}, /* 1x ῌ ..ῌ → ῃ ..ῃ Greek2 */ 1073 | {0x1fd8, 0x1fd9, -8}, /* 2x Ῐ ..Ῑ → ῐ ..ῑ Greek2 */ 1074 | {0x1fda, 0x1fdb, -100}, /* 2x Ὶ ..Ί → ὶ ..ί Greek2 */ 1075 | {0x1fe8, 0x1fe9, -8}, /* 2x Ῠ ..Ῡ → ῠ ..ῡ Greek2 */ 1076 | {0x1fea, 0x1feb, -112}, /* 2x Ὺ ..Ύ → ὺ ..ύ Greek2 */ 1077 | {0x1fec, 0x1fec, -7}, /* 1x Ῥ ..Ῥ → ῥ ..ῥ Greek2 */ 1078 | {0x1ff8, 0x1ff9, -128}, /* 2x Ὸ ..Ό → ὸ ..ό Greek2 */ 1079 | {0x1ffa, 0x1ffb, -126}, /* 2x Ὼ ..Ώ → ὼ ..ώ Greek2 */ 1080 | {0x1ffc, 0x1ffc, -9}, /* 1x ῼ ..ῼ → ῳ ..ῳ Greek2 */ 1081 | {0x2126, 0x2126, -7517}, /* 1x Ω ..Ω → ω ..ω Letterlike */ 1082 | {0x212a, 0x212a, -8383}, /* 1x K ..K → k ..k Letterlike */ 1083 | {0x212b, 0x212b, -8262}, /* 1x Å ..Å → å ..å Letterlike */ 1084 | {0x2132, 0x2132, +28}, /* 1x Ⅎ ..Ⅎ → ⅎ ..ⅎ Letterlike */ 1085 | {0x2160, 0x216f, +16}, /* 16x Ⅰ ..Ⅿ → ⅰ ..ⅿ Numbery */ 1086 | {0x2183, 0x2183, +1}, /* 1x Ↄ ..Ↄ → ↄ ..ↄ Numbery */ 1087 | {0x24b6, 0x24cf, +26}, /* 26x Ⓐ ..Ⓩ → ⓐ ..ⓩ Enclosed */ 1088 | {0x2c00, 0x2c2e, +48}, /* 47x Ⰰ ..Ⱞ → ⰰ ..ⱞ Glagolitic */ 1089 | {0xff21, 0xff3a, +32}, /* 26x A..Z → a..z Dubs */ 1090 | }; 1091 | l = 0; 1092 | r = n = sizeof(kLower) / sizeof(kLower[0]); 1093 | while (l < r) { 1094 | m = (l + r) >> 1; 1095 | if (kLower[m].b < c) { 1096 | l = m + 1; 1097 | } else { 1098 | r = m; 1099 | } 1100 | } 1101 | if (l < n && kLower[l].a <= c && c <= kLower[l].b) { 1102 | return c + kLower[l].d; 1103 | } else { 1104 | return c; 1105 | } 1106 | } 1107 | } else { 1108 | static struct { 1109 | unsigned a; 1110 | unsigned b; 1111 | short d; 1112 | } kAstralLower[] = { 1113 | {0x10400, 0x10427, +40}, /* 40x 𐐀 ..𐐧 → 𐐨 ..𐑏 Deseret */ 1114 | {0x104b0, 0x104d3, +40}, /* 36x 𐒰 ..𐓓 → 𐓘 ..𐓻 Osage */ 1115 | {0x1d400, 0x1d419, +26}, /* 26x 𝐀 ..𝐙 → 𝐚 ..𝐳 Math */ 1116 | {0x1d43c, 0x1d44d, +26}, /* 18x 𝐼 ..𝑍 → 𝑖 ..𝑧 Math */ 1117 | {0x1d468, 0x1d481, +26}, /* 26x 𝑨 ..𝒁 → 𝒂 ..𝒛 Math */ 1118 | {0x1d4ae, 0x1d4b5, +26}, /* 8x 𝒮 ..𝒵 → 𝓈 ..𝓏 Math */ 1119 | {0x1d4d0, 0x1d4e9, +26}, /* 26x 𝓐 ..𝓩 → 𝓪 ..𝔃 Math */ 1120 | {0x1d50d, 0x1d514, +26}, /* 8x 𝔍 ..𝔔 → 𝔧 ..𝔮 Math */ 1121 | {0x1d56c, 0x1d585, +26}, /* 26x 𝕬 ..𝖅 → 𝖆 ..𝖟 Math */ 1122 | {0x1d5a0, 0x1d5b9, +26}, /* 26x 𝖠 ..𝖹 → 𝖺 ..𝗓 Math */ 1123 | {0x1d5d4, 0x1d5ed, +26}, /* 26x 𝗔 ..𝗭 → 𝗮 ..𝘇 Math */ 1124 | {0x1d608, 0x1d621, +26}, /* 26x 𝘈 ..𝘡 → 𝘢 ..𝘻 Math */ 1125 | {0x1d63c, 0x1d655, -442}, /* 26x 𝘼 ..𝙕 → 𝒂 ..𝒛 Math */ 1126 | {0x1d670, 0x1d689, +26}, /* 26x 𝙰 ..𝚉 → 𝚊 ..𝚣 Math */ 1127 | {0x1d6a8, 0x1d6b8, +26}, /* 17x 𝚨 ..𝚸 → 𝛂 ..𝛒 Math */ 1128 | {0x1d6e2, 0x1d6f2, +26}, /* 17x 𝛢 ..𝛲 → 𝛼 ..𝜌 Math */ 1129 | {0x1d71c, 0x1d72c, +26}, /* 17x 𝜜 ..𝜬 → 𝜶 ..𝝆 Math */ 1130 | {0x1d756, 0x1d766, +26}, /* 17x 𝝖 ..𝝦 → 𝝰 ..𝞀 Math */ 1131 | {0x1d790, 0x1d7a0, -90}, /* 17x 𝞐 ..𝞠 → 𝜶 ..𝝆 Math */ 1132 | }; 1133 | l = 0; 1134 | r = n = sizeof(kAstralLower) / sizeof(kAstralLower[0]); 1135 | while (l < r) { 1136 | m = (l + r) >> 1; 1137 | if (kAstralLower[m].b < c) { 1138 | l = m + 1; 1139 | } else { 1140 | r = m; 1141 | } 1142 | } 1143 | if (l < n && kAstralLower[l].a <= c && c <= kAstralLower[l].b) { 1144 | return c + kAstralLower[l].d; 1145 | } else { 1146 | return c; 1147 | } 1148 | } 1149 | } 1150 | 1151 | unsigned bestlineUppercase(unsigned c) { 1152 | int m, l, r, n; 1153 | if (c < 0200) { 1154 | if ('a' <= c && c <= 'z') { 1155 | return c - 32; 1156 | } else { 1157 | return c; 1158 | } 1159 | } else if (c <= 0xffff) { 1160 | if ((0x0101 <= c && c <= 0x0177) || /* 60x ā..ŵ → Ā..ā Watin-A */ 1161 | (0x01df <= c && c <= 0x01ef) || /* 9x ǟ..ǯ → Ǟ..Ǯ Watin-B */ 1162 | (0x01f8 <= c && c <= 0x021e) || /* 20x ǹ..ȟ → Ǹ..Ȟ Watin-B */ 1163 | (0x0222 <= c && c <= 0x0232) || /* 9x ȣ..ȳ → Ȣ..Ȳ Watin-B */ 1164 | (0x1e01 <= c && c <= 0x1eff)) { /*256x ḁ..ỿ → Ḁ..Ỿ Watin-C */ 1165 | if (c == 0x0131) 1166 | return c + 232; 1167 | if (c == 0x1e9e) 1168 | return c; 1169 | return c - (c & 1); 1170 | } else if (0x01d0 <= c && c <= 0x01dc) { 1171 | return c - (~c & 1); /* 7x ǐ..ǜ → Ǐ..Ǜ Watin-B */ 1172 | } else if (0xab70 <= c && c <= 0xabbf) { 1173 | return c - 38864; /* 80x ꭰ ..ꮿ → Ꭰ ..Ꮿ Cherokee Supplement */ 1174 | } else { 1175 | static const struct { 1176 | unsigned short a; 1177 | unsigned short b; 1178 | short d; 1179 | } kUpper[] = { 1180 | {0x00b5, 0x00b5, +743}, /* 1x µ ..µ → Μ ..Μ Watin */ 1181 | {0x00e0, 0x00f6, -32}, /* 23x à ..ö → À ..Ö Watin */ 1182 | {0x00f8, 0x00fe, -32}, /* 7x ø ..þ → Ø ..Þ Watin */ 1183 | {0x00ff, 0x00ff, +121}, /* 1x ÿ ..ÿ → Ÿ ..Ÿ Watin */ 1184 | {0x017a, 0x017a, -1}, /* 1x ź ..ź → Ź ..Ź Watin-A */ 1185 | {0x017c, 0x017c, -1}, /* 1x ż ..ż → Ż ..Ż Watin-A */ 1186 | {0x017e, 0x017e, -1}, /* 1x ž ..ž → Ž ..Ž Watin-A */ 1187 | {0x017f, 0x017f, -300}, /* 1x ſ ..ſ → S ..S Watin-A */ 1188 | {0x0180, 0x0180, +195}, /* 1x ƀ ..ƀ → Ƀ ..Ƀ Watin-B */ 1189 | {0x0183, 0x0183, -1}, /* 1x ƃ ..ƃ → Ƃ ..Ƃ Watin-B */ 1190 | {0x0185, 0x0185, -1}, /* 1x ƅ ..ƅ → Ƅ ..Ƅ Watin-B */ 1191 | {0x0188, 0x0188, -1}, /* 1x ƈ ..ƈ → Ƈ ..Ƈ Watin-B */ 1192 | {0x018c, 0x018c, -1}, /* 1x ƌ ..ƌ → Ƌ ..Ƌ Watin-B */ 1193 | {0x0192, 0x0192, -1}, /* 1x ƒ ..ƒ → Ƒ ..Ƒ Watin-B */ 1194 | {0x0195, 0x0195, +97}, /* 1x ƕ ..ƕ → Ƕ ..Ƕ Watin-B */ 1195 | {0x0199, 0x0199, -1}, /* 1x ƙ ..ƙ → Ƙ ..Ƙ Watin-B */ 1196 | {0x019a, 0x019a, +163}, /* 1x ƚ ..ƚ → Ƚ ..Ƚ Watin-B */ 1197 | {0x019e, 0x019e, +130}, /* 1x ƞ ..ƞ → Ƞ ..Ƞ Watin-B */ 1198 | {0x01a1, 0x01a1, -1}, /* 1x ơ ..ơ → Ơ ..Ơ Watin-B */ 1199 | {0x01a3, 0x01a3, -1}, /* 1x ƣ ..ƣ → Ƣ ..Ƣ Watin-B */ 1200 | {0x01a5, 0x01a5, -1}, /* 1x ƥ ..ƥ → Ƥ ..Ƥ Watin-B */ 1201 | {0x01a8, 0x01a8, -1}, /* 1x ƨ ..ƨ → Ƨ ..Ƨ Watin-B */ 1202 | {0x01ad, 0x01ad, -1}, /* 1x ƭ ..ƭ → Ƭ ..Ƭ Watin-B */ 1203 | {0x01b0, 0x01b0, -1}, /* 1x ư ..ư → Ư ..Ư Watin-B */ 1204 | {0x01b4, 0x01b4, -1}, /* 1x ƴ ..ƴ → Ƴ ..Ƴ Watin-B */ 1205 | {0x01b6, 0x01b6, -1}, /* 1x ƶ ..ƶ → Ƶ ..Ƶ Watin-B */ 1206 | {0x01b9, 0x01b9, -1}, /* 1x ƹ ..ƹ → Ƹ ..Ƹ Watin-B */ 1207 | {0x01bd, 0x01bd, -1}, /* 1x ƽ ..ƽ → Ƽ ..Ƽ Watin-B */ 1208 | {0x01bf, 0x01bf, +56}, /* 1x ƿ ..ƿ → Ƿ ..Ƿ Watin-B */ 1209 | {0x01c5, 0x01c5, -1}, /* 1x Dž ..Dž → DŽ ..DŽ Watin-B */ 1210 | {0x01c6, 0x01c6, -2}, /* 1x dž ..dž → DŽ ..DŽ Watin-B */ 1211 | {0x01c8, 0x01c8, -1}, /* 1x Lj ..Lj → LJ ..LJ Watin-B */ 1212 | {0x01c9, 0x01c9, -2}, /* 1x lj ..lj → LJ ..LJ Watin-B */ 1213 | {0x01cb, 0x01cb, -1}, /* 1x Nj ..Nj → NJ ..NJ Watin-B */ 1214 | {0x01cc, 0x01cc, -2}, /* 1x nj ..nj → NJ ..NJ Watin-B */ 1215 | {0x01ce, 0x01ce, -1}, /* 1x ǎ ..ǎ → Ǎ ..Ǎ Watin-B */ 1216 | {0x01dd, 0x01dd, -79}, /* 1x ǝ ..ǝ → Ǝ ..Ǝ Watin-B */ 1217 | {0x01f2, 0x01f2, -1}, /* 1x Dz ..Dz → DZ ..DZ Watin-B */ 1218 | {0x01f3, 0x01f3, -2}, /* 1x dz ..dz → DZ ..DZ Watin-B */ 1219 | {0x01f5, 0x01f5, -1}, /* 1x ǵ ..ǵ → Ǵ ..Ǵ Watin-B */ 1220 | {0x023c, 0x023c, -1}, /* 1x ȼ ..ȼ → Ȼ ..Ȼ Watin-B */ 1221 | {0x023f, 0x0240, +10815}, /* 2x ȿ ..ɀ → Ȿ ..Ɀ Watin-B */ 1222 | {0x0242, 0x0242, -1}, /* 1x ɂ ..ɂ → Ɂ ..Ɂ Watin-B */ 1223 | {0x0247, 0x0247, -1}, /* 1x ɇ ..ɇ → Ɇ ..Ɇ Watin-B */ 1224 | {0x0249, 0x0249, -1}, /* 1x ɉ ..ɉ → Ɉ ..Ɉ Watin-B */ 1225 | {0x024b, 0x024b, -1}, /* 1x ɋ ..ɋ → Ɋ ..Ɋ Watin-B */ 1226 | {0x024d, 0x024d, -1}, /* 1x ɍ ..ɍ → Ɍ ..Ɍ Watin-B */ 1227 | {0x024f, 0x024f, -1}, /* 1x ɏ ..ɏ → Ɏ ..Ɏ Watin-B */ 1228 | {0x037b, 0x037d, +130}, /* 3x ͻ ..ͽ → Ͻ ..Ͽ Greek */ 1229 | {0x03ac, 0x03ac, -38}, /* 1x ά ..ά → Ά ..Ά Greek */ 1230 | {0x03ad, 0x03af, -37}, /* 3x έ ..ί → Έ ..Ί Greek */ 1231 | {0x03b1, 0x03c1, -32}, /* 17x α ..ρ → Α ..Ρ Greek */ 1232 | {0x03c2, 0x03c2, -31}, /* 1x ς ..ς → Σ ..Σ Greek */ 1233 | {0x03c3, 0x03cb, -32}, /* 9x σ ..ϋ → Σ ..Ϋ Greek */ 1234 | {0x03cc, 0x03cc, -64}, /* 1x ό ..ό → Ό ..Ό Greek */ 1235 | {0x03cd, 0x03ce, -63}, /* 2x ύ ..ώ → Ύ ..Ώ Greek */ 1236 | {0x03d0, 0x03d0, -62}, /* 1x ϐ ..ϐ → Β ..Β Greek */ 1237 | {0x03d1, 0x03d1, -57}, /* 1x ϑ ..ϑ → Θ ..Θ Greek */ 1238 | {0x03d5, 0x03d5, -47}, /* 1x ϕ ..ϕ → Φ ..Φ Greek */ 1239 | {0x03d6, 0x03d6, -54}, /* 1x ϖ ..ϖ → Π ..Π Greek */ 1240 | {0x03dd, 0x03dd, -1}, /* 1x ϝ ..ϝ → Ϝ ..Ϝ Greek */ 1241 | {0x03f0, 0x03f0, -86}, /* 1x ϰ ..ϰ → Κ ..Κ Greek */ 1242 | {0x03f1, 0x03f1, -80}, /* 1x ϱ ..ϱ → Ρ ..Ρ Greek */ 1243 | {0x03f5, 0x03f5, -96}, /* 1x ϵ ..ϵ → Ε ..Ε Greek */ 1244 | {0x0430, 0x044f, -32}, /* 32x а ..я → А ..Я Cyrillic */ 1245 | {0x0450, 0x045f, -80}, /* 16x ѐ ..џ → Ѐ ..Џ Cyrillic */ 1246 | {0x0461, 0x0461, -1}, /* 1x ѡ ..ѡ → Ѡ ..Ѡ Cyrillic */ 1247 | {0x0463, 0x0463, -1}, /* 1x ѣ ..ѣ → Ѣ ..Ѣ Cyrillic */ 1248 | {0x0465, 0x0465, -1}, /* 1x ѥ ..ѥ → Ѥ ..Ѥ Cyrillic */ 1249 | {0x0473, 0x0473, -1}, /* 1x ѳ ..ѳ → Ѳ ..Ѳ Cyrillic */ 1250 | {0x0491, 0x0491, -1}, /* 1x ґ ..ґ → Ґ ..Ґ Cyrillic */ 1251 | {0x0499, 0x0499, -1}, /* 1x ҙ ..ҙ → Ҙ ..Ҙ Cyrillic */ 1252 | {0x049b, 0x049b, -1}, /* 1x қ ..қ → Қ ..Қ Cyrillic */ 1253 | {0x0561, 0x0586, -48}, /* 38x ա ..ֆ → Ա ..Ֆ Armenian */ 1254 | {0x10d0, 0x10fa, +3008}, /* 43x ა ..ჺ → Ა ..Ჺ Georgian */ 1255 | {0x10fd, 0x10ff, +3008}, /* 3x ჽ ..ჿ → Ჽ ..Ჿ Georgian */ 1256 | {0x13f8, 0x13fd, -8}, /* 6x ᏸ ..ᏽ → Ᏸ ..Ᏽ Cherokee */ 1257 | {0x214e, 0x214e, -28}, /* 1x ⅎ ..ⅎ → Ⅎ ..Ⅎ Letterlike */ 1258 | {0x2170, 0x217f, -16}, /* 16x ⅰ ..ⅿ → Ⅰ ..Ⅿ Numbery */ 1259 | {0x2184, 0x2184, -1}, /* 1x ↄ ..ↄ → Ↄ ..Ↄ Numbery */ 1260 | {0x24d0, 0x24e9, -26}, /* 26x ⓐ ..ⓩ → Ⓐ ..Ⓩ Enclosed */ 1261 | {0x2c30, 0x2c5e, -48}, /* 47x ⰰ ..ⱞ → Ⰰ ..Ⱞ Glagolitic */ 1262 | {0x2d00, 0x2d25, -7264}, /* 38x ⴀ ..ⴥ → Ⴀ ..Ⴥ Georgian2 */ 1263 | {0x2d27, 0x2d27, -7264}, /* 1x ⴧ ..ⴧ → Ⴧ ..Ⴧ Georgian2 */ 1264 | {0x2d2d, 0x2d2d, -7264}, /* 1x ⴭ ..ⴭ → Ⴭ ..Ⴭ Georgian2 */ 1265 | {0xff41, 0xff5a, -32}, /* 26x a..z → A..Z Dubs */ 1266 | }; 1267 | l = 0; 1268 | r = n = sizeof(kUpper) / sizeof(kUpper[0]); 1269 | while (l < r) { 1270 | m = (l + r) >> 1; 1271 | if (kUpper[m].b < c) { 1272 | l = m + 1; 1273 | } else { 1274 | r = m; 1275 | } 1276 | } 1277 | if (l < n && kUpper[l].a <= c && c <= kUpper[l].b) { 1278 | return c + kUpper[l].d; 1279 | } else { 1280 | return c; 1281 | } 1282 | } 1283 | } else { 1284 | static const struct { 1285 | unsigned a; 1286 | unsigned b; 1287 | short d; 1288 | } kAstralUpper[] = { 1289 | {0x10428, 0x1044f, -40}, /* 40x 𐐨..𐑏 → 𐐀..𐐧 Deseret */ 1290 | {0x104d8, 0x104fb, -40}, /* 36x 𐓘..𐓻 → 𐒰..𐓓 Osage */ 1291 | {0x1d41a, 0x1d433, -26}, /* 26x 𝐚..𝐳 → 𝐀..𝐙 Math */ 1292 | {0x1d456, 0x1d467, -26}, /* 18x 𝑖..𝑧 → 𝐼..𝑍 Math */ 1293 | {0x1d482, 0x1d49b, -26}, /* 26x 𝒂..𝒛 → 𝑨..𝒁 Math */ 1294 | {0x1d4c8, 0x1d4cf, -26}, /* 8x 𝓈..𝓏 → 𝒮..𝒵 Math */ 1295 | {0x1d4ea, 0x1d503, -26}, /* 26x 𝓪..𝔃 → 𝓐..𝓩 Math */ 1296 | {0x1d527, 0x1d52e, -26}, /* 8x 𝔧..𝔮 → 𝔍..𝔔 Math */ 1297 | {0x1d586, 0x1d59f, -26}, /* 26x 𝖆..𝖟 → 𝕬..𝖅 Math */ 1298 | {0x1d5ba, 0x1d5d3, -26}, /* 26x 𝖺..𝗓 → 𝖠..𝖹 Math */ 1299 | {0x1d5ee, 0x1d607, -26}, /* 26x 𝗮..𝘇 → 𝗔..𝗭 Math */ 1300 | {0x1d622, 0x1d63b, -26}, /* 26x 𝘢..𝘻 → 𝘈..𝘡 Math */ 1301 | {0x1d68a, 0x1d6a3, +442}, /* 26x 𝒂..𝒛 → 𝘼..𝙕 Math */ 1302 | {0x1d6c2, 0x1d6d2, -26}, /* 26x 𝚊..𝚣 → 𝙰..𝚉 Math */ 1303 | {0x1d6fc, 0x1d70c, -26}, /* 17x 𝛂..𝛒 → 𝚨..𝚸 Math */ 1304 | {0x1d736, 0x1d746, -26}, /* 17x 𝛼..𝜌 → 𝛢..𝛲 Math */ 1305 | {0x1d770, 0x1d780, -26}, /* 17x 𝜶..𝝆 → 𝜜..𝜬 Math */ 1306 | {0x1d770, 0x1d756, -26}, /* 17x 𝝰..𝞀 → 𝝖..𝝦 Math */ 1307 | {0x1d736, 0x1d790, -90}, /* 17x 𝜶..𝝆 → 𝞐..𝞠 Math */ 1308 | }; 1309 | l = 0; 1310 | r = n = sizeof(kAstralUpper) / sizeof(kAstralUpper[0]); 1311 | while (l < r) { 1312 | m = (l + r) >> 1; 1313 | if (kAstralUpper[m].b < c) { 1314 | l = m + 1; 1315 | } else { 1316 | r = m; 1317 | } 1318 | } 1319 | if (l < n && kAstralUpper[l].a <= c && c <= kAstralUpper[l].b) { 1320 | return c + kAstralUpper[l].d; 1321 | } else { 1322 | return c; 1323 | } 1324 | } 1325 | } 1326 | 1327 | char bestlineNotSeparator(unsigned c) { 1328 | return !bestlineIsSeparator(c); 1329 | } 1330 | 1331 | static unsigned GetMirror(const unsigned short A[][2], size_t n, unsigned c) { 1332 | int l, m, r; 1333 | l = 0; 1334 | r = n - 1; 1335 | while (l <= r) { 1336 | m = (l + r) >> 1; 1337 | if (A[m][0] < c) { 1338 | l = m + 1; 1339 | } else if (A[m][0] > c) { 1340 | r = m - 1; 1341 | } else { 1342 | return A[m][1]; 1343 | } 1344 | } 1345 | return 0; 1346 | } 1347 | 1348 | unsigned bestlineMirrorLeft(unsigned c) { 1349 | static const unsigned short kMirrorRight[][2] = { 1350 | {L')', L'('}, {L']', L'['}, {L'}', L'{'}, {L'⁆', L'⁅'}, {L'⁾', L'⁽'}, 1351 | {L'₎', L'₍'}, {L'⌉', L'⌈'}, {L'⌋', L'⌊'}, {L'〉', L'〈'}, {L'❩', L'❨'}, 1352 | {L'❫', L'❪'}, {L'❭', L'❬'}, {L'❯', L'❮'}, {L'❱', L'❰'}, {L'❳', L'❲'}, 1353 | {L'❵', L'❴'}, {L'⟆', L'⟅'}, {L'⟧', L'⟦'}, {L'⟩', L'⟨'}, {L'⟫', L'⟪'}, 1354 | {L'⟭', L'⟬'}, {L'⟯', L'⟮'}, {L'⦄', L'⦃'}, {L'⦆', L'⦅'}, {L'⦈', L'⦇'}, 1355 | {L'⦊', L'⦉'}, {L'⦌', L'⦋'}, {L'⦎', L'⦏'}, {L'⦐', L'⦍'}, {L'⦒', L'⦑'}, 1356 | {L'⦔', L'⦓'}, {L'⦘', L'⦗'}, {L'⧙', L'⧘'}, {L'⧛', L'⧚'}, {L'⧽', L'⧼'}, 1357 | {L'﹚', L'﹙'}, {L'﹜', L'﹛'}, {L'﹞', L'﹝'}, {L')', L'('}, {L']', L'['}, 1358 | {L'}', L'{'}, {L'」', L'「'}, 1359 | }; 1360 | return GetMirror(kMirrorRight, sizeof(kMirrorRight) / sizeof(kMirrorRight[0]), c); 1361 | } 1362 | 1363 | unsigned bestlineMirrorRight(unsigned c) { 1364 | static const unsigned short kMirrorLeft[][2] = { 1365 | {L'(', L')'}, {L'[', L']'}, {L'{', L'}'}, {L'⁅', L'⁆'}, {L'⁽', L'⁾'}, 1366 | {L'₍', L'₎'}, {L'⌈', L'⌉'}, {L'⌊', L'⌋'}, {L'〈', L'〉'}, {L'❨', L'❩'}, 1367 | {L'❪', L'❫'}, {L'❬', L'❭'}, {L'❮', L'❯'}, {L'❰', L'❱'}, {L'❲', L'❳'}, 1368 | {L'❴', L'❵'}, {L'⟅', L'⟆'}, {L'⟦', L'⟧'}, {L'⟨', L'⟩'}, {L'⟪', L'⟫'}, 1369 | {L'⟬', L'⟭'}, {L'⟮', L'⟯'}, {L'⦃', L'⦄'}, {L'⦅', L'⦆'}, {L'⦇', L'⦈'}, 1370 | {L'⦉', L'⦊'}, {L'⦋', L'⦌'}, {L'⦍', L'⦐'}, {L'⦏', L'⦎'}, {L'⦑', L'⦒'}, 1371 | {L'⦓', L'⦔'}, {L'⦗', L'⦘'}, {L'⧘', L'⧙'}, {L'⧚', L'⧛'}, {L'⧼', L'⧽'}, 1372 | {L'﹙', L'﹚'}, {L'﹛', L'﹜'}, {L'﹝', L'﹞'}, {L'(', L')'}, {L'[', L']'}, 1373 | {L'{', L'}'}, {L'「', L'」'}, 1374 | }; 1375 | return GetMirror(kMirrorLeft, sizeof(kMirrorLeft) / sizeof(kMirrorLeft[0]), c); 1376 | } 1377 | 1378 | static char StartsWith(const char *s, const char *prefix) { 1379 | for (;;) { 1380 | if (!*prefix) 1381 | return 1; 1382 | if (!*s) 1383 | return 0; 1384 | if (*s++ != *prefix++) 1385 | return 0; 1386 | } 1387 | } 1388 | 1389 | static char EndsWith(const char *s, const char *suffix) { 1390 | size_t n, m; 1391 | n = strlen(s); 1392 | m = strlen(suffix); 1393 | if (m > n) 1394 | return 0; 1395 | return !memcmp(s + n - m, suffix, m); 1396 | } 1397 | 1398 | char bestlineIsXeparator(unsigned c) { 1399 | return (bestlineIsSeparator(c) && !bestlineMirrorLeft(c) && !bestlineMirrorRight(c)); 1400 | } 1401 | 1402 | static unsigned Capitalize(unsigned c) { 1403 | if (!iscapital) { 1404 | c = bestlineUppercase(c); 1405 | iscapital = 1; 1406 | } 1407 | return c; 1408 | } 1409 | 1410 | static inline int Bsr(unsigned long long x) { 1411 | #if defined(__GNUC__) && !defined(__STRICT_ANSI__) 1412 | int b; 1413 | b = __builtin_clzll(x); 1414 | b ^= sizeof(unsigned long long) * CHAR_BIT - 1; 1415 | return b; 1416 | #else 1417 | static const char kDebruijn[64] = { 1418 | 0, 47, 1, 56, 48, 27, 2, 60, 57, 49, 41, 37, 28, 16, 3, 61, 54, 58, 35, 52, 50, 42, 1419 | 21, 44, 38, 32, 29, 23, 17, 11, 4, 62, 46, 55, 26, 59, 40, 36, 15, 53, 34, 51, 20, 43, 1420 | 31, 22, 10, 45, 25, 39, 14, 33, 19, 30, 9, 24, 13, 18, 8, 12, 7, 6, 5, 63, 1421 | }; 1422 | x |= x >> 1; 1423 | x |= x >> 2; 1424 | x |= x >> 4; 1425 | x |= x >> 8; 1426 | x |= x >> 16; 1427 | x |= x >> 32; 1428 | return kDebruijn[(x * 0x03f79d71b4cb0a89) >> 58]; 1429 | #endif 1430 | } 1431 | 1432 | static struct rune DecodeUtf8(int c) { 1433 | struct rune r; 1434 | if (c < 252) { 1435 | r.n = Bsr(255 & ~c); 1436 | r.c = c & (((1 << r.n) - 1) | 3); 1437 | r.n = 6 - r.n; 1438 | } else { 1439 | r.c = c & 3; 1440 | r.n = 5; 1441 | } 1442 | return r; 1443 | } 1444 | 1445 | static unsigned long long EncodeUtf8(unsigned c) { 1446 | static const unsigned short kTpEnc[32 - 7] = { 1447 | 1 | 0300 << 8, 1 | 0300 << 8, 1 | 0300 << 8, 1 | 0300 << 8, 2 | 0340 << 8, 1448 | 2 | 0340 << 8, 2 | 0340 << 8, 2 | 0340 << 8, 2 | 0340 << 8, 3 | 0360 << 8, 1449 | 3 | 0360 << 8, 3 | 0360 << 8, 3 | 0360 << 8, 3 | 0360 << 8, 4 | 0370 << 8, 1450 | 4 | 0370 << 8, 4 | 0370 << 8, 4 | 0370 << 8, 4 | 0370 << 8, 5 | 0374 << 8, 1451 | 5 | 0374 << 8, 5 | 0374 << 8, 5 | 0374 << 8, 5 | 0374 << 8, 5 | 0374 << 8, 1452 | }; 1453 | int e, n; 1454 | unsigned long long w; 1455 | if (c < 0200) 1456 | return c; 1457 | e = kTpEnc[Bsr(c) - 7]; 1458 | n = e & 0xff; 1459 | w = 0; 1460 | do { 1461 | w |= 0200 | (c & 077); 1462 | w <<= 8; 1463 | c >>= 6; 1464 | } while (--n); 1465 | return c | w | e >> 8; 1466 | } 1467 | 1468 | static struct rune GetUtf8(const char *p, size_t n) { 1469 | struct rune r; 1470 | if ((r.n = r.c = 0) < n && (r.c = p[r.n++] & 255) >= 0300) { 1471 | r.c = DecodeUtf8(r.c).c; 1472 | while (r.n < n && (p[r.n] & 0300) == 0200) { 1473 | r.c = r.c << 6 | (p[r.n++] & 077); 1474 | } 1475 | } 1476 | return r; 1477 | } 1478 | 1479 | static char *FormatUnsigned(char *p, unsigned x) { 1480 | char t; 1481 | size_t i, a, b; 1482 | i = 0; 1483 | do { 1484 | p[i++] = x % 10 + '0'; 1485 | x = x / 10; 1486 | } while (x > 0); 1487 | p[i] = '\0'; 1488 | if (i) { 1489 | for (a = 0, b = i - 1; a < b; ++a, --b) { 1490 | t = p[a]; 1491 | p[a] = p[b]; 1492 | p[b] = t; 1493 | } 1494 | } 1495 | return p + i; 1496 | } 1497 | 1498 | static void abInit(struct abuf *a) { 1499 | a->len = 0; 1500 | a->cap = 16; 1501 | a->b = (char *)malloc(a->cap); 1502 | a->b[0] = 0; 1503 | } 1504 | 1505 | static char abGrow(struct abuf *a, int need) { 1506 | int cap; 1507 | char *b; 1508 | cap = a->cap; 1509 | do 1510 | cap += cap / 2; 1511 | while (cap < need); 1512 | if (!(b = (char *)realloc(a->b, cap * sizeof(*a->b)))) 1513 | return 0; 1514 | a->cap = cap; 1515 | a->b = b; 1516 | return 1; 1517 | } 1518 | 1519 | static void abAppendw(struct abuf *a, unsigned long long w) { 1520 | char *p; 1521 | if (a->len + 8 > a->cap && !abGrow(a, a->len + 8)) 1522 | return; 1523 | p = a->b + a->len; 1524 | p[0] = (0x00000000000000FF & w) >> 000; 1525 | p[1] = (0x000000000000FF00 & w) >> 010; 1526 | p[2] = (0x0000000000FF0000 & w) >> 020; 1527 | p[3] = (0x00000000FF000000 & w) >> 030; 1528 | p[4] = (0x000000FF00000000 & w) >> 040; 1529 | p[5] = (0x0000FF0000000000 & w) >> 050; 1530 | p[6] = (0x00FF000000000000 & w) >> 060; 1531 | p[7] = (0xFF00000000000000 & w) >> 070; 1532 | a->len += w ? (Bsr(w) >> 3) + 1 : 1; 1533 | } 1534 | 1535 | static void abAppend(struct abuf *a, const char *s, int len) { 1536 | if (a->len + len + 1 > a->cap && !abGrow(a, a->len + len + 1)) 1537 | return; 1538 | memcpy(a->b + a->len, s, len); 1539 | a->b[a->len + len] = 0; 1540 | a->len += len; 1541 | } 1542 | 1543 | static void abAppends(struct abuf *a, const char *s) { 1544 | abAppend(a, s, strlen(s)); 1545 | } 1546 | 1547 | static void abAppendu(struct abuf *a, unsigned u) { 1548 | char b[11]; 1549 | abAppend(a, b, FormatUnsigned(b, u) - b); 1550 | } 1551 | 1552 | static void abFree(struct abuf *a) { 1553 | free(a->b); 1554 | a->b = 0; 1555 | } 1556 | 1557 | static size_t GetFdSize(int fd) { 1558 | struct stat st; 1559 | st.st_size = 0; 1560 | fstat(fd, &st); 1561 | return st.st_size; 1562 | } 1563 | 1564 | static char IsCharDev(int fd) { 1565 | struct stat st; 1566 | st.st_mode = 0; 1567 | fstat(fd, &st); 1568 | return (st.st_mode & S_IFMT) == S_IFCHR; 1569 | } 1570 | 1571 | static int MyRead(int fd, void *c, int); 1572 | static int MyWrite(int fd, const void *c, int); 1573 | static int MyPoll(int fd, int events, int to); 1574 | 1575 | static int (*_MyRead)(int fd, void *c, int n) = MyRead; 1576 | static int (*_MyWrite)(int fd, const void *c, int n) = MyWrite; 1577 | static int (*_MyPoll)(int fd, int events, int to) = MyPoll; 1578 | 1579 | static int WaitUntilReady(int fd, int events) { 1580 | return _MyPoll(fd, events, -1); 1581 | } 1582 | 1583 | static char HasPendingInput(int fd) { 1584 | return _MyPoll(fd, POLLIN, 0) == 1; 1585 | } 1586 | 1587 | static char *GetLineBlock(FILE *f) { 1588 | ssize_t rc; 1589 | char *p = 0; 1590 | size_t n, c = 0; 1591 | if ((rc = getdelim(&p, &c, '\n', f)) != EOF) { 1592 | for (n = rc; n; --n) { 1593 | if (p[n - 1] == '\r' || p[n - 1] == '\n') { 1594 | p[n - 1] = 0; 1595 | } else { 1596 | break; 1597 | } 1598 | } 1599 | return p; 1600 | } else { 1601 | free(p); 1602 | return 0; 1603 | } 1604 | } 1605 | 1606 | long bestlineReadCharacter(int fd, char *p, unsigned long n) { 1607 | int e; 1608 | size_t i; 1609 | ssize_t rc; 1610 | struct rune r; 1611 | unsigned char c; 1612 | enum { kAscii, kUtf8, kEsc, kCsi1, kCsi2, kSs, kNf, kStr, kStr2, kDone } t; 1613 | i = 0; 1614 | r.c = 0; 1615 | r.n = 0; 1616 | e = errno; 1617 | t = kAscii; 1618 | if (n) 1619 | p[0] = 0; 1620 | do { 1621 | for (;;) { 1622 | if (gotint) { 1623 | errno = EINTR; 1624 | return -1; 1625 | } 1626 | if (n) { 1627 | rc = _MyRead(fd, &c, 1); 1628 | } else { 1629 | rc = _MyRead(fd, 0, 0); 1630 | } 1631 | if (rc == -1 && errno == EINTR) { 1632 | if (!i) { 1633 | return -1; 1634 | } 1635 | } else if (rc == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { 1636 | if (WaitUntilReady(fd, POLLIN) == -1) { 1637 | if (rc == -1 && errno == EINTR) { 1638 | if (!i) { 1639 | return -1; 1640 | } 1641 | } else { 1642 | return -1; 1643 | } 1644 | } 1645 | } else if (rc == -1) { 1646 | return -1; 1647 | } else if (!rc) { 1648 | if (!i) { 1649 | errno = e; 1650 | return 0; 1651 | } else { 1652 | errno = EILSEQ; 1653 | return -1; 1654 | } 1655 | } else { 1656 | break; 1657 | } 1658 | } 1659 | if (i + 1 < n) { 1660 | p[i] = c; 1661 | p[i + 1] = 0; 1662 | } else if (i < n) { 1663 | p[i] = 0; 1664 | } 1665 | ++i; 1666 | switch (t) { 1667 | Whoopsie: 1668 | if (n) 1669 | p[0] = c; 1670 | t = kAscii; 1671 | i = 1; 1672 | /* fallthrough */ 1673 | case kAscii: 1674 | if (c < 0200) { 1675 | if (c == 033) { 1676 | t = kEsc; 1677 | } else { 1678 | t = kDone; 1679 | } 1680 | } else if (c >= 0300) { 1681 | t = kUtf8; 1682 | r = DecodeUtf8(c); 1683 | } else { 1684 | /* ignore overlong sequences */ 1685 | } 1686 | break; 1687 | case kUtf8: 1688 | if ((c & 0300) == 0200) { 1689 | r.c <<= 6; 1690 | r.c |= c & 077; 1691 | if (!--r.n) { 1692 | switch (r.c) { 1693 | case 033: 1694 | t = kEsc; /* parsed but not canonicalized */ 1695 | break; 1696 | case 0x9b: 1697 | t = kCsi1; /* unusual but legal */ 1698 | break; 1699 | case 0x8e: /* SS2 (Single Shift Two) */ 1700 | case 0x8f: /* SS3 (Single Shift Three) */ 1701 | t = kSs; 1702 | break; 1703 | case 0x90: /* DCS (Device Control String) */ 1704 | case 0x98: /* SOS (Start of String) */ 1705 | case 0x9d: /* OSC (Operating System Command) */ 1706 | case 0x9e: /* PM (Privacy Message) */ 1707 | case 0x9f: /* APC (Application Program Command) */ 1708 | t = kStr; 1709 | break; 1710 | default: 1711 | t = kDone; 1712 | break; 1713 | } 1714 | } 1715 | } else { 1716 | goto Whoopsie; /* ignore underlong sequences if not eof */ 1717 | } 1718 | break; 1719 | case kEsc: 1720 | if (0x20 <= c && c <= 0x2f) { /* Nf */ 1721 | /* 1722 | * Almost no one uses ANSI Nf sequences 1723 | * They overlaps with alt+graphic keystrokes 1724 | * We care more about being able to type alt-/ 1725 | */ 1726 | if (c == ' ' || c == '#') { 1727 | t = kNf; 1728 | } else { 1729 | t = kDone; 1730 | } 1731 | } else if (0x30 <= c && c <= 0x3f) { /* Fp */ 1732 | t = kDone; 1733 | } else if (0x20 <= c && c <= 0x5F) { /* Fe */ 1734 | switch (c) { 1735 | case '[': 1736 | t = kCsi1; 1737 | break; 1738 | case 'N': /* SS2 (Single Shift Two) */ 1739 | case 'O': /* SS3 (Single Shift Three) */ 1740 | t = kSs; 1741 | break; 1742 | case 'P': /* DCS (Device Control String) */ 1743 | case 'X': /* SOS (Start of String) */ 1744 | case ']': /* OSC (Operating System Command) */ 1745 | case '^': /* PM (Privacy Message) */ 1746 | case '_': /* APC (Application Program Command) */ 1747 | t = kStr; 1748 | break; 1749 | default: 1750 | t = kDone; 1751 | break; 1752 | } 1753 | } else if (0x60 <= c && c <= 0x7e) { /* Fs */ 1754 | t = kDone; 1755 | } else if (c == 033) { 1756 | if (i < 3) { 1757 | /* alt chording */ 1758 | } else { 1759 | t = kDone; /* esc mashing */ 1760 | i = 1; 1761 | } 1762 | } else { 1763 | t = kDone; 1764 | } 1765 | break; 1766 | case kSs: 1767 | t = kDone; 1768 | break; 1769 | case kNf: 1770 | if (0x30 <= c && c <= 0x7e) { 1771 | t = kDone; 1772 | } else if (!(0x20 <= c && c <= 0x2f)) { 1773 | goto Whoopsie; 1774 | } 1775 | break; 1776 | case kCsi1: 1777 | if (0x20 <= c && c <= 0x2f) { 1778 | t = kCsi2; 1779 | } else if (c == '[' && ((i == 3) || (i == 4 && p[1] == 033))) { 1780 | /* linux function keys */ 1781 | } else if (0x40 <= c && c <= 0x7e) { 1782 | t = kDone; 1783 | } else if (!(0x30 <= c && c <= 0x3f)) { 1784 | goto Whoopsie; 1785 | } 1786 | break; 1787 | case kCsi2: 1788 | if (0x40 <= c && c <= 0x7e) { 1789 | t = kDone; 1790 | } else if (!(0x20 <= c && c <= 0x2f)) { 1791 | goto Whoopsie; 1792 | } 1793 | break; 1794 | case kStr: 1795 | switch (c) { 1796 | case '\a': 1797 | t = kDone; 1798 | break; 1799 | case 0033: /* ESC */ 1800 | case 0302: /* C1 (UTF-8) */ 1801 | t = kStr2; 1802 | break; 1803 | default: 1804 | break; 1805 | } 1806 | break; 1807 | case kStr2: 1808 | switch (c) { 1809 | case '\a': 1810 | case '\\': /* ST (ASCII) */ 1811 | case 0234: /* ST (UTF-8) */ 1812 | t = kDone; 1813 | break; 1814 | default: 1815 | t = kStr; 1816 | break; 1817 | } 1818 | break; 1819 | default: 1820 | assert(0); 1821 | } 1822 | } while (t != kDone); 1823 | errno = e; 1824 | return i; 1825 | } 1826 | 1827 | static char *GetLineChar(int fin, int fout) { 1828 | size_t got; 1829 | ssize_t rc; 1830 | char seq[16]; 1831 | struct abuf a; 1832 | struct sigaction sa[3]; 1833 | abInit(&a); 1834 | gotint = 0; 1835 | sigemptyset(&sa->sa_mask); 1836 | sa->sa_flags = 0; 1837 | sa->sa_handler = bestlineOnInt; 1838 | sigaction(SIGINT, sa, sa + 1); 1839 | sigaction(SIGQUIT, sa, sa + 2); 1840 | for (;;) { 1841 | if (gotint) { 1842 | rc = -1; 1843 | break; 1844 | } 1845 | if ((rc = bestlineReadCharacter(fin, seq, sizeof(seq))) == -1) { 1846 | if (errno == EAGAIN || errno == EWOULDBLOCK) { 1847 | if (WaitUntilReady(fin, POLLIN) > 0) { 1848 | continue; 1849 | } 1850 | } 1851 | if (errno == EINTR) { 1852 | continue; 1853 | } else { 1854 | break; 1855 | } 1856 | } 1857 | if (!(got = rc)) { 1858 | if (a.len) { 1859 | break; 1860 | } else { 1861 | rc = -1; 1862 | break; 1863 | } 1864 | } 1865 | if (seq[0] == '\r') { 1866 | if (HasPendingInput(fin)) { 1867 | if ((rc = bestlineReadCharacter(fin, seq + 1, sizeof(seq) - 1)) > 0) { 1868 | if (seq[0] == '\n') { 1869 | break; 1870 | } 1871 | } else { 1872 | rc = -1; 1873 | break; 1874 | } 1875 | } else { 1876 | _MyWrite(fout, "\n", 1); 1877 | break; 1878 | } 1879 | } else if (seq[0] == Ctrl('D')) { 1880 | break; 1881 | } else if (seq[0] == '\n') { 1882 | break; 1883 | } else if (seq[0] == '\b') { 1884 | while (a.len && (a.b[a.len - 1] & 0300) == 0200) 1885 | --a.len; 1886 | if (a.len) 1887 | --a.len; 1888 | } 1889 | if (!IsControl(seq[0])) { 1890 | abAppend(&a, seq, got); 1891 | } 1892 | } 1893 | sigaction(SIGQUIT, sa + 2, 0); 1894 | sigaction(SIGINT, sa + 1, 0); 1895 | if (gotint) { 1896 | abFree(&a); 1897 | raise(gotint); 1898 | errno = EINTR; 1899 | rc = -1; 1900 | } 1901 | if (rc != -1) { 1902 | return a.b; 1903 | } else { 1904 | abFree(&a); 1905 | return 0; 1906 | } 1907 | } 1908 | 1909 | static char *GetLine(FILE *in, FILE *out) { 1910 | if (!IsCharDev(fileno(in))) { 1911 | return GetLineBlock(in); 1912 | } else { 1913 | return GetLineChar(fileno(in), fileno(out)); 1914 | } 1915 | } 1916 | 1917 | static char *Copy(char *d, const char *s, size_t n) { 1918 | memcpy(d, s, n); 1919 | return d + n; 1920 | } 1921 | 1922 | static int CompareStrings(const char *a, const char *b) { 1923 | size_t i; 1924 | int x, y, c; 1925 | for (i = 0;; ++i) { 1926 | x = bestlineLowercase(a[i] & 255); 1927 | y = bestlineLowercase(b[i] & 255); 1928 | if ((c = x - y) || !x) { 1929 | return c; 1930 | } 1931 | } 1932 | } 1933 | 1934 | static const char *FindSubstringReverse(const char *p, size_t n, const char *q, size_t m) { 1935 | size_t i; 1936 | if (m <= n) { 1937 | n -= m; 1938 | do { 1939 | for (i = 0; i < m; ++i) { 1940 | if (p[n + i] != q[i]) { 1941 | break; 1942 | } 1943 | } 1944 | if (i == m) { 1945 | return p + n; 1946 | } 1947 | } while (n--); 1948 | } 1949 | return 0; 1950 | } 1951 | 1952 | static int ParseUnsigned(const char *s, void *e) { 1953 | int c, x; 1954 | for (x = 0; (c = *s++);) { 1955 | if ('0' <= c && c <= '9') { 1956 | x = Min(c - '0' + x * 10, 32767); 1957 | } else { 1958 | break; 1959 | } 1960 | } 1961 | if (e) 1962 | *(const char **)e = s; 1963 | return x; 1964 | } 1965 | 1966 | /** 1967 | * Returns UNICODE CJK Monospace Width of string. 1968 | * 1969 | * Control codes and ANSI sequences have a width of zero. We only parse 1970 | * a limited subset of ANSI here since we don't store ANSI codes in the 1971 | * linenoiseState::buf, but we do encourage CSI color codes in prompts. 1972 | */ 1973 | static size_t GetMonospaceWidth(const char *p, size_t n, char *out_haswides) { 1974 | int c, d; 1975 | size_t i, w; 1976 | struct rune r; 1977 | char haswides; 1978 | enum { kAscii, kUtf8, kEsc, kCsi1, kCsi2 } t; 1979 | for (haswides = r.c = r.n = w = i = 0, t = kAscii; i < n; ++i) { 1980 | c = p[i] & 255; 1981 | switch (t) { 1982 | Whoopsie: 1983 | t = kAscii; 1984 | /* fallthrough */ 1985 | case kAscii: 1986 | if (c < 0200) { 1987 | if (c == 033) { 1988 | t = kEsc; 1989 | } else { 1990 | ++w; 1991 | } 1992 | } else if (c >= 0300) { 1993 | t = kUtf8; 1994 | r = DecodeUtf8(c); 1995 | } 1996 | break; 1997 | case kUtf8: 1998 | if ((c & 0300) == 0200) { 1999 | r.c <<= 6; 2000 | r.c |= c & 077; 2001 | if (!--r.n) { 2002 | d = bestlineCharacterWidth(r.c); 2003 | d = Max(0, d); 2004 | w += d; 2005 | haswides |= d > 1; 2006 | t = kAscii; 2007 | break; 2008 | } 2009 | } else { 2010 | goto Whoopsie; 2011 | } 2012 | break; 2013 | case kEsc: 2014 | if (c == '[') { 2015 | t = kCsi1; 2016 | } else { 2017 | t = kAscii; 2018 | } 2019 | break; 2020 | case kCsi1: 2021 | if (0x20 <= c && c <= 0x2f) { 2022 | t = kCsi2; 2023 | } else if (0x40 <= c && c <= 0x7e) { 2024 | t = kAscii; 2025 | } else if (!(0x30 <= c && c <= 0x3f)) { 2026 | goto Whoopsie; 2027 | } 2028 | break; 2029 | case kCsi2: 2030 | if (0x40 <= c && c <= 0x7e) { 2031 | t = kAscii; 2032 | } else if (!(0x20 <= c && c <= 0x2f)) { 2033 | goto Whoopsie; 2034 | } 2035 | break; 2036 | default: 2037 | assert(0); 2038 | } 2039 | } 2040 | if (out_haswides) { 2041 | *out_haswides = haswides; 2042 | } 2043 | return w; 2044 | } 2045 | 2046 | static int bestlineIsUnsupportedTerm(void) { 2047 | size_t i; 2048 | char *term; 2049 | static char once, res; 2050 | if (!once) { 2051 | if ((term = getenv("TERM"))) { 2052 | for (i = 0; i < sizeof(kUnsupported) / sizeof(*kUnsupported); i++) { 2053 | if (!CompareStrings(term, kUnsupported[i])) { 2054 | res = 1; 2055 | break; 2056 | } 2057 | } 2058 | } 2059 | once = 1; 2060 | } 2061 | return res; 2062 | } 2063 | 2064 | static int enableRawMode(int fd) { 2065 | struct termios raw; 2066 | struct sigaction sa; 2067 | if (tcgetattr(fd, &orig_termios) != -1) { 2068 | raw = orig_termios; 2069 | raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); 2070 | raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); 2071 | raw.c_iflag |= IUTF8; 2072 | raw.c_cflag |= CS8; 2073 | raw.c_cc[VMIN] = 1; 2074 | raw.c_cc[VTIME] = 0; 2075 | if (tcsetattr(fd, TCSANOW, &raw) != -1) { 2076 | sa.sa_flags = 0; 2077 | sa.sa_handler = bestlineOnCont; 2078 | sigemptyset(&sa.sa_mask); 2079 | sigaction(SIGCONT, &sa, &orig_cont); 2080 | sa.sa_handler = bestlineOnWinch; 2081 | sigaction(SIGWINCH, &sa, &orig_winch); 2082 | rawmode = fd; 2083 | gotwinch = 0; 2084 | gotcont = 0; 2085 | return 0; 2086 | } 2087 | } 2088 | errno = ENOTTY; 2089 | return -1; 2090 | } 2091 | 2092 | static void bestlineUnpause(int fd) { 2093 | if (ispaused) { 2094 | tcflow(fd, TCOON); 2095 | ispaused = 0; 2096 | } 2097 | } 2098 | 2099 | void bestlineDisableRawMode(void) { 2100 | if (rawmode != -1) { 2101 | bestlineUnpause(rawmode); 2102 | sigaction(SIGCONT, &orig_cont, 0); 2103 | sigaction(SIGWINCH, &orig_winch, 0); 2104 | tcsetattr(rawmode, TCSANOW, &orig_termios); 2105 | rawmode = -1; 2106 | } 2107 | } 2108 | 2109 | static int bestlineWrite(int fd, const void *p, size_t n) { 2110 | ssize_t rc; 2111 | size_t wrote; 2112 | do { 2113 | for (;;) { 2114 | if (gotint) { 2115 | errno = EINTR; 2116 | return -1; 2117 | } 2118 | if (ispaused) { 2119 | return 0; 2120 | } 2121 | rc = _MyWrite(fd, p, n); 2122 | if (rc == -1 && errno == EINTR) { 2123 | continue; 2124 | } else if (rc == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { 2125 | if (WaitUntilReady(fd, POLLOUT) == -1) { 2126 | if (errno == EINTR) { 2127 | continue; 2128 | } else { 2129 | return -1; 2130 | } 2131 | } 2132 | } else { 2133 | break; 2134 | } 2135 | } 2136 | if (rc != -1) { 2137 | wrote = rc; 2138 | n -= wrote; 2139 | p = (char *)p + wrote; 2140 | } else { 2141 | return -1; 2142 | } 2143 | } while (n); 2144 | return 0; 2145 | } 2146 | 2147 | static int bestlineWriteStr(int fd, const char *p) { 2148 | return bestlineWrite(fd, p, strlen(p)); 2149 | } 2150 | 2151 | static ssize_t bestlineRead(int fd, char *buf, size_t size, struct bestlineState *l) { 2152 | size_t got; 2153 | ssize_t rc; 2154 | int refreshme; 2155 | do { 2156 | refreshme = 0; 2157 | if (gotint) { 2158 | errno = EINTR; 2159 | return -1; 2160 | } 2161 | if (gotcont && rawmode != -1) { 2162 | enableRawMode(rawmode); 2163 | if (l) 2164 | refreshme = 1; 2165 | } 2166 | if (gotwinch && l) { 2167 | refreshme = 1; 2168 | } 2169 | if (refreshme) 2170 | bestlineRefreshLine(l); 2171 | rc = bestlineReadCharacter(fd, buf, size); 2172 | } while (rc == -1 && errno == EINTR); 2173 | if (rc != -1) { 2174 | got = rc; 2175 | if (got > 0 && l) { 2176 | memcpy(l->seq[1], l->seq[0], sizeof(l->seq[0])); 2177 | memset(l->seq[0], 0, sizeof(l->seq[0])); 2178 | memcpy(l->seq[0], buf, Min(Min(size, got), sizeof(l->seq[0]) - 1)); 2179 | } 2180 | } 2181 | return rc; 2182 | } 2183 | 2184 | /** 2185 | * Returns number of columns in current terminal. 2186 | * 2187 | * 1. Checks COLUMNS environment variable (set by Emacs) 2188 | * 2. Tries asking termios (works for pseudoteletypewriters) 2189 | * 3. Falls back to inband signalling (works w/ pipe or serial) 2190 | * 4. Otherwise we conservatively assume 80 columns 2191 | * 2192 | * @param ws should be initialized by caller to zero before first call 2193 | * @param ifd is input file descriptor 2194 | * @param ofd is output file descriptor 2195 | * @return window size 2196 | */ 2197 | static struct winsize GetTerminalSize(struct winsize ws, int ifd, int ofd) { 2198 | int x; 2199 | ssize_t n; 2200 | char *p, *s, b[16]; 2201 | ioctl(ofd, TIOCGWINSZ, &ws); 2202 | if ((!ws.ws_row && (s = getenv("ROWS")) && (x = ParseUnsigned(s, 0)))) { 2203 | ws.ws_row = x; 2204 | } 2205 | if ((!ws.ws_col && (s = getenv("COLUMNS")) && (x = ParseUnsigned(s, 0)))) { 2206 | ws.ws_col = x; 2207 | } 2208 | if (((!ws.ws_col || !ws.ws_row) && bestlineRead(ifd, 0, 0, 0) != -1 && 2209 | bestlineWriteStr(ofd, "\0337" /* save position */ 2210 | "\033[9979;9979H" /* move cursor to bottom right corner */ 2211 | "\033[6n" /* report position */ 2212 | "\0338") != -1 && /* restore position */ 2213 | (n = bestlineRead(ifd, b, sizeof(b), 0)) != -1 && 2214 | n && b[0] == 033 && b[1] == '[' && b[n - 1] == 'R')) { 2215 | p = b + 2; 2216 | if ((x = ParseUnsigned(p, &p))) 2217 | ws.ws_row = x; 2218 | if (*p++ == ';' && (x = ParseUnsigned(p, 0))) 2219 | ws.ws_col = x; 2220 | } 2221 | if (!ws.ws_col) 2222 | ws.ws_col = 80; 2223 | if (!ws.ws_row) 2224 | ws.ws_row = 24; 2225 | return ws; 2226 | } 2227 | 2228 | /* Clear the screen. Used to handle ctrl+l */ 2229 | void bestlineClearScreen(int fd) { 2230 | bestlineWriteStr(fd, "\033[H" /* move cursor to top left corner */ 2231 | "\033[2J"); /* erase display */ 2232 | } 2233 | 2234 | static void bestlineBeep(void) { 2235 | /* THE TERMINAL BELL IS DEAD - HISTORY HAS KILLED IT */ 2236 | } 2237 | 2238 | static char bestlineGrow(struct bestlineState *ls, size_t n) { 2239 | char *p; 2240 | size_t m; 2241 | m = ls->buflen; 2242 | if (m >= n) 2243 | return 1; 2244 | do 2245 | m += m >> 1; 2246 | while (m < n); 2247 | if (!(p = (char *)realloc(ls->buf, m * sizeof(*ls->buf)))) 2248 | return 0; 2249 | ls->buf = p; 2250 | ls->buflen = m; 2251 | return 1; 2252 | } 2253 | 2254 | /* This is an helper function for bestlineEdit() and is called when the 2255 | * user types the key in order to complete the string currently in the 2256 | * input. 2257 | * 2258 | * The state of the editing is encapsulated into the pointed bestlineState 2259 | * structure as described in the structure definition. */ 2260 | static ssize_t bestlineCompleteLine(struct bestlineState *ls, char *seq, int size) { 2261 | ssize_t nread; 2262 | size_t i, n, stop; 2263 | bestlineCompletions lc; 2264 | struct bestlineState original, saved; 2265 | nread = 0; 2266 | memset(&lc, 0, sizeof(lc)); 2267 | completionCallback(ls->buf, ls->pos, &lc); 2268 | if (!lc.len) { 2269 | bestlineBeep(); 2270 | } else { 2271 | i = 0; 2272 | stop = 0; 2273 | original = *ls; 2274 | while (!stop) { 2275 | /* Show completion or original buffer */ 2276 | if (i < lc.len) { 2277 | saved = *ls; 2278 | ls->len = strlen(lc.cvec[i]); 2279 | ls->pos = original.pos + ls->len - original.len; 2280 | ls->buf = lc.cvec[i]; 2281 | bestlineRefreshLine(ls); 2282 | ls->len = saved.len; 2283 | ls->pos = saved.pos; 2284 | ls->buf = saved.buf; 2285 | if (lc.len == 1) { 2286 | nread = 0; 2287 | goto FinishQuickly; 2288 | } 2289 | } else { 2290 | bestlineRefreshLine(ls); 2291 | } 2292 | if ((nread = bestlineRead(ls->ifd, seq, size, ls)) <= 0) { 2293 | bestlineFreeCompletions(&lc); 2294 | return -1; 2295 | } 2296 | switch (seq[0]) { 2297 | case '\t': 2298 | i = (i + 1) % (lc.len + 1); 2299 | if (i == lc.len) { 2300 | bestlineBeep(); 2301 | } 2302 | break; 2303 | default: 2304 | if (i < lc.len) { 2305 | FinishQuickly: 2306 | n = strlen(lc.cvec[i]); 2307 | if (bestlineGrow(ls, n + 1)) { 2308 | memcpy(ls->buf, lc.cvec[i], n + 1); 2309 | ls->len = n; 2310 | ls->pos = original.pos + n - original.len; 2311 | } 2312 | } 2313 | stop = 1; 2314 | break; 2315 | } 2316 | } 2317 | } 2318 | bestlineFreeCompletions(&lc); 2319 | return nread; 2320 | } 2321 | 2322 | static void bestlineEditHistoryGoto(struct bestlineState *l, unsigned i) { 2323 | size_t n; 2324 | if (historylen <= 1) 2325 | return; 2326 | if (i > historylen - 1) 2327 | return; 2328 | i = Max(Min(i, historylen - 1), 0); 2329 | free(history[historylen - 1 - l->hindex]); 2330 | history[historylen - 1 - l->hindex] = strdup(l->buf); 2331 | l->hindex = i; 2332 | n = strlen(history[historylen - 1 - l->hindex]); 2333 | bestlineGrow(l, n + 1); 2334 | n = Min(n, l->buflen - 1); 2335 | memcpy(l->buf, history[historylen - 1 - l->hindex], n); 2336 | l->buf[n] = 0; 2337 | l->len = l->pos = n; 2338 | bestlineRefreshLine(l); 2339 | } 2340 | 2341 | static void bestlineEditHistoryMove(struct bestlineState *l, int dx) { 2342 | bestlineEditHistoryGoto(l, l->hindex + dx); 2343 | } 2344 | 2345 | static char *bestlineMakeSearchPrompt(struct abuf *ab, int fail, const char *s, int n) { 2346 | ab->len = 0; 2347 | abAppendw(ab, '('); 2348 | if (fail) 2349 | abAppends(ab, "failed "); 2350 | abAppends(ab, "reverse-i-search `\033[4m"); 2351 | abAppend(ab, s, n); 2352 | abAppends(ab, "\033[24m"); 2353 | abAppends(ab, s + n); 2354 | abAppendw(ab, Read32le("') ")); 2355 | return ab->b; 2356 | } 2357 | 2358 | static int bestlineSearch(struct bestlineState *l, char *seq, int size) { 2359 | char *p; 2360 | char isstale; 2361 | struct abuf ab; 2362 | struct abuf prompt; 2363 | unsigned i, j, k, matlen; 2364 | const char *oldprompt, *q; 2365 | int rc, fail, added, oldpos, oldindex; 2366 | if (historylen <= 1) 2367 | return 0; 2368 | abInit(&ab); 2369 | abInit(&prompt); 2370 | oldpos = l->pos; 2371 | oldprompt = l->prompt; 2372 | oldindex = l->hindex; 2373 | for (fail = matlen = 0;;) { 2374 | l->prompt = bestlineMakeSearchPrompt(&prompt, fail, ab.b, matlen); 2375 | bestlineRefreshLine(l); 2376 | fail = 1; 2377 | added = 0; 2378 | j = l->pos; 2379 | i = l->hindex; 2380 | rc = bestlineRead(l->ifd, seq, size, l); 2381 | if (rc > 0) { 2382 | if (seq[0] == Ctrl('?') || seq[0] == Ctrl('H')) { 2383 | if (ab.len) { 2384 | --ab.len; 2385 | matlen = Min(matlen, ab.len); 2386 | } 2387 | } else if (seq[0] == Ctrl('R')) { 2388 | if (j) { 2389 | --j; 2390 | } else if (i + 1 < historylen) { 2391 | ++i; 2392 | j = strlen(history[historylen - 1 - i]); 2393 | } 2394 | } else if (seq[0] == Ctrl('G')) { 2395 | bestlineEditHistoryGoto(l, oldindex); 2396 | l->pos = oldpos; 2397 | rc = 0; 2398 | break; 2399 | } else if (IsControl(seq[0])) { /* only sees canonical c0 */ 2400 | break; 2401 | } else { 2402 | abAppend(&ab, seq, rc); 2403 | added = rc; 2404 | } 2405 | } else { 2406 | break; 2407 | } 2408 | isstale = 0; 2409 | while (i < historylen) { 2410 | p = history[historylen - 1 - i]; 2411 | k = strlen(p); 2412 | if (!isstale) { 2413 | j = Min(k, j + ab.len); 2414 | } else { 2415 | isstale = 0; 2416 | j = k; 2417 | } 2418 | if ((q = FindSubstringReverse(p, j, ab.b, ab.len))) { 2419 | bestlineEditHistoryGoto(l, i); 2420 | l->pos = q - p; 2421 | fail = 0; 2422 | if (added) { 2423 | matlen += added; 2424 | added = 0; 2425 | } 2426 | break; 2427 | } else { 2428 | isstale = 1; 2429 | ++i; 2430 | } 2431 | } 2432 | } 2433 | l->prompt = oldprompt; 2434 | bestlineRefreshLine(l); 2435 | abFree(&prompt); 2436 | abFree(&ab); 2437 | bestlineRefreshLine(l); 2438 | return rc; 2439 | } 2440 | 2441 | static void bestlineRingFree(void) { 2442 | size_t i; 2443 | for (i = 0; i < BESTLINE_MAX_RING; ++i) { 2444 | if (ring.p[i]) { 2445 | free(ring.p[i]); 2446 | ring.p[i] = 0; 2447 | } 2448 | } 2449 | } 2450 | 2451 | static void bestlineRingPush(const char *p, size_t n) { 2452 | char *q; 2453 | if (!n) 2454 | return; 2455 | if (!(q = (char *)malloc(n + 1))) 2456 | return; 2457 | ring.i = (ring.i + 1) % BESTLINE_MAX_RING; 2458 | free(ring.p[ring.i]); 2459 | ring.p[ring.i] = (char *)memcpy(q, p, n); 2460 | ring.p[ring.i][n] = 0; 2461 | } 2462 | 2463 | static void bestlineRingRotate(void) { 2464 | size_t i; 2465 | for (i = 0; i < BESTLINE_MAX_RING; ++i) { 2466 | ring.i = (ring.i - 1) % BESTLINE_MAX_RING; 2467 | if (ring.p[ring.i]) 2468 | break; 2469 | } 2470 | } 2471 | 2472 | static char *bestlineRefreshHints(struct bestlineState *l) { 2473 | char *hint; 2474 | struct abuf ab; 2475 | const char *ansi1 = "\033[90m", *ansi2 = "\033[39m"; 2476 | if (!hintsCallback) 2477 | return 0; 2478 | if (!(hint = hintsCallback(l->buf, &ansi1, &ansi2))) 2479 | return 0; 2480 | abInit(&ab); 2481 | if (ansi1) 2482 | abAppends(&ab, ansi1); 2483 | abAppends(&ab, hint); 2484 | if (ansi2) 2485 | abAppends(&ab, ansi2); 2486 | if (freeHintsCallback) 2487 | freeHintsCallback(hint); 2488 | return ab.b; 2489 | } 2490 | 2491 | static size_t Backward(struct bestlineState *l, size_t pos) { 2492 | if (pos) { 2493 | do 2494 | --pos; 2495 | while (pos && (l->buf[pos] & 0300) == 0200); 2496 | } 2497 | return pos; 2498 | } 2499 | 2500 | static int bestlineEditMirrorLeft(struct bestlineState *l, int res[2]) { 2501 | unsigned c, pos, left, right, depth, index; 2502 | if ((pos = Backward(l, l->pos))) { 2503 | right = GetUtf8(l->buf + pos, l->len - pos).c; 2504 | if ((left = bestlineMirrorLeft(right))) { 2505 | depth = 0; 2506 | index = pos; 2507 | do { 2508 | pos = Backward(l, pos); 2509 | c = GetUtf8(l->buf + pos, l->len - pos).c; 2510 | if (c == right) { 2511 | ++depth; 2512 | } else if (c == left) { 2513 | if (depth) { 2514 | --depth; 2515 | } else { 2516 | res[0] = pos; 2517 | res[1] = index; 2518 | return 0; 2519 | } 2520 | } 2521 | } while (pos); 2522 | } 2523 | } 2524 | return -1; 2525 | } 2526 | 2527 | static int bestlineEditMirrorRight(struct bestlineState *l, int res[2]) { 2528 | struct rune rune; 2529 | unsigned pos, left, right, depth, index; 2530 | pos = l->pos; 2531 | rune = GetUtf8(l->buf + pos, l->len - pos); 2532 | left = rune.c; 2533 | if ((right = bestlineMirrorRight(left))) { 2534 | depth = 0; 2535 | index = pos; 2536 | do { 2537 | pos += rune.n; 2538 | rune = GetUtf8(l->buf + pos, l->len - pos); 2539 | if (rune.c == left) { 2540 | ++depth; 2541 | } else if (rune.c == right) { 2542 | if (depth) { 2543 | --depth; 2544 | } else { 2545 | res[0] = index; 2546 | res[1] = pos; 2547 | return 0; 2548 | } 2549 | } 2550 | } while (pos + rune.n < l->len); 2551 | } 2552 | return -1; 2553 | } 2554 | 2555 | static int bestlineEditMirror(struct bestlineState *l, int res[2]) { 2556 | int rc; 2557 | rc = bestlineEditMirrorLeft(l, res); 2558 | if (rc == -1) 2559 | rc = bestlineEditMirrorRight(l, res); 2560 | return rc; 2561 | } 2562 | 2563 | static void bestlineRefreshLineImpl(struct bestlineState *l, int force) { 2564 | char *hint; 2565 | char flipit; 2566 | char hasflip; 2567 | char haswides; 2568 | struct abuf ab; 2569 | const char *buf; 2570 | struct rune rune; 2571 | struct winsize oldsize; 2572 | int fd, plen, rows, len, pos; 2573 | unsigned x, xn, yn, width, pwidth; 2574 | int i, t, cx, cy, tn, resized, flip[2]; 2575 | 2576 | /* 2577 | * synchonize the i/o state 2578 | */ 2579 | if (ispaused) { 2580 | if (force) { 2581 | bestlineUnpause(l->ofd); 2582 | } else { 2583 | return; 2584 | } 2585 | } 2586 | if (!force && HasPendingInput(l->ifd)) { 2587 | l->dirty = 1; 2588 | return; 2589 | } 2590 | oldsize = l->ws; 2591 | if ((resized = gotwinch) && rawmode != -1) { 2592 | gotwinch = 0; 2593 | l->ws = GetTerminalSize(l->ws, l->ifd, l->ofd); 2594 | } 2595 | hasflip = !l->final && !bestlineEditMirror(l, flip); 2596 | 2597 | StartOver: 2598 | fd = l->ofd; 2599 | buf = l->buf; 2600 | pos = l->pos; 2601 | len = l->len; 2602 | xn = l->ws.ws_col; 2603 | yn = l->ws.ws_row; 2604 | plen = strlen(l->prompt); 2605 | pwidth = GetMonospaceWidth(l->prompt, plen, 0); 2606 | width = GetMonospaceWidth(buf, len, &haswides); 2607 | 2608 | /* 2609 | * handle the case where the line is larger than the whole display 2610 | * gnu readline actually isn't able to deal with this situation!!! 2611 | * we kludge xn to address the edge case of wide chars on the edge 2612 | */ 2613 | for (tn = xn - haswides * 2;;) { 2614 | if (pwidth + width + 1 < tn * yn) 2615 | break; /* we're fine */ 2616 | if (!len || width < 2) 2617 | break; /* we can't do anything */ 2618 | if (pwidth + 2 > tn * yn) 2619 | break; /* we can't do anything */ 2620 | if (pos > len / 2) { 2621 | /* hide content on the left if we're editing on the right */ 2622 | rune = GetUtf8(buf, len); 2623 | buf += rune.n; 2624 | len -= rune.n; 2625 | pos -= rune.n; 2626 | } else { 2627 | /* hide content on the right if we're editing on left */ 2628 | t = len; 2629 | while (len && (buf[len - 1] & 0300) == 0200) 2630 | --len; 2631 | if (len) 2632 | --len; 2633 | rune = GetUtf8(buf + len, t - len); 2634 | } 2635 | if ((t = bestlineCharacterWidth(rune.c)) > 0) { 2636 | width -= t; 2637 | } 2638 | } 2639 | pos = Max(0, Min(pos, len)); 2640 | 2641 | /* 2642 | * now generate the terminal codes to update the line 2643 | * 2644 | * since we support unlimited lines it's important that we don't 2645 | * clear the screen before we draw the screen. doing that causes 2646 | * flickering. the key with terminals is to overwrite cells, and 2647 | * then use \e[K and \e[J to clear everything else. 2648 | * 2649 | * we make the assumption that prompts and hints may contain ansi 2650 | * sequences, but the buffer does not. 2651 | * 2652 | * we need to handle the edge case where a wide character like 度 2653 | * might be at the edge of the window, when there's one cell left. 2654 | * so we can't use division based on string width to compute the 2655 | * coordinates and have to track it as we go. 2656 | */ 2657 | cy = -1; 2658 | cx = -1; 2659 | rows = 1; 2660 | abInit(&ab); 2661 | abAppendw(&ab, '\r'); /* start of line */ 2662 | if (l->rows - l->oldpos - 1 > 0) { 2663 | abAppends(&ab, "\033["); 2664 | abAppendu(&ab, l->rows - l->oldpos - 1); 2665 | abAppendw(&ab, 'A'); /* cursor up clamped */ 2666 | } 2667 | abAppends(&ab, l->prompt); 2668 | x = pwidth; 2669 | for (i = 0; i < len; i += rune.n) { 2670 | rune = GetUtf8(buf + i, len - i); 2671 | if (x && x + rune.n > xn) { 2672 | if (cy >= 0) 2673 | ++cy; 2674 | if (x < xn) { 2675 | abAppends(&ab, "\033[K"); /* clear line forward */ 2676 | } 2677 | abAppends(&ab, "\r" /* start of line */ 2678 | "\n"); /* cursor down unclamped */ 2679 | ++rows; 2680 | x = 0; 2681 | } 2682 | if (i == pos) { 2683 | cy = 0; 2684 | cx = x; 2685 | } 2686 | if (maskmode) { 2687 | abAppendw(&ab, '*'); 2688 | } else { 2689 | flipit = hasflip && (i == flip[0] || i == flip[1]); 2690 | if (flipit) 2691 | abAppends(&ab, "\033[1m"); 2692 | abAppendw(&ab, EncodeUtf8(rune.c)); 2693 | if (flipit) 2694 | abAppends(&ab, "\033[22m"); 2695 | } 2696 | t = bestlineCharacterWidth(rune.c); 2697 | t = Max(0, t); 2698 | x += t; 2699 | } 2700 | if (!l->final && (hint = bestlineRefreshHints(l))) { 2701 | if (GetMonospaceWidth(hint, strlen(hint), 0) < xn - x) { 2702 | if (cx < 0) { 2703 | cx = x; 2704 | } 2705 | abAppends(&ab, hint); 2706 | } 2707 | free(hint); 2708 | } 2709 | abAppendw(&ab, Read32le("\033[J")); /* erase display forwards */ 2710 | 2711 | /* 2712 | * if we are at the very end of the screen with our prompt, we need 2713 | * to emit a newline and move the prompt to the first column. 2714 | */ 2715 | if (pos && pos == len && x >= xn) { 2716 | abAppendw(&ab, Read32le("\n\r\0")); 2717 | ++rows; 2718 | } 2719 | 2720 | /* 2721 | * move cursor to right position 2722 | */ 2723 | if (cy > 0) { 2724 | abAppends(&ab, "\033["); 2725 | abAppendu(&ab, cy); 2726 | abAppendw(&ab, 'A'); /* cursor up */ 2727 | } 2728 | if (cx > 0) { 2729 | abAppendw(&ab, Read32le("\r\033[")); 2730 | abAppendu(&ab, cx); 2731 | abAppendw(&ab, 'C'); /* cursor right */ 2732 | } else if (!cx) { 2733 | abAppendw(&ab, '\r'); /* start */ 2734 | } 2735 | 2736 | /* 2737 | * now get ready to progress state 2738 | * we use a mostly correct kludge when the tty resizes 2739 | */ 2740 | l->rows = rows; 2741 | if (resized && oldsize.ws_col > l->ws.ws_col) { 2742 | resized = 0; 2743 | abFree(&ab); 2744 | goto StartOver; 2745 | } 2746 | l->dirty = 0; 2747 | l->oldpos = Max(0, cy); 2748 | 2749 | /* 2750 | * send codes to terminal 2751 | */ 2752 | bestlineWrite(fd, ab.b, ab.len); 2753 | abFree(&ab); 2754 | } 2755 | 2756 | static void bestlineRefreshLine(struct bestlineState *l) { 2757 | bestlineRefreshLineImpl(l, 0); 2758 | } 2759 | 2760 | static void bestlineRefreshLineForce(struct bestlineState *l) { 2761 | bestlineRefreshLineImpl(l, 1); 2762 | } 2763 | 2764 | static void bestlineEditInsert(struct bestlineState *l, const char *p, size_t n) { 2765 | if (!bestlineGrow(l, l->len + n + 1)) 2766 | return; 2767 | memmove(l->buf + l->pos + n, l->buf + l->pos, l->len - l->pos); 2768 | memcpy(l->buf + l->pos, p, n); 2769 | l->pos += n; 2770 | l->len += n; 2771 | l->buf[l->len] = 0; 2772 | bestlineRefreshLine(l); 2773 | } 2774 | 2775 | static void bestlineEditHome(struct bestlineState *l) { 2776 | l->pos = 0; 2777 | bestlineRefreshLine(l); 2778 | } 2779 | 2780 | static void bestlineEditEnd(struct bestlineState *l) { 2781 | l->pos = l->len; 2782 | bestlineRefreshLine(l); 2783 | } 2784 | 2785 | static void bestlineEditUp(struct bestlineState *l) { 2786 | bestlineEditHistoryMove(l, BESTLINE_HISTORY_PREV); 2787 | } 2788 | 2789 | static void bestlineEditDown(struct bestlineState *l) { 2790 | bestlineEditHistoryMove(l, BESTLINE_HISTORY_NEXT); 2791 | } 2792 | 2793 | static void bestlineEditBof(struct bestlineState *l) { 2794 | bestlineEditHistoryGoto(l, historylen - 1); 2795 | } 2796 | 2797 | static void bestlineEditEof(struct bestlineState *l) { 2798 | bestlineEditHistoryGoto(l, 0); 2799 | } 2800 | 2801 | static void bestlineEditRefresh(struct bestlineState *l) { 2802 | bestlineClearScreen(l->ofd); 2803 | bestlineRefreshLine(l); 2804 | } 2805 | 2806 | static size_t Forward(struct bestlineState *l, size_t pos) { 2807 | return pos + GetUtf8(l->buf + pos, l->len - pos).n; 2808 | } 2809 | 2810 | static size_t Backwards(struct bestlineState *l, size_t pos, char pred(unsigned)) { 2811 | size_t i; 2812 | struct rune r; 2813 | while (pos) { 2814 | i = Backward(l, pos); 2815 | r = GetUtf8(l->buf + i, l->len - i); 2816 | if (pred(r.c)) { 2817 | pos = i; 2818 | } else { 2819 | break; 2820 | } 2821 | } 2822 | return pos; 2823 | } 2824 | 2825 | static size_t Forwards(struct bestlineState *l, size_t pos, char pred(unsigned)) { 2826 | struct rune r; 2827 | while (pos < l->len) { 2828 | r = GetUtf8(l->buf + pos, l->len - pos); 2829 | if (pred(r.c)) { 2830 | pos += r.n; 2831 | } else { 2832 | break; 2833 | } 2834 | } 2835 | return pos; 2836 | } 2837 | 2838 | static size_t ForwardWord(struct bestlineState *l, size_t pos) { 2839 | pos = Forwards(l, pos, bestlineIsSeparator); 2840 | pos = Forwards(l, pos, bestlineNotSeparator); 2841 | return pos; 2842 | } 2843 | 2844 | static size_t BackwardWord(struct bestlineState *l, size_t pos) { 2845 | pos = Backwards(l, pos, bestlineIsSeparator); 2846 | pos = Backwards(l, pos, bestlineNotSeparator); 2847 | return pos; 2848 | } 2849 | 2850 | static size_t EscapeWord(struct bestlineState *l, size_t i) { 2851 | size_t j; 2852 | struct rune r; 2853 | for (; i && i < l->len; i += r.n) { 2854 | if (i < l->len) { 2855 | r = GetUtf8(l->buf + i, l->len - i); 2856 | if (bestlineIsSeparator(r.c)) 2857 | break; 2858 | } 2859 | if ((j = i)) { 2860 | do 2861 | --j; 2862 | while (j && (l->buf[j] & 0300) == 0200); 2863 | r = GetUtf8(l->buf + j, l->len - j); 2864 | if (bestlineIsSeparator(r.c)) 2865 | break; 2866 | } 2867 | } 2868 | return i; 2869 | } 2870 | 2871 | static void bestlineEditLeft(struct bestlineState *l) { 2872 | l->pos = Backward(l, l->pos); 2873 | bestlineRefreshLine(l); 2874 | } 2875 | 2876 | static void bestlineEditRight(struct bestlineState *l) { 2877 | if (l->pos == l->len) 2878 | return; 2879 | do 2880 | l->pos++; 2881 | while (l->pos < l->len && (l->buf[l->pos] & 0300) == 0200); 2882 | bestlineRefreshLine(l); 2883 | } 2884 | 2885 | static void bestlineEditLeftWord(struct bestlineState *l) { 2886 | l->pos = BackwardWord(l, l->pos); 2887 | bestlineRefreshLine(l); 2888 | } 2889 | 2890 | static void bestlineEditRightWord(struct bestlineState *l) { 2891 | l->pos = ForwardWord(l, l->pos); 2892 | bestlineRefreshLine(l); 2893 | } 2894 | 2895 | static void bestlineEditLeftExpr(struct bestlineState *l) { 2896 | int mark[2]; 2897 | l->pos = Backwards(l, l->pos, bestlineIsXeparator); 2898 | if (!bestlineEditMirrorLeft(l, mark)) { 2899 | l->pos = mark[0]; 2900 | } else { 2901 | l->pos = Backwards(l, l->pos, bestlineNotSeparator); 2902 | } 2903 | bestlineRefreshLine(l); 2904 | } 2905 | 2906 | static void bestlineEditRightExpr(struct bestlineState *l) { 2907 | int mark[2]; 2908 | l->pos = Forwards(l, l->pos, bestlineIsXeparator); 2909 | if (!bestlineEditMirrorRight(l, mark)) { 2910 | l->pos = Forward(l, mark[1]); 2911 | } else { 2912 | l->pos = Forwards(l, l->pos, bestlineNotSeparator); 2913 | } 2914 | bestlineRefreshLine(l); 2915 | } 2916 | 2917 | static void bestlineEditDelete(struct bestlineState *l) { 2918 | size_t i; 2919 | if (l->pos == l->len) 2920 | return; 2921 | i = Forward(l, l->pos); 2922 | memmove(l->buf + l->pos, l->buf + i, l->len - i + 1); 2923 | l->len -= i - l->pos; 2924 | bestlineRefreshLine(l); 2925 | } 2926 | 2927 | static void bestlineEditRubout(struct bestlineState *l) { 2928 | size_t i; 2929 | if (!l->pos) 2930 | return; 2931 | i = Backward(l, l->pos); 2932 | memmove(l->buf + i, l->buf + l->pos, l->len - l->pos + 1); 2933 | l->len -= l->pos - i; 2934 | l->pos = i; 2935 | bestlineRefreshLine(l); 2936 | } 2937 | 2938 | static void bestlineEditDeleteWord(struct bestlineState *l) { 2939 | size_t i; 2940 | if (l->pos == l->len) 2941 | return; 2942 | i = ForwardWord(l, l->pos); 2943 | bestlineRingPush(l->buf + l->pos, i - l->pos); 2944 | memmove(l->buf + l->pos, l->buf + i, l->len - i + 1); 2945 | l->len -= i - l->pos; 2946 | bestlineRefreshLine(l); 2947 | } 2948 | 2949 | static void bestlineEditRuboutWord(struct bestlineState *l) { 2950 | size_t i; 2951 | if (!l->pos) 2952 | return; 2953 | i = BackwardWord(l, l->pos); 2954 | bestlineRingPush(l->buf + i, l->pos - i); 2955 | memmove(l->buf + i, l->buf + l->pos, l->len - l->pos + 1); 2956 | l->len -= l->pos - i; 2957 | l->pos = i; 2958 | bestlineRefreshLine(l); 2959 | } 2960 | 2961 | static void bestlineEditXlatWord(struct bestlineState *l, unsigned xlat(unsigned)) { 2962 | unsigned c; 2963 | size_t i, j; 2964 | struct rune r; 2965 | struct abuf ab; 2966 | abInit(&ab); 2967 | i = Forwards(l, l->pos, bestlineIsSeparator); 2968 | for (j = i; j < l->len; j += r.n) { 2969 | r = GetUtf8(l->buf + j, l->len - j); 2970 | if (bestlineIsSeparator(r.c)) 2971 | break; 2972 | if ((c = xlat(r.c)) != r.c) { 2973 | abAppendw(&ab, EncodeUtf8(c)); 2974 | } else { /* avoid canonicalization */ 2975 | abAppend(&ab, l->buf + j, r.n); 2976 | } 2977 | } 2978 | if (ab.len && bestlineGrow(l, i + ab.len + l->len - j + 1)) { 2979 | l->pos = i + ab.len; 2980 | abAppend(&ab, l->buf + j, l->len - j); 2981 | l->len = i + ab.len; 2982 | memcpy(l->buf + i, ab.b, ab.len + 1); 2983 | bestlineRefreshLine(l); 2984 | } 2985 | abFree(&ab); 2986 | } 2987 | 2988 | static void bestlineEditLowercaseWord(struct bestlineState *l) { 2989 | bestlineEditXlatWord(l, bestlineLowercase); 2990 | } 2991 | 2992 | static void bestlineEditUppercaseWord(struct bestlineState *l) { 2993 | bestlineEditXlatWord(l, bestlineUppercase); 2994 | } 2995 | 2996 | static void bestlineEditCapitalizeWord(struct bestlineState *l) { 2997 | iscapital = 0; 2998 | bestlineEditXlatWord(l, Capitalize); 2999 | } 3000 | 3001 | static void bestlineEditKillLeft(struct bestlineState *l) { 3002 | size_t diff, old_pos; 3003 | bestlineRingPush(l->buf, l->pos); 3004 | old_pos = l->pos; 3005 | l->pos = 0; 3006 | diff = old_pos - l->pos; 3007 | memmove(l->buf + l->pos, l->buf + old_pos, l->len - old_pos + 1); 3008 | l->len -= diff; 3009 | bestlineRefreshLine(l); 3010 | } 3011 | 3012 | static void bestlineEditKillRight(struct bestlineState *l) { 3013 | bestlineRingPush(l->buf + l->pos, l->len - l->pos); 3014 | l->buf[l->pos] = '\0'; 3015 | l->len = l->pos; 3016 | bestlineRefreshLine(l); 3017 | } 3018 | 3019 | static void bestlineEditYank(struct bestlineState *l) { 3020 | char *p; 3021 | size_t n; 3022 | if (!ring.p[ring.i]) 3023 | return; 3024 | n = strlen(ring.p[ring.i]); 3025 | if (!bestlineGrow(l, l->len + n + 1)) 3026 | return; 3027 | if (!(p = (char *)malloc(l->len - l->pos + 1))) 3028 | return; 3029 | memcpy(p, l->buf + l->pos, l->len - l->pos + 1); 3030 | memcpy(l->buf + l->pos, ring.p[ring.i], n); 3031 | memcpy(l->buf + l->pos + n, p, l->len - l->pos + 1); 3032 | free(p); 3033 | l->yi = l->pos; 3034 | l->yj = l->pos + n; 3035 | l->pos += n; 3036 | l->len += n; 3037 | bestlineRefreshLine(l); 3038 | } 3039 | 3040 | static void bestlineEditRotate(struct bestlineState *l) { 3041 | if ((l->seq[1][0] == Ctrl('Y') || (l->seq[1][0] == 033 && l->seq[1][1] == 'y'))) { 3042 | if (l->yi < l->len && l->yj <= l->len) { 3043 | memmove(l->buf + l->yi, l->buf + l->yj, l->len - l->yj + 1); 3044 | l->len -= l->yj - l->yi; 3045 | l->pos -= l->yj - l->yi; 3046 | } 3047 | bestlineRingRotate(); 3048 | bestlineEditYank(l); 3049 | } 3050 | } 3051 | 3052 | static void bestlineEditTranspose(struct bestlineState *l) { 3053 | char *q, *p; 3054 | size_t a, b, c; 3055 | b = l->pos; 3056 | if (b == l->len) 3057 | --b; 3058 | a = Backward(l, b); 3059 | c = Forward(l, b); 3060 | if (!(a < b && b < c)) 3061 | return; 3062 | p = q = (char *)malloc(c - a); 3063 | p = Copy(p, l->buf + b, c - b); 3064 | p = Copy(p, l->buf + a, b - a); 3065 | assert((size_t)(p - q) == c - a); 3066 | memcpy(l->buf + a, q, p - q); 3067 | l->pos = c; 3068 | free(q); 3069 | bestlineRefreshLine(l); 3070 | } 3071 | 3072 | static void bestlineEditTransposeWords(struct bestlineState *l) { 3073 | char *q, *p; 3074 | size_t i, pi, xi, xj, yi, yj; 3075 | i = l->pos; 3076 | if (i == l->len) { 3077 | i = Backwards(l, i, bestlineIsSeparator); 3078 | i = Backwards(l, i, bestlineNotSeparator); 3079 | } 3080 | pi = EscapeWord(l, i); 3081 | xj = Backwards(l, pi, bestlineIsSeparator); 3082 | xi = Backwards(l, xj, bestlineNotSeparator); 3083 | yi = Forwards(l, pi, bestlineIsSeparator); 3084 | yj = Forwards(l, yi, bestlineNotSeparator); 3085 | if (!(xi < xj && xj < yi && yi < yj)) 3086 | return; 3087 | p = q = (char *)malloc(yj - xi); 3088 | p = Copy(p, l->buf + yi, yj - yi); 3089 | p = Copy(p, l->buf + xj, yi - xj); 3090 | p = Copy(p, l->buf + xi, xj - xi); 3091 | assert((size_t)(p - q) == yj - xi); 3092 | memcpy(l->buf + xi, q, p - q); 3093 | l->pos = yj; 3094 | free(q); 3095 | bestlineRefreshLine(l); 3096 | } 3097 | 3098 | static void bestlineEditSqueeze(struct bestlineState *l) { 3099 | size_t i, j; 3100 | i = Backwards(l, l->pos, bestlineIsSeparator); 3101 | j = Forwards(l, l->pos, bestlineIsSeparator); 3102 | if (!(i < j)) 3103 | return; 3104 | memmove(l->buf + i, l->buf + j, l->len - j + 1); 3105 | l->len -= j - i; 3106 | l->pos = i; 3107 | bestlineRefreshLine(l); 3108 | } 3109 | 3110 | static void bestlineEditMark(struct bestlineState *l) { 3111 | l->mark = l->pos; 3112 | } 3113 | 3114 | static void bestlineEditGoto(struct bestlineState *l) { 3115 | if (l->mark > l->len) 3116 | return; 3117 | l->pos = Min(l->mark, l->len); 3118 | bestlineRefreshLine(l); 3119 | } 3120 | 3121 | static size_t bestlineEscape(char *d, const char *s, size_t n) { 3122 | char *p; 3123 | size_t i; 3124 | unsigned c, w, l; 3125 | for (p = d, l = i = 0; i < n; ++i) { 3126 | switch ((c = s[i] & 255)) { 3127 | Case('\a', w = Read16le("\\a")); 3128 | Case('\b', w = Read16le("\\b")); 3129 | Case('\t', w = Read16le("\\t")); 3130 | Case('\n', w = Read16le("\\n")); 3131 | Case('\v', w = Read16le("\\v")); 3132 | Case('\f', w = Read16le("\\f")); 3133 | Case('\r', w = Read16le("\\r")); 3134 | Case('"', w = Read16le("\\\"")); 3135 | Case('\'', w = Read16le("\\\'")); 3136 | Case('\\', w = Read16le("\\\\")); 3137 | default: 3138 | if (c <= 0x1F || c == 0x7F || (c == '?' && l == '?')) { 3139 | w = Read16le("\\x"); 3140 | w |= "0123456789abcdef"[(c & 0xF0) >> 4] << 020; 3141 | w |= "0123456789abcdef"[(c & 0x0F) >> 0] << 030; 3142 | } else { 3143 | w = c; 3144 | } 3145 | break; 3146 | } 3147 | p[0] = (w & 0x000000ff) >> 000; 3148 | p[1] = (w & 0x0000ff00) >> 010; 3149 | p[2] = (w & 0x00ff0000) >> 020; 3150 | p[3] = (w & 0xff000000) >> 030; 3151 | p += (Bsr(w) >> 3) + 1; 3152 | l = w; 3153 | } 3154 | return p - d; 3155 | } 3156 | 3157 | static void bestlineEditInsertEscape(struct bestlineState *l) { 3158 | size_t m; 3159 | ssize_t n; 3160 | char seq[16]; 3161 | char esc[sizeof(seq) * 4]; 3162 | if ((n = bestlineRead(l->ifd, seq, sizeof(seq), l)) > 0) { 3163 | m = bestlineEscape(esc, seq, n); 3164 | bestlineEditInsert(l, esc, m); 3165 | } 3166 | } 3167 | 3168 | static void bestlineEditInterrupt(void) { 3169 | gotint = SIGINT; 3170 | } 3171 | 3172 | static void bestlineEditQuit(void) { 3173 | gotint = SIGQUIT; 3174 | } 3175 | 3176 | static void bestlineEditSuspend(void) { 3177 | raise(SIGSTOP); 3178 | } 3179 | 3180 | static void bestlineEditPause(struct bestlineState *l) { 3181 | tcflow(l->ofd, TCOOFF); 3182 | ispaused = 1; 3183 | } 3184 | 3185 | static void bestlineEditCtrlq(struct bestlineState *l) { 3186 | if (ispaused) { 3187 | bestlineUnpause(l->ofd); 3188 | bestlineRefreshLineForce(l); 3189 | } else { 3190 | bestlineEditInsertEscape(l); 3191 | } 3192 | } 3193 | 3194 | /** 3195 | * Moves last item inside current s-expression to outside, e.g. 3196 | * 3197 | * (a| b c) 3198 | * (a| b) c 3199 | * 3200 | * The cursor position changes only if a paren is moved before it: 3201 | * 3202 | * (a b c |) 3203 | * (a b) c | 3204 | * 3205 | * To accommodate non-LISP languages we connect unspaced outer symbols: 3206 | * 3207 | * f(a,| b, g()) 3208 | * f(a,| b), g() 3209 | * 3210 | * Our standard keybinding is ALT-SHIFT-B. 3211 | */ 3212 | static void bestlineEditBarf(struct bestlineState *l) { 3213 | struct rune r; 3214 | unsigned long w; 3215 | size_t i, pos, depth = 0; 3216 | unsigned lhs, rhs, end, *stack = 0; 3217 | /* go as far right within current s-expr as possible */ 3218 | for (pos = l->pos;; pos += r.n) { 3219 | if (pos == l->len) 3220 | goto Finish; 3221 | r = GetUtf8(l->buf + pos, l->len - pos); 3222 | if (depth) { 3223 | if (r.c == stack[depth - 1]) { 3224 | --depth; 3225 | } 3226 | } else { 3227 | if ((rhs = bestlineMirrorRight(r.c))) { 3228 | stack = (unsigned *)realloc(stack, ++depth * sizeof(*stack)); 3229 | stack[depth - 1] = rhs; 3230 | } else if (bestlineMirrorLeft(r.c)) { 3231 | end = pos; 3232 | break; 3233 | } 3234 | } 3235 | } 3236 | /* go back one item */ 3237 | pos = Backwards(l, pos, bestlineIsXeparator); 3238 | for (;; pos = i) { 3239 | if (!pos) 3240 | goto Finish; 3241 | i = Backward(l, pos); 3242 | r = GetUtf8(l->buf + i, l->len - i); 3243 | if (depth) { 3244 | if (r.c == stack[depth - 1]) { 3245 | --depth; 3246 | } 3247 | } else { 3248 | if ((lhs = bestlineMirrorLeft(r.c))) { 3249 | stack = (unsigned *)realloc(stack, ++depth * sizeof(*stack)); 3250 | stack[depth - 1] = lhs; 3251 | } else if (bestlineIsSeparator(r.c)) { 3252 | break; 3253 | } 3254 | } 3255 | } 3256 | pos = Backwards(l, pos, bestlineIsXeparator); 3257 | /* now move the text */ 3258 | r = GetUtf8(l->buf + end, l->len - end); 3259 | memmove(l->buf + pos + r.n, l->buf + pos, end - pos); 3260 | w = EncodeUtf8(r.c); 3261 | for (i = 0; i < r.n; ++i) { 3262 | l->buf[pos + i] = w; 3263 | w >>= 8; 3264 | } 3265 | if (l->pos > pos) { 3266 | l->pos += r.n; 3267 | } 3268 | bestlineRefreshLine(l); 3269 | Finish: 3270 | free(stack); 3271 | } 3272 | 3273 | /** 3274 | * Moves first item outside current s-expression to inside, e.g. 3275 | * 3276 | * (a| b) c d 3277 | * (a| b c) d 3278 | * 3279 | * To accommodate non-LISP languages we connect unspaced outer symbols: 3280 | * 3281 | * f(a,| b), g() 3282 | * f(a,| b, g()) 3283 | * 3284 | * Our standard keybinding is ALT-SHIFT-S. 3285 | */ 3286 | static void bestlineEditSlurp(struct bestlineState *l) { 3287 | char rp[6]; 3288 | struct rune r; 3289 | size_t pos, depth = 0; 3290 | unsigned rhs, point = 0, start = 0, *stack = 0; 3291 | /* go to outside edge of current s-expr */ 3292 | for (pos = l->pos; pos < l->len; pos += r.n) { 3293 | r = GetUtf8(l->buf + pos, l->len - pos); 3294 | if (depth) { 3295 | if (r.c == stack[depth - 1]) { 3296 | --depth; 3297 | } 3298 | } else { 3299 | if ((rhs = bestlineMirrorRight(r.c))) { 3300 | stack = (unsigned *)realloc(stack, ++depth * sizeof(*stack)); 3301 | stack[depth - 1] = rhs; 3302 | } else if (bestlineMirrorLeft(r.c)) { 3303 | point = pos; 3304 | pos += r.n; 3305 | start = pos; 3306 | break; 3307 | } 3308 | } 3309 | } 3310 | /* go forward one item */ 3311 | pos = Forwards(l, pos, bestlineIsXeparator); 3312 | for (; pos < l->len; pos += r.n) { 3313 | r = GetUtf8(l->buf + pos, l->len - pos); 3314 | if (depth) { 3315 | if (r.c == stack[depth - 1]) { 3316 | --depth; 3317 | } 3318 | } else { 3319 | if ((rhs = bestlineMirrorRight(r.c))) { 3320 | stack = (unsigned *)realloc(stack, ++depth * sizeof(*stack)); 3321 | stack[depth - 1] = rhs; 3322 | } else if (bestlineIsSeparator(r.c)) { 3323 | break; 3324 | } 3325 | } 3326 | } 3327 | /* now move the text */ 3328 | memcpy(rp, l->buf + point, start - point); 3329 | memmove(l->buf + point, l->buf + start, pos - start); 3330 | memcpy(l->buf + pos - (start - point), rp, start - point); 3331 | bestlineRefreshLine(l); 3332 | free(stack); 3333 | } 3334 | 3335 | static void bestlineEditRaise(struct bestlineState *l) { 3336 | (void)l; 3337 | } 3338 | 3339 | static char IsBalanced(struct abuf *buf) { 3340 | unsigned i, d; 3341 | for (d = i = 0; i < buf->len; ++i) { 3342 | if (buf->b[i] == '(') 3343 | ++d; 3344 | else if (d > 0 && buf->b[i] == ')') 3345 | --d; 3346 | } 3347 | return d == 0; 3348 | } 3349 | 3350 | /** 3351 | * Runs bestline engine. 3352 | * 3353 | * This function is the core of the line editing capability of bestline. 3354 | * It expects 'fd' to be already in "raw mode" so that every key pressed 3355 | * will be returned ASAP to read(). 3356 | * 3357 | * The resulting string is put into 'buf' when the user type enter, or 3358 | * when ctrl+d is typed. 3359 | * 3360 | * Returns chomped character count in buf >=0 or -1 on eof / error 3361 | */ 3362 | static ssize_t bestlineEdit(int stdin_fd, int stdout_fd, const char *prompt, const char *init, 3363 | char **obuf) { 3364 | ssize_t rc; 3365 | char seq[16]; 3366 | const char *promptnotnull, *promptlastnl; 3367 | size_t nread; 3368 | int pastemode; 3369 | struct rune rune; 3370 | unsigned long long w; 3371 | struct bestlineState l; 3372 | pastemode = 0; 3373 | memset(&l, 0, sizeof(l)); 3374 | if (!(l.buf = (char *)malloc((l.buflen = 32)))) 3375 | return -1; 3376 | l.buf[0] = 0; 3377 | l.ifd = stdin_fd; 3378 | l.ofd = stdout_fd; 3379 | promptnotnull = prompt ? prompt : ""; 3380 | promptlastnl = strrchr(promptnotnull, '\n'); 3381 | l.prompt = promptlastnl ? promptlastnl + 1 : promptnotnull; 3382 | l.ws = GetTerminalSize(l.ws, l.ifd, l.ofd); 3383 | abInit(&l.full); 3384 | bestlineHistoryAdd(""); 3385 | bestlineWriteStr(l.ofd, promptnotnull); 3386 | init = init ? init : ""; 3387 | bestlineEditInsert(&l, init, strlen(init)); 3388 | while (1) { 3389 | if (l.dirty) 3390 | bestlineRefreshLineForce(&l); 3391 | rc = bestlineRead(l.ifd, seq, sizeof(seq), &l); 3392 | if (rc > 0) { 3393 | if (seq[0] == Ctrl('R')) { 3394 | rc = bestlineSearch(&l, seq, sizeof(seq)); 3395 | if (!rc) 3396 | continue; 3397 | } else if (seq[0] == '\t' && completionCallback) { 3398 | rc = bestlineCompleteLine(&l, seq, sizeof(seq)); 3399 | if (!rc) 3400 | continue; 3401 | } 3402 | } 3403 | if (rc > 0) { 3404 | nread = rc; 3405 | } else if (!rc && l.len) { 3406 | nread = 1; 3407 | seq[0] = '\r'; 3408 | seq[1] = 0; 3409 | } else { 3410 | if (historylen) { 3411 | free(history[--historylen]); 3412 | history[historylen] = 0; 3413 | } 3414 | free(l.buf); 3415 | abFree(&l.full); 3416 | return -1; 3417 | } 3418 | switch (seq[0]) { 3419 | Case(Ctrl('P'), bestlineEditUp(&l)); 3420 | Case(Ctrl('E'), bestlineEditEnd(&l)); 3421 | Case(Ctrl('N'), bestlineEditDown(&l)); 3422 | Case(Ctrl('A'), bestlineEditHome(&l)); 3423 | Case(Ctrl('B'), bestlineEditLeft(&l)); 3424 | Case(Ctrl('@'), bestlineEditMark(&l)); 3425 | Case(Ctrl('Y'), bestlineEditYank(&l)); 3426 | Case(Ctrl('Q'), bestlineEditCtrlq(&l)); 3427 | Case(Ctrl('F'), bestlineEditRight(&l)); 3428 | Case(Ctrl('\\'), bestlineEditQuit()); 3429 | Case(Ctrl('S'), bestlineEditPause(&l)); 3430 | Case(Ctrl('?'), bestlineEditRubout(&l)); 3431 | Case(Ctrl('H'), bestlineEditRubout(&l)); 3432 | Case(Ctrl('L'), bestlineEditRefresh(&l)); 3433 | Case(Ctrl('Z'), bestlineEditSuspend()); 3434 | Case(Ctrl('U'), bestlineEditKillLeft(&l)); 3435 | Case(Ctrl('T'), bestlineEditTranspose(&l)); 3436 | Case(Ctrl('K'), bestlineEditKillRight(&l)); 3437 | Case(Ctrl('W'), bestlineEditRuboutWord(&l)); 3438 | case Ctrl('C'): 3439 | if (emacsmode) { 3440 | if (bestlineRead(l.ifd, seq, sizeof(seq), &l) != 1) 3441 | break; 3442 | switch (seq[0]) { 3443 | Case(Ctrl('C'), bestlineEditInterrupt()); 3444 | Case(Ctrl('B'), bestlineEditBarf(&l)); 3445 | Case(Ctrl('S'), bestlineEditSlurp(&l)); 3446 | Case(Ctrl('R'), bestlineEditRaise(&l)); 3447 | default: 3448 | break; 3449 | } 3450 | } else { 3451 | bestlineEditInterrupt(); 3452 | } 3453 | break; 3454 | case Ctrl('X'): 3455 | if (l.seq[1][0] == Ctrl('X')) { 3456 | bestlineEditGoto(&l); 3457 | } 3458 | break; 3459 | case Ctrl('D'): 3460 | if (l.len) { 3461 | bestlineEditDelete(&l); 3462 | } else { 3463 | if (historylen) { 3464 | free(history[--historylen]); 3465 | history[historylen] = 0; 3466 | } 3467 | free(l.buf); 3468 | abFree(&l.full); 3469 | return -1; 3470 | } 3471 | break; 3472 | case '\n': 3473 | l.final = 1; 3474 | bestlineEditEnd(&l); 3475 | bestlineRefreshLineForce(&l); 3476 | l.final = 0; 3477 | abAppend(&l.full, l.buf, l.len); 3478 | l.prompt = "... "; 3479 | abAppends(&l.full, "\n"); 3480 | l.len = 0; 3481 | l.pos = 0; 3482 | bestlineWriteStr(stdout_fd, "\r\n"); 3483 | bestlineRefreshLineForce(&l); 3484 | break; 3485 | case '\r': { 3486 | char is_finished = 1; 3487 | char needs_strip = 0; 3488 | if (historylen) { 3489 | free(history[--historylen]); 3490 | history[historylen] = 0; 3491 | } 3492 | l.final = 1; 3493 | bestlineEditEnd(&l); 3494 | bestlineRefreshLineForce(&l); 3495 | l.final = 0; 3496 | abAppend(&l.full, l.buf, l.len); 3497 | if (pastemode) 3498 | is_finished = 0; 3499 | if (balancemode) 3500 | if (!IsBalanced(&l.full)) 3501 | is_finished = 0; 3502 | if (llamamode) 3503 | if (StartsWith(l.full.b, "\"\"\"")) 3504 | needs_strip = is_finished = l.full.len > 6 && EndsWith(l.full.b, "\"\"\""); 3505 | if (is_finished) { 3506 | if (needs_strip) { 3507 | int len = l.full.len - 6; 3508 | *obuf = strndup(l.full.b + 3, len); 3509 | abFree(&l.full); 3510 | free(l.buf); 3511 | return len; 3512 | } else { 3513 | *obuf = l.full.b; 3514 | free(l.buf); 3515 | return l.full.len; 3516 | } 3517 | } else { 3518 | l.prompt = "... "; 3519 | abAppends(&l.full, "\n"); 3520 | l.len = 0; 3521 | l.pos = 0; 3522 | bestlineWriteStr(stdout_fd, "\r\n"); 3523 | bestlineRefreshLineForce(&l); 3524 | } 3525 | break; 3526 | } 3527 | case 033: 3528 | if (nread < 2) 3529 | break; 3530 | switch (seq[1]) { 3531 | Case('<', bestlineEditBof(&l)); 3532 | Case('>', bestlineEditEof(&l)); 3533 | Case('B', bestlineEditBarf(&l)); 3534 | Case('S', bestlineEditSlurp(&l)); 3535 | Case('R', bestlineEditRaise(&l)); 3536 | Case('y', bestlineEditRotate(&l)); 3537 | Case('\\', bestlineEditSqueeze(&l)); 3538 | Case('b', bestlineEditLeftWord(&l)); 3539 | Case('f', bestlineEditRightWord(&l)); 3540 | Case('h', bestlineEditRuboutWord(&l)); 3541 | Case('d', bestlineEditDeleteWord(&l)); 3542 | Case('l', bestlineEditLowercaseWord(&l)); 3543 | Case('u', bestlineEditUppercaseWord(&l)); 3544 | Case('c', bestlineEditCapitalizeWord(&l)); 3545 | Case('t', bestlineEditTransposeWords(&l)); 3546 | Case(Ctrl('B'), bestlineEditLeftExpr(&l)); 3547 | Case(Ctrl('F'), bestlineEditRightExpr(&l)); 3548 | Case(Ctrl('H'), bestlineEditRuboutWord(&l)); 3549 | case '[': 3550 | if (nread == 6 && !memcmp(seq, "\033[200~", 6)) { 3551 | pastemode = 1; 3552 | break; 3553 | } 3554 | if (nread == 6 && !memcmp(seq, "\033[201~", 6)) { 3555 | pastemode = 0; 3556 | break; 3557 | } 3558 | if (nread < 3) 3559 | break; 3560 | if (seq[2] >= '0' && seq[2] <= '9') { 3561 | if (nread < 4) 3562 | break; 3563 | if (seq[3] == '~') { 3564 | switch (seq[2]) { 3565 | Case('1', bestlineEditHome(&l)); /* \e[1~ */ 3566 | Case('3', bestlineEditDelete(&l)); /* \e[3~ */ 3567 | Case('4', bestlineEditEnd(&l)); /* \e[4~ */ 3568 | default: 3569 | break; 3570 | } 3571 | } 3572 | } else { 3573 | switch (seq[2]) { 3574 | Case('A', bestlineEditUp(&l)); 3575 | Case('B', bestlineEditDown(&l)); 3576 | Case('C', bestlineEditRight(&l)); 3577 | Case('D', bestlineEditLeft(&l)); 3578 | Case('H', bestlineEditHome(&l)); 3579 | Case('F', bestlineEditEnd(&l)); 3580 | default: 3581 | break; 3582 | } 3583 | } 3584 | break; 3585 | case 'O': 3586 | if (nread < 3) 3587 | break; 3588 | switch (seq[2]) { 3589 | Case('A', bestlineEditUp(&l)); 3590 | Case('B', bestlineEditDown(&l)); 3591 | Case('C', bestlineEditRight(&l)); 3592 | Case('D', bestlineEditLeft(&l)); 3593 | Case('H', bestlineEditHome(&l)); 3594 | Case('F', bestlineEditEnd(&l)); 3595 | default: 3596 | break; 3597 | } 3598 | break; 3599 | case 033: 3600 | if (nread < 3) 3601 | break; 3602 | switch (seq[2]) { 3603 | case '[': 3604 | if (nread < 4) 3605 | break; 3606 | switch (seq[3]) { 3607 | Case('C', bestlineEditRightExpr(&l)); /* \e\e[C alt-right */ 3608 | Case('D', bestlineEditLeftExpr(&l)); /* \e\e[D alt-left */ 3609 | default: 3610 | break; 3611 | } 3612 | break; 3613 | case 'O': 3614 | if (nread < 4) 3615 | break; 3616 | switch (seq[3]) { 3617 | Case('C', bestlineEditRightExpr(&l)); /* \e\eOC alt-right */ 3618 | Case('D', bestlineEditLeftExpr(&l)); /* \e\eOD alt-left */ 3619 | default: 3620 | break; 3621 | } 3622 | break; 3623 | default: 3624 | break; 3625 | } 3626 | break; 3627 | default: 3628 | break; 3629 | } 3630 | break; 3631 | default: 3632 | if (!IsControl(seq[0])) { /* only sees canonical c0 */ 3633 | if (xlatCallback) { 3634 | rune = GetUtf8(seq, nread); 3635 | w = EncodeUtf8(xlatCallback(rune.c)); 3636 | nread = 0; 3637 | do { 3638 | seq[nread++] = w; 3639 | } while ((w >>= 8)); 3640 | } 3641 | bestlineEditInsert(&l, seq, nread); 3642 | } 3643 | break; 3644 | } 3645 | } 3646 | } 3647 | 3648 | void bestlineFree(void *ptr) { 3649 | free(ptr); 3650 | } 3651 | 3652 | void bestlineHistoryFree(void) { 3653 | size_t i; 3654 | for (i = 0; i < BESTLINE_MAX_HISTORY; i++) { 3655 | if (history[i]) { 3656 | free(history[i]); 3657 | history[i] = 0; 3658 | } 3659 | } 3660 | historylen = 0; 3661 | } 3662 | 3663 | static void bestlineAtExit(void) { 3664 | bestlineDisableRawMode(); 3665 | bestlineHistoryFree(); 3666 | bestlineRingFree(); 3667 | } 3668 | 3669 | int bestlineHistoryAdd(const char *line) { 3670 | char *linecopy; 3671 | if (!BESTLINE_MAX_HISTORY) 3672 | return 0; 3673 | if (historylen && !strcmp(history[historylen - 1], line)) 3674 | return 0; 3675 | if (!(linecopy = strdup(line))) 3676 | return 0; 3677 | if (historylen == BESTLINE_MAX_HISTORY) { 3678 | free(history[0]); 3679 | memmove(history, history + 1, sizeof(char *) * (BESTLINE_MAX_HISTORY - 1)); 3680 | historylen--; 3681 | } 3682 | history[historylen++] = linecopy; 3683 | return 1; 3684 | } 3685 | 3686 | /** 3687 | * Saves line editing history to file. 3688 | * 3689 | * @return 0 on success, or -1 w/ errno 3690 | */ 3691 | int bestlineHistorySave(const char *filename) { 3692 | FILE *fp; 3693 | unsigned j; 3694 | mode_t old_umask; 3695 | old_umask = umask(S_IXUSR | S_IRWXG | S_IRWXO); 3696 | fp = fopen(filename, "w"); 3697 | umask(old_umask); 3698 | if (!fp) 3699 | return -1; 3700 | chmod(filename, S_IRUSR | S_IWUSR); 3701 | for (j = 0; j < historylen; j++) { 3702 | fputs(history[j], fp); 3703 | fputc('\n', fp); 3704 | } 3705 | fclose(fp); 3706 | return 0; 3707 | } 3708 | 3709 | /** 3710 | * Loads history from the specified file. 3711 | * 3712 | * If the file doesn't exist, zero is returned and this will do nothing. 3713 | * If the file does exists and the operation succeeded zero is returned 3714 | * otherwise on error -1 is returned. 3715 | * 3716 | * @return 0 on success, or -1 w/ errno 3717 | */ 3718 | int bestlineHistoryLoad(const char *filename) { 3719 | char **h; 3720 | int rc, fd, err; 3721 | size_t i, j, k, n, t; 3722 | char *m, *e, *p, *q, *f, *s; 3723 | err = errno, rc = 0; 3724 | if (!BESTLINE_MAX_HISTORY) 3725 | return 0; 3726 | if (!(h = (char **)calloc(2 * BESTLINE_MAX_HISTORY, sizeof(char *)))) 3727 | return -1; 3728 | if ((fd = open(filename, O_RDONLY)) != -1) { 3729 | if ((n = GetFdSize(fd))) { 3730 | if ((m = (char *)mmap(0, n, PROT_READ, MAP_SHARED, fd, 0)) != MAP_FAILED) { 3731 | for (i = 0, e = (p = m) + n; p < e; p = f + 1) { 3732 | if (!(q = (char *)memchr(p, '\n', e - p))) 3733 | q = e; 3734 | for (f = q; q > p; --q) { 3735 | if (q[-1] != '\n' && q[-1] != '\r') 3736 | break; 3737 | } 3738 | if (q > p) { 3739 | h[i * 2 + 0] = p; 3740 | h[i * 2 + 1] = q; 3741 | i = (i + 1) % BESTLINE_MAX_HISTORY; 3742 | } 3743 | } 3744 | bestlineHistoryFree(); 3745 | for (j = 0; j < BESTLINE_MAX_HISTORY; ++j) { 3746 | if (h[(k = (i + j) % BESTLINE_MAX_HISTORY) * 2]) { 3747 | if ((s = (char *)malloc((t = h[k * 2 + 1] - h[k * 2]) + 1))) { 3748 | memcpy(s, h[k * 2], t), s[t] = 0; 3749 | history[historylen++] = s; 3750 | } 3751 | } 3752 | } 3753 | munmap(m, n); 3754 | } else { 3755 | rc = -1; 3756 | } 3757 | } 3758 | close(fd); 3759 | } else if (errno == ENOENT) { 3760 | errno = err; 3761 | } else { 3762 | rc = -1; 3763 | } 3764 | free(h); 3765 | return rc; 3766 | } 3767 | 3768 | /** 3769 | * Like bestlineRaw, but with the additional parameter init used as the buffer 3770 | * initial value. 3771 | */ 3772 | char *bestlineRawInit(const char *prompt, const char *init, int infd, int outfd) { 3773 | char *buf; 3774 | ssize_t rc; 3775 | static char once; 3776 | struct sigaction sa[3]; 3777 | if (!once) 3778 | atexit(bestlineAtExit), once = 1; 3779 | if (enableRawMode(infd) == -1) 3780 | return 0; 3781 | buf = 0; 3782 | gotint = 0; 3783 | sigemptyset(&sa->sa_mask); 3784 | sa->sa_flags = 0; 3785 | sa->sa_handler = bestlineOnInt; 3786 | sigaction(SIGINT, sa, sa + 1); 3787 | sigaction(SIGQUIT, sa, sa + 2); 3788 | bestlineWriteStr(outfd, "\033[?2004h"); // enable bracketed paste mode 3789 | rc = bestlineEdit(infd, outfd, prompt, init, &buf); 3790 | bestlineWriteStr(outfd, "\033[?2004l"); // disable bracketed paste mode 3791 | bestlineDisableRawMode(); 3792 | sigaction(SIGQUIT, sa + 2, 0); 3793 | sigaction(SIGINT, sa + 1, 0); 3794 | if (gotint) { 3795 | free(buf); 3796 | buf = 0; 3797 | raise(gotint); 3798 | errno = EINTR; 3799 | rc = -1; 3800 | } 3801 | bestlineWriteStr(outfd, "\r\n"); 3802 | if (rc != -1) { 3803 | return buf; 3804 | } else { 3805 | free(buf); 3806 | return 0; 3807 | } 3808 | } 3809 | 3810 | /** 3811 | * Reads line interactively. 3812 | * 3813 | * This function can be used instead of bestline() in cases where we 3814 | * know for certain we're dealing with a terminal, which means we can 3815 | * avoid linking any stdio code. 3816 | * 3817 | * @return chomped allocated string of read line or null on eof/error 3818 | */ 3819 | char *bestlineRaw(const char *prompt, int infd, int outfd) { 3820 | return bestlineRawInit(prompt, "", infd, outfd); 3821 | } 3822 | 3823 | /** 3824 | * Like bestline, but with the additional parameter init used as the buffer 3825 | * initial value. The init parameter is only used if the terminal has basic 3826 | * capabilites. 3827 | */ 3828 | char *bestlineInit(const char *prompt, const char *init) { 3829 | if (prompt && *prompt && (strchr(prompt, '\t') || strchr(prompt + 1, '\r'))) { 3830 | errno = EINVAL; 3831 | return 0; 3832 | } 3833 | if ((!isatty(fileno(stdin)) || !isatty(fileno(stdout)))) { 3834 | if (prompt && *prompt && (IsCharDev(fileno(stdin)) && IsCharDev(fileno(stdout)))) { 3835 | fputs(prompt, stdout); 3836 | fflush(stdout); 3837 | } 3838 | return GetLine(stdin, stdout); 3839 | } else if (bestlineIsUnsupportedTerm()) { 3840 | if (prompt && *prompt) { 3841 | fputs(prompt, stdout); 3842 | fflush(stdout); 3843 | } 3844 | return GetLine(stdin, stdout); 3845 | } else { 3846 | fflush(stdout); 3847 | return bestlineRawInit(prompt, init, fileno(stdin), fileno(stdout)); 3848 | } 3849 | } 3850 | 3851 | /** 3852 | * Reads line intelligently. 3853 | * 3854 | * The high level function that is the main API of the bestline library. 3855 | * This function checks if the terminal has basic capabilities, just checking 3856 | * for a blacklist of inarticulate terminals, and later either calls the line 3857 | * editing function or uses dummy fgets() so that you will be able to type 3858 | * something even in the most desperate of the conditions. 3859 | * 3860 | * @param prompt is printed before asking for input if we have a term 3861 | * and this may be set to empty or null to disable and prompt may 3862 | * contain ansi escape sequences, color, utf8, etc. 3863 | * @return chomped allocated string of read line or null on eof/error 3864 | */ 3865 | char *bestline(const char *prompt) { 3866 | return bestlineInit(prompt, ""); 3867 | } 3868 | 3869 | /** 3870 | * Reads line intelligently w/ history, e.g. 3871 | * 3872 | * // see ~/.foo_history 3873 | * main() { 3874 | * char *line; 3875 | * while ((line = bestlineWithHistory("IN> ", "foo"))) { 3876 | * printf("OUT> %s\n", line); 3877 | * free(line); 3878 | * } 3879 | * } 3880 | * 3881 | * @param prompt is printed before asking for input if we have a term 3882 | * and this may be set to empty or null to disable and prompt may 3883 | * contain ansi escape sequences, color, utf8, etc. 3884 | * @param prog is name of your app, used to generate history filename 3885 | * however if it contains a slash / dot then we'll assume prog is 3886 | * the history filename which as determined by the caller 3887 | * @return chomped allocated string of read line or null on eof/error 3888 | */ 3889 | char *bestlineWithHistory(const char *prompt, const char *prog) { 3890 | char *line; 3891 | struct abuf path; 3892 | const char *a, *b; 3893 | abInit(&path); 3894 | if (prog) { 3895 | if (strchr(prog, '/') || strchr(prog, '.')) { 3896 | abAppends(&path, prog); 3897 | } else { 3898 | b = ""; 3899 | if (!(a = getenv("HOME"))) { 3900 | if (!(a = getenv("HOMEDRIVE")) || !(b = getenv("HOMEPATH"))) { 3901 | a = ""; 3902 | } 3903 | } 3904 | if (*a) { 3905 | abAppends(&path, a); 3906 | abAppends(&path, b); 3907 | abAppendw(&path, '/'); 3908 | } 3909 | abAppendw(&path, '.'); 3910 | abAppends(&path, prog); 3911 | abAppends(&path, "_history"); 3912 | } 3913 | } 3914 | if (path.len) { 3915 | bestlineHistoryLoad(path.b); 3916 | } 3917 | line = bestline(prompt); 3918 | if (path.len && line && *line) { 3919 | /* history here is inefficient but helpful when the user has multiple 3920 | * repls open at the same time, so history propagates between them */ 3921 | bestlineHistoryLoad(path.b); 3922 | bestlineHistoryAdd(line); 3923 | bestlineHistorySave(path.b); 3924 | } 3925 | abFree(&path); 3926 | return line; 3927 | } 3928 | 3929 | /** 3930 | * Registers tab completion callback. 3931 | */ 3932 | void bestlineSetCompletionCallback(bestlineCompletionCallback *fn) { 3933 | completionCallback = fn; 3934 | } 3935 | 3936 | /** 3937 | * Registers hints callback. 3938 | * 3939 | * Register a hits function to be called to show hits to the user at the 3940 | * right of the prompt. 3941 | */ 3942 | void bestlineSetHintsCallback(bestlineHintsCallback *fn) { 3943 | hintsCallback = fn; 3944 | } 3945 | 3946 | /** 3947 | * Sets free hints callback. 3948 | * 3949 | * This registers a function to free the hints returned by the hints 3950 | * callback registered with bestlineSetHintsCallback(). 3951 | */ 3952 | void bestlineSetFreeHintsCallback(bestlineFreeHintsCallback *fn) { 3953 | freeHintsCallback = fn; 3954 | } 3955 | 3956 | /** 3957 | * Sets character translation callback. 3958 | */ 3959 | void bestlineSetXlatCallback(bestlineXlatCallback *fn) { 3960 | xlatCallback = fn; 3961 | } 3962 | 3963 | /** 3964 | * Adds completion. 3965 | * 3966 | * This function is used by the callback function registered by the user 3967 | * in order to add completion options given the input string when the 3968 | * user typed . See the example.c source code for a very easy to 3969 | * understand example. 3970 | */ 3971 | void bestlineAddCompletion(bestlineCompletions *lc, const char *str) { 3972 | size_t len; 3973 | char *copy, **cvec; 3974 | if ((copy = (char *)malloc((len = strlen(str)) + 1))) { 3975 | memcpy(copy, str, len + 1); 3976 | if ((cvec = (char **)realloc(lc->cvec, (lc->len + 1) * sizeof(*lc->cvec)))) { 3977 | lc->cvec = cvec; 3978 | lc->cvec[lc->len++] = copy; 3979 | } else { 3980 | free(copy); 3981 | } 3982 | } 3983 | } 3984 | 3985 | /** 3986 | * Frees list of completion option populated by bestlineAddCompletion(). 3987 | */ 3988 | void bestlineFreeCompletions(bestlineCompletions *lc) { 3989 | size_t i; 3990 | for (i = 0; i < lc->len; i++) 3991 | free(lc->cvec[i]); 3992 | if (lc->cvec) 3993 | free(lc->cvec); 3994 | } 3995 | 3996 | /** 3997 | * Enables "mask mode". 3998 | * 3999 | * When it is enabled, instead of the input that the user is typing, the 4000 | * terminal will just display a corresponding number of asterisks, like 4001 | * "****". This is useful for passwords and other secrets that should 4002 | * not be displayed. 4003 | * 4004 | * @see bestlineMaskModeDisable() 4005 | */ 4006 | void bestlineMaskModeEnable(void) { 4007 | maskmode = 1; 4008 | } 4009 | 4010 | /** 4011 | * Disables "mask mode". 4012 | * 4013 | * @see bestlineMaskModeEnable() 4014 | */ 4015 | void bestlineMaskModeDisable(void) { 4016 | maskmode = 0; 4017 | } 4018 | 4019 | /** 4020 | * Enables or disables "balance mode". 4021 | * 4022 | * When it is enabled, bestline() will block until parentheses are 4023 | * balanced. This is useful for code but not for free text. 4024 | */ 4025 | void bestlineBalanceMode(char mode) { 4026 | balancemode = mode; 4027 | } 4028 | 4029 | /** 4030 | * Enables or disables "ollama mode". 4031 | * 4032 | * This enables you to type multiline input by putting triple quotes at 4033 | * the beginning and end. For example: 4034 | * 4035 | * >>> """ 4036 | * ... second line 4037 | * ... third line 4038 | * ... """ 4039 | * 4040 | * Would yield the string `"\nsecond line\nthird line\n"`. 4041 | * 4042 | * @param mode is 1 to enable, or 0 to disable 4043 | */ 4044 | void bestlineLlamaMode(char mode) { 4045 | llamamode = mode; 4046 | } 4047 | 4048 | /** 4049 | * Enables Emacs mode. 4050 | * 4051 | * This mode remaps CTRL-C so you can use additional shortcuts, like C-c 4052 | * C-s for slurp. By default, CTRL-C raises SIGINT for exiting programs. 4053 | */ 4054 | void bestlineEmacsMode(char mode) { 4055 | emacsmode = mode; 4056 | } 4057 | 4058 | /** 4059 | * Allows implementation of user functions for read, write, and poll 4060 | * with the intention of polling for background I/O. 4061 | */ 4062 | 4063 | static int MyRead(int fd, void *c, int n) { 4064 | return read(fd, c, n); 4065 | } 4066 | 4067 | static int MyWrite(int fd, const void *c, int n) { 4068 | return write(fd, c, n); 4069 | } 4070 | 4071 | static int MyPoll(int fd, int events, int to) { 4072 | struct pollfd p[1]; 4073 | p[0].fd = fd; 4074 | p[0].events = events; 4075 | return poll(p, 1, to); 4076 | } 4077 | 4078 | void bestlineUserIO(int (*userReadFn)(int, void *, int), int (*userWriteFn)(int, const void *, int), 4079 | int (*userPollFn)(int, int, int)) { 4080 | if (userReadFn) 4081 | _MyRead = userReadFn; 4082 | else 4083 | _MyRead = MyRead; 4084 | if (userWriteFn) 4085 | _MyWrite = userWriteFn; 4086 | else 4087 | _MyWrite = MyWrite; 4088 | if (userPollFn) 4089 | _MyPoll = userPollFn; 4090 | else 4091 | _MyPoll = MyPoll; 4092 | } 4093 | -------------------------------------------------------------------------------- /bestline.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jart/bestline/5a0bc4bcca0cd912d1671c2f71229e507b4bf632/bestline.gif -------------------------------------------------------------------------------- /bestline.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifdef __cplusplus 3 | extern "C" { 4 | #endif 5 | 6 | typedef struct bestlineCompletions { 7 | unsigned long len; 8 | char **cvec; 9 | } bestlineCompletions; 10 | 11 | typedef void(bestlineCompletionCallback)(const char *, int, 12 | bestlineCompletions *); 13 | typedef char *(bestlineHintsCallback)(const char *, const char **, const char **); 14 | typedef void(bestlineFreeHintsCallback)(void *); 15 | typedef unsigned(bestlineXlatCallback)(unsigned); 16 | 17 | void bestlineSetCompletionCallback(bestlineCompletionCallback *); 18 | void bestlineSetHintsCallback(bestlineHintsCallback *); 19 | void bestlineSetFreeHintsCallback(bestlineFreeHintsCallback *); 20 | void bestlineAddCompletion(bestlineCompletions *, const char *); 21 | void bestlineSetXlatCallback(bestlineXlatCallback *); 22 | 23 | char *bestline(const char *); 24 | char *bestlineInit(const char *, const char *); 25 | char *bestlineRaw(const char *, int, int); 26 | char *bestlineRawInit(const char *, const char *, int, int); 27 | char *bestlineWithHistory(const char *, const char *); 28 | int bestlineHistoryAdd(const char *); 29 | int bestlineHistoryLoad(const char *); 30 | int bestlineHistorySave(const char *); 31 | void bestlineBalanceMode(char); 32 | void bestlineEmacsMode(char); 33 | void bestlineClearScreen(int); 34 | void bestlineDisableRawMode(void); 35 | void bestlineFree(void *); 36 | void bestlineFreeCompletions(bestlineCompletions *); 37 | void bestlineHistoryFree(void); 38 | void bestlineLlamaMode(char); 39 | void bestlineMaskModeDisable(void); 40 | void bestlineMaskModeEnable(void); 41 | 42 | void bestlineUserIO(int (*)(int, void *, int), int (*)(int, const void *, int), 43 | int (*)(int, int, int)); 44 | 45 | int bestlineCharacterWidth(int); 46 | char bestlineIsSeparator(unsigned); 47 | char bestlineNotSeparator(unsigned); 48 | char bestlineIsXeparator(unsigned); 49 | unsigned bestlineUppercase(unsigned); 50 | unsigned bestlineLowercase(unsigned); 51 | long bestlineReadCharacter(int, char *, unsigned long); 52 | 53 | #ifdef __cplusplus 54 | } 55 | #endif 56 | -------------------------------------------------------------------------------- /example.c: -------------------------------------------------------------------------------- 1 | #include "bestline.h" 2 | 3 | #ifndef __COSMOPOLITAN__ 4 | #include 5 | #include 6 | #include 7 | #endif 8 | 9 | #if 0 10 | // should be ~50kb statically linked 11 | // will save history to ~/.foo_history 12 | // cc -fno-jump-tables -Os -o foo foo.c bestline.c 13 | int main() { 14 | char *line; 15 | while ((line = bestlineWithHistory("IN> ", "foo"))) { 16 | fputs("OUT> ", stdout); 17 | fputs(line, stdout); 18 | fputs("\n", stdout); 19 | free(line); 20 | } 21 | } 22 | #endif 23 | 24 | void completion(const char *buf, int pos, bestlineCompletions *lc) { 25 | (void) pos; 26 | if (buf[0] == 'h') { 27 | bestlineAddCompletion(lc, "hello"); 28 | bestlineAddCompletion(lc, "hello there"); 29 | } 30 | } 31 | 32 | char *hints(const char *buf, const char **ansi1, const char **ansi2) { 33 | if (!strcmp(buf, "hello")) { 34 | *ansi1 = "\033[35m"; /* magenta foreground */ 35 | *ansi2 = "\033[39m"; /* reset foreground */ 36 | return " World"; 37 | } 38 | return NULL; 39 | } 40 | 41 | int main(int argc, char **argv) { 42 | char *line; 43 | 44 | /* Set the completion callback. This will be called every time the 45 | * user uses the key. */ 46 | bestlineSetCompletionCallback(completion); 47 | bestlineSetHintsCallback(hints); 48 | 49 | /* Load history from file. The history file is just a plain text file 50 | * where entries are separated by newlines. */ 51 | bestlineHistoryLoad("history.txt"); /* Load the history at startup */ 52 | 53 | /* Now this is the main loop of the typical bestline-based application. 54 | * The call to bestline() will block as long as the user types something 55 | * and presses enter. 56 | * 57 | * The typed string is returned as a malloc() allocated string by 58 | * bestline, so the user needs to free() it. */ 59 | 60 | while ((line = bestline("hello> ")) != NULL) { 61 | /* Do something with the string. */ 62 | if (line[0] != '\0' && line[0] != '/') { 63 | fputs("echo: '", stdout); 64 | fputs(line, stdout); 65 | fputs("'\n", stdout); 66 | bestlineHistoryAdd(line); /* Add to the history. */ 67 | bestlineHistorySave("history.txt"); /* Save the history on disk. */ 68 | } else if (!strncmp(line, "/mask", 5)) { 69 | bestlineMaskModeEnable(); 70 | } else if (!strncmp(line, "/unmask", 7)) { 71 | bestlineMaskModeDisable(); 72 | } else if (!strncmp(line, "/balance", 8)) { 73 | bestlineBalanceMode(1); 74 | } else if (!strncmp(line, "/unbalance", 10)) { 75 | bestlineBalanceMode(0); 76 | } else if (line[0] == '/') { 77 | fputs("Unrecognized command: '", stdout); 78 | fputs(line, stdout); 79 | fputs("'\n", stdout); 80 | } 81 | free(line); 82 | } 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /multi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "bestline.h" 10 | 11 | struct sockaddr_in serve; 12 | 13 | int udp_open(int port) { 14 | int sock = socket(AF_INET, SOCK_DGRAM, 0); 15 | int opt = 1; 16 | setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)); 17 | bzero(&serve, sizeof(serve)); 18 | serve.sin_family = AF_INET; 19 | serve.sin_addr.s_addr = htonl(INADDR_ANY); 20 | serve.sin_port = htons(port); 21 | if (bind(sock, (struct sockaddr *)&serve, sizeof(serve)) >= 0) { 22 | return sock; 23 | } 24 | return -1; 25 | } 26 | 27 | struct sockaddr_in client; 28 | unsigned int client_len = sizeof(client); 29 | 30 | int udp_read(int fd, void *c, int len) { 31 | int n = recvfrom(fd, c, len, 0, (struct sockaddr *)&client, &client_len); 32 | return n; 33 | } 34 | 35 | int sock = -1; 36 | char sock_buf[1024]; 37 | int sock_count = 0; 38 | 39 | int multi_read(int fd, void *c, int n) { 40 | struct pollfd p[2]; 41 | p[0].fd = fd; 42 | p[0].events = POLLIN; 43 | p[1].fd = sock; 44 | p[1].events = POLLIN; 45 | int r = 0; 46 | char *m = (char *)c; 47 | while (1) { 48 | r = poll(p, 2, -1); 49 | if (r <= 0) { 50 | return r; 51 | } 52 | // check for sock events 53 | if (p[1].revents & POLLIN) { 54 | int u = udp_read(sock, sock_buf, sizeof(sock_buf)); 55 | if (u > 0) { 56 | sock_count += u; 57 | } 58 | } 59 | // check for bestline events 60 | if (p[0].revents & POLLIN) { 61 | read(fd, m, n); 62 | m++; 63 | break; 64 | } 65 | } 66 | return r; 67 | } 68 | 69 | #define PORT (13961) 70 | 71 | int main(int argc, char *argv[]) { 72 | char *l; 73 | sock = udp_open(PORT); 74 | if (sock >= 0) { 75 | printf("also listening on *:%d\n", PORT); 76 | bestlineUserIO(multi_read, NULL, NULL); 77 | } 78 | while (1) { 79 | l = bestline("> "); 80 | if (l == NULL) break; 81 | printf("GOT {%s} (%d in background)\n", l, sock_count); 82 | if (l[0] == '?') { 83 | for (int i=0; i= 0) { 97 | sock = -1; 98 | close(sock); 99 | } 100 | return 0; 101 | } 102 | --------------------------------------------------------------------------------