├── .gitignore ├── LICENSE ├── Makefile ├── README.markdown ├── example.c ├── linenoise.c └── linenoise.h /.gitignore: -------------------------------------------------------------------------------- 1 | linenoise_example 2 | *.dSYM 3 | history.txt 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2014, Salvatore Sanfilippo 2 | Copyright (c) 2010-2013, Pieter Noordhuis 3 | 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | linenoise_example: linenoise.h linenoise.c 2 | 3 | linenoise_example: linenoise.c example.c 4 | $(CC) -Wall -W -Os -g -o linenoise_example linenoise.c example.c 5 | 6 | clean: 7 | rm -f linenoise_example 8 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # Linenoise 2 | 3 | A minimal, zero-config, BSD licensed, readline replacement used in Redis, 4 | MongoDB, Android and many other projects. 5 | 6 | * Single and multi line editing mode with the usual key bindings implemented. 7 | * History handling. 8 | * Completion. 9 | * Hints (suggestions at the right of the prompt as you type). 10 | * Multiplexing mode, with prompt hiding/restoring for asynchronous output. 11 | * About ~850 lines (comments and spaces excluded) of BSD license source code. 12 | * Only uses a subset of VT100 escapes (ANSI.SYS compatible). 13 | 14 | ## Can a line editing library be 20k lines of code? 15 | 16 | Line editing with some support for history is a really important feature for command line utilities. Instead of retyping almost the same stuff again and again it's just much better to hit the up arrow and edit on syntax errors, or in order to try a slightly different command. But apparently code dealing with terminals is some sort of Black Magic: readline is 30k lines of code, libedit 20k. Is it reasonable to link small utilities to huge libraries just to get a minimal support for line editing? 17 | 18 | So what usually happens is either: 19 | 20 | * Large programs with configure scripts disabling line editing if readline is not present in the system, or not supporting it at all since readline is GPL licensed and libedit (the BSD clone) is not as known and available as readline is (real world example of this problem: Tclsh). 21 | * Smaller programs not using a configure script not supporting line editing at all (A problem we had with `redis-cli`, for instance). 22 | 23 | The result is a pollution of binaries without line editing support. 24 | 25 | So I spent more or less two hours doing a reality check resulting in this little library: is it *really* needed for a line editing library to be 20k lines of code? Apparently not, it is possibe to get a very small, zero configuration, trivial to embed library, that solves the problem. Smaller programs will just include this, supporting line editing out of the box. Larger programs may use this little library or just checking with configure if readline/libedit is available and resorting to Linenoise if not. 26 | 27 | ## Terminals, in 2010. 28 | 29 | Apparently almost every terminal you can happen to use today has some kind of support for basic VT100 escape sequences. So I tried to write a lib using just very basic VT100 features. The resulting library appears to work everywhere I tried to use it, and now can work even on ANSI.SYS compatible terminals, since no 30 | VT220 specific sequences are used anymore. 31 | 32 | The library is currently about 850 lines of code. In order to use it in your project just look at the *example.c* file in the source distribution, it is pretty straightforward. The library supports both a blocking mode and a multiplexing mode, see the API documentation later in this file for more information. 33 | 34 | Linenoise is BSD-licensed code, so you can use both in free software and commercial software. 35 | 36 | ## Tested with... 37 | 38 | * Linux text only console ($TERM = linux) 39 | * Linux KDE terminal application ($TERM = xterm) 40 | * Linux xterm ($TERM = xterm) 41 | * Linux Buildroot ($TERM = vt100) 42 | * Mac OS X iTerm ($TERM = xterm) 43 | * Mac OS X default Terminal.app ($TERM = xterm) 44 | * OpenBSD 4.5 through an OSX Terminal.app ($TERM = screen) 45 | * IBM AIX 6.1 46 | * FreeBSD xterm ($TERM = xterm) 47 | * ANSI.SYS 48 | * Emacs comint mode ($TERM = dumb) 49 | 50 | Please test it everywhere you can and report back! 51 | 52 | ## Let's push this forward! 53 | 54 | Patches should be provided in the respect of Linenoise sensibility for small 55 | easy to understand code. 56 | 57 | Send feedbacks to antirez at gmail 58 | 59 | # The API 60 | 61 | Linenoise is very easy to use, and reading the example shipped with the 62 | library should get you up to speed ASAP. Here is a list of API calls 63 | and how to use them. Let's start with the simple blocking mode: 64 | 65 | char *linenoise(const char *prompt); 66 | 67 | This is the main Linenoise call: it shows the user a prompt with line editing 68 | and history capabilities. The prompt you specify is used as a prompt, that is, 69 | it will be printed to the left of the cursor. The library returns a buffer 70 | with the line composed by the user, or NULL on end of file or when there 71 | is an out of memory condition. 72 | 73 | When a tty is detected (the user is actually typing into a terminal session) 74 | the maximum editable line length is `LINENOISE_MAX_LINE`. When instead the 75 | standard input is not a tty, which happens every time you redirect a file 76 | to a program, or use it in an Unix pipeline, there are no limits to the 77 | length of the line that can be returned. 78 | 79 | The returned line should be freed with the `free()` standard system call. 80 | However sometimes it could happen that your program uses a different dynamic 81 | allocation library, so you may also used `linenoiseFree` to make sure the 82 | line is freed with the same allocator it was created. 83 | 84 | The canonical loop used by a program using Linenoise will be something like 85 | this: 86 | 87 | while((line = linenoise("hello> ")) != NULL) { 88 | printf("You wrote: %s\n", line); 89 | linenoiseFree(line); /* Or just free(line) if you use libc malloc. */ 90 | } 91 | 92 | ## Single line VS multi line editing 93 | 94 | By default, Linenoise uses single line editing, that is, a single row on the 95 | screen will be used, and as the user types more, the text will scroll towards 96 | left to make room. This works if your program is one where the user is 97 | unlikely to write a lot of text, otherwise multi line editing, where multiple 98 | screens rows are used, can be a lot more comfortable. 99 | 100 | In order to enable multi line editing use the following API call: 101 | 102 | linenoiseSetMultiLine(1); 103 | 104 | You can disable it using `0` as argument. 105 | 106 | ## History 107 | 108 | Linenoise supporst history, so that the user does not have to retype 109 | again and again the same things, but can use the down and up arrows in order 110 | to search and re-edit already inserted lines of text. 111 | 112 | The followings are the history API calls: 113 | 114 | int linenoiseHistoryAdd(const char *line); 115 | int linenoiseHistorySetMaxLen(int len); 116 | int linenoiseHistorySave(const char *filename); 117 | int linenoiseHistoryLoad(const char *filename); 118 | 119 | Use `linenoiseHistoryAdd` every time you want to add a new element 120 | to the top of the history (it will be the first the user will see when 121 | using the up arrow). 122 | 123 | Note that for history to work, you have to set a length for the history 124 | (which is zero by default, so history will be disabled if you don't set 125 | a proper one). This is accomplished using the `linenoiseHistorySetMaxLen` 126 | function. 127 | 128 | Linenoise has direct support for persisting the history into an history 129 | file. The functions `linenoiseHistorySave` and `linenoiseHistoryLoad` do 130 | just that. Both functions return -1 on error and 0 on success. 131 | 132 | ## Mask mode 133 | 134 | Sometimes it is useful to allow the user to type passwords or other 135 | secrets that should not be displayed. For such situations linenoise supports 136 | a "mask mode" that will just replace the characters the user is typing 137 | with `*` characters, like in the following example: 138 | 139 | $ ./linenoise_example 140 | hello> get mykey 141 | echo: 'get mykey' 142 | hello> /mask 143 | hello> ********* 144 | 145 | You can enable and disable mask mode using the following two functions: 146 | 147 | void linenoiseMaskModeEnable(void); 148 | void linenoiseMaskModeDisable(void); 149 | 150 | ## Completion 151 | 152 | Linenoise supports completion, which is the ability to complete the user 153 | input when she or he presses the `` key. 154 | 155 | In order to use completion, you need to register a completion callback, which 156 | is called every time the user presses ``. Your callback will return a 157 | list of items that are completions for the current string. 158 | 159 | The following is an example of registering a completion callback: 160 | 161 | linenoiseSetCompletionCallback(completion); 162 | 163 | The completion must be a function returning `void` and getting as input 164 | a `const char` pointer, which is the line the user has typed so far, and 165 | a `linenoiseCompletions` object pointer, which is used as argument of 166 | `linenoiseAddCompletion` in order to add completions inside the callback. 167 | An example will make it more clear: 168 | 169 | void completion(const char *buf, linenoiseCompletions *lc) { 170 | if (buf[0] == 'h') { 171 | linenoiseAddCompletion(lc,"hello"); 172 | linenoiseAddCompletion(lc,"hello there"); 173 | } 174 | } 175 | 176 | Basically in your completion callback, you inspect the input, and return 177 | a list of items that are good completions by using `linenoiseAddCompletion`. 178 | 179 | If you want to test the completion feature, compile the example program 180 | with `make`, run it, type `h` and press ``. 181 | 182 | ## Hints 183 | 184 | Linenoise has a feature called *hints* which is very useful when you 185 | use Linenoise in order to implement a REPL (Read Eval Print Loop) for 186 | a program that accepts commands and arguments, but may also be useful in 187 | other conditions. 188 | 189 | The feature shows, on the right of the cursor, as the user types, hints that 190 | may be useful. The hints can be displayed using a different color compared 191 | to the color the user is typing, and can also be bold. 192 | 193 | For example as the user starts to type `"git remote add"`, with hints it's 194 | possible to show on the right of the prompt a string ` `. 195 | 196 | The feature works similarly to the history feature, using a callback. 197 | To register the callback we use: 198 | 199 | linenoiseSetHintsCallback(hints); 200 | 201 | The callback itself is implemented like this: 202 | 203 | char *hints(const char *buf, int *color, int *bold) { 204 | if (!strcasecmp(buf,"git remote add")) { 205 | *color = 35; 206 | *bold = 0; 207 | return " "; 208 | } 209 | return NULL; 210 | } 211 | 212 | The callback function returns the string that should be displayed or NULL 213 | if no hint is available for the text the user currently typed. The returned 214 | string will be trimmed as needed depending on the number of columns available 215 | on the screen. 216 | 217 | It is possible to return a string allocated in dynamic way, by also registering 218 | a function to deallocate the hint string once used: 219 | 220 | void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *); 221 | 222 | The free hint callback will just receive the pointer and free the string 223 | as needed (depending on how the hits callback allocated it). 224 | 225 | As you can see in the example above, a `color` (in xterm color terminal codes) 226 | can be provided together with a `bold` attribute. If no color is set, the 227 | current terminal foreground color is used. If no bold attribute is set, 228 | non-bold text is printed. 229 | 230 | Color codes are: 231 | 232 | red = 31 233 | green = 32 234 | yellow = 33 235 | blue = 34 236 | magenta = 35 237 | cyan = 36 238 | white = 37; 239 | 240 | ## Screen handling 241 | 242 | Sometimes you may want to clear the screen as a result of something the 243 | user typed. You can do this by calling the following function: 244 | 245 | void linenoiseClearScreen(void); 246 | 247 | ## Asyncrhronous API 248 | 249 | Sometimes you want to read from the keyboard but also from sockets or other 250 | external events, and at the same time there could be input to display to the 251 | user *while* the user is typing something. Let's call this the "IRC problem", 252 | since if you want to write an IRC client with linenoise, without using 253 | some fully featured libcurses approach, you will surely end having such an 254 | issue. 255 | 256 | Fortunately now a multiplexing friendly API exists, and it is just what the 257 | blocking calls internally use. To start, we need to initialize a linenoise 258 | context like this: 259 | 260 | struct linenoiseState ls; 261 | char buf[1024]; 262 | linenoiseEditStart(&ls,-1,-1,buf,sizeof(buf),"some prompt> "); 263 | 264 | The two -1 and -1 arguments are the stdin/out descriptors. If they are 265 | set to -1, linenoise will just use the default stdin/out file descriptors. 266 | Now as soon as we have data from stdin (and we know it via select(2) or 267 | some other way), we can ask linenoise to read the next character with: 268 | 269 | linenoiseEditFeed(&ls); 270 | 271 | The function returns a `char` pointer: if the user didn't yet press enter 272 | to provide a line to the program, it will return `linenoiseEditMore`, that 273 | means we need to call `linenoiseEditFeed()` again when more data is 274 | available. If the function returns non NULL, then this is a heap allocated 275 | data (to be freed with `linenoiseFree()`) representing the user input. 276 | When the function returns NULL, than the user pressed CTRL-C or CTRL-D 277 | with an empty line, to quit the program, or there was some I/O error. 278 | 279 | After each line is received (or if you want to quit the program, and exit raw mode), the following function needs to be called: 280 | 281 | linenoiseEditStop(&ls); 282 | 283 | To start reading the next line, a new linenoiseEditStart() must 284 | be called, in order to reset the state, and so forth, so a typical event 285 | handler called when the standard input is readable, will work similarly 286 | to the example below: 287 | 288 | ``` c 289 | void stdinHasSomeData(void) { 290 | char *line = linenoiseEditFeed(&LineNoiseState); 291 | if (line == linenoiseEditMore) return; 292 | linenoiseEditStop(&LineNoiseState); 293 | if (line == NULL) exit(0); 294 | 295 | printf("line: %s\n", line); 296 | linenoiseFree(line); 297 | linenoiseEditStart(&LineNoiseState,-1,-1,LineNoiseBuffer,sizeof(LineNoiseBuffer),"serial> "); 298 | } 299 | ``` 300 | 301 | Now that we have a way to avoid blocking in the user input, we can use 302 | two calls to hide/show the edited line, so that it is possible to also 303 | show some input that we received (from socekts, bluetooth, whatever) on 304 | screen: 305 | 306 | linenoiseHide(&ls); 307 | printf("some data...\n"); 308 | linenoiseShow(&ls); 309 | 310 | To the API calls, the linenoise example C file implements a multiplexing 311 | example using select(2) and the asynchronous API: 312 | 313 | ```c 314 | struct linenoiseState ls; 315 | char buf[1024]; 316 | linenoiseEditStart(&ls,-1,-1,buf,sizeof(buf),"hello> "); 317 | 318 | while(1) { 319 | // Select(2) setup code removed... 320 | retval = select(ls.ifd+1, &readfds, NULL, NULL, &tv); 321 | if (retval == -1) { 322 | perror("select()"); 323 | exit(1); 324 | } else if (retval) { 325 | line = linenoiseEditFeed(&ls); 326 | /* A NULL return means: line editing is continuing. 327 | * Otherwise the user hit enter or stopped editing 328 | * (CTRL+C/D). */ 329 | if (line != linenoiseEditMore) break; 330 | } else { 331 | // Timeout occurred 332 | static int counter = 0; 333 | linenoiseHide(&ls); 334 | printf("Async output %d.\n", counter++); 335 | linenoiseShow(&ls); 336 | } 337 | } 338 | linenoiseEditStop(&ls); 339 | if (line == NULL) exit(0); /* Ctrl+D/C. */ 340 | ``` 341 | 342 | You can test the example by running the example program with the `--async` option. 343 | 344 | ## Related projects 345 | 346 | * [Linenoise NG](https://github.com/arangodb/linenoise-ng) is a fork of Linenoise that aims to add more advanced features like UTF-8 support, Windows support and other features. Uses C++ instead of C as development language. 347 | * [Linenoise-swift](https://github.com/andybest/linenoise-swift) is a reimplementation of Linenoise written in Swift. 348 | -------------------------------------------------------------------------------- /example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "linenoise.h" 6 | 7 | void completion(const char *buf, linenoiseCompletions *lc) { 8 | if (buf[0] == 'h') { 9 | linenoiseAddCompletion(lc,"hello"); 10 | linenoiseAddCompletion(lc,"hello there"); 11 | } 12 | } 13 | 14 | char *hints(const char *buf, int *color, int *bold) { 15 | if (!strcasecmp(buf,"hello")) { 16 | *color = 35; 17 | *bold = 0; 18 | return " World"; 19 | } 20 | return NULL; 21 | } 22 | 23 | int main(int argc, char **argv) { 24 | char *line; 25 | char *prgname = argv[0]; 26 | int async = 0; 27 | 28 | /* Parse options, with --multiline we enable multi line editing. */ 29 | while(argc > 1) { 30 | argc--; 31 | argv++; 32 | if (!strcmp(*argv,"--multiline")) { 33 | linenoiseSetMultiLine(1); 34 | printf("Multi-line mode enabled.\n"); 35 | } else if (!strcmp(*argv,"--keycodes")) { 36 | linenoisePrintKeyCodes(); 37 | exit(0); 38 | } else if (!strcmp(*argv,"--async")) { 39 | async = 1; 40 | } else { 41 | fprintf(stderr, "Usage: %s [--multiline] [--keycodes] [--async]\n", prgname); 42 | exit(1); 43 | } 44 | } 45 | 46 | /* Set the completion callback. This will be called every time the 47 | * user uses the key. */ 48 | linenoiseSetCompletionCallback(completion); 49 | linenoiseSetHintsCallback(hints); 50 | 51 | /* Load history from file. The history file is just a plain text file 52 | * where entries are separated by newlines. */ 53 | linenoiseHistoryLoad("history.txt"); /* Load the history at startup */ 54 | 55 | /* Now this is the main loop of the typical linenoise-based application. 56 | * The call to linenoise() will block as long as the user types something 57 | * and presses enter. 58 | * 59 | * The typed string is returned as a malloc() allocated string by 60 | * linenoise, so the user needs to free() it. */ 61 | 62 | while(1) { 63 | if (!async) { 64 | line = linenoise("hello> "); 65 | if (line == NULL) break; 66 | } else { 67 | /* Asynchronous mode using the multiplexing API: wait for 68 | * data on stdin, and simulate async data coming from some source 69 | * using the select(2) timeout. */ 70 | struct linenoiseState ls; 71 | char buf[1024]; 72 | linenoiseEditStart(&ls,-1,-1,buf,sizeof(buf),"hello> "); 73 | while(1) { 74 | fd_set readfds; 75 | struct timeval tv; 76 | int retval; 77 | 78 | FD_ZERO(&readfds); 79 | FD_SET(ls.ifd, &readfds); 80 | tv.tv_sec = 1; // 1 sec timeout 81 | tv.tv_usec = 0; 82 | 83 | retval = select(ls.ifd+1, &readfds, NULL, NULL, &tv); 84 | if (retval == -1) { 85 | perror("select()"); 86 | exit(1); 87 | } else if (retval) { 88 | line = linenoiseEditFeed(&ls); 89 | /* A NULL return means: line editing is continuing. 90 | * Otherwise the user hit enter or stopped editing 91 | * (CTRL+C/D). */ 92 | if (line != linenoiseEditMore) break; 93 | } else { 94 | // Timeout occurred 95 | static int counter = 0; 96 | linenoiseHide(&ls); 97 | printf("Async output %d.\n", counter++); 98 | linenoiseShow(&ls); 99 | } 100 | } 101 | linenoiseEditStop(&ls); 102 | if (line == NULL) exit(0); /* Ctrl+D/C. */ 103 | } 104 | 105 | /* Do something with the string. */ 106 | if (line[0] != '\0' && line[0] != '/') { 107 | printf("echo: '%s'\n", line); 108 | linenoiseHistoryAdd(line); /* Add to the history. */ 109 | linenoiseHistorySave("history.txt"); /* Save the history on disk. */ 110 | } else if (!strncmp(line,"/historylen",11)) { 111 | /* The "/historylen" command will change the history len. */ 112 | int len = atoi(line+11); 113 | linenoiseHistorySetMaxLen(len); 114 | } else if (!strncmp(line, "/mask", 5)) { 115 | linenoiseMaskModeEnable(); 116 | } else if (!strncmp(line, "/unmask", 7)) { 117 | linenoiseMaskModeDisable(); 118 | } else if (line[0] == '/') { 119 | printf("Unreconized command: %s\n", line); 120 | } 121 | free(line); 122 | } 123 | return 0; 124 | } 125 | -------------------------------------------------------------------------------- /linenoise.c: -------------------------------------------------------------------------------- 1 | /* linenoise.c -- guerrilla line editing library against the idea that a 2 | * line editing lib needs to be 20,000 lines of C code. 3 | * 4 | * You can find the latest source code at: 5 | * 6 | * http://github.com/antirez/linenoise 7 | * 8 | * Does a number of crazy assumptions that happen to be true in 99.9999% of 9 | * the 2010 UNIX computers around. 10 | * 11 | * ------------------------------------------------------------------------ 12 | * 13 | * Copyright (c) 2010-2023, Salvatore Sanfilippo 14 | * Copyright (c) 2010-2013, Pieter Noordhuis 15 | * 16 | * All rights reserved. 17 | * 18 | * Redistribution and use in source and binary forms, with or without 19 | * modification, are permitted provided that the following conditions are 20 | * met: 21 | * 22 | * * Redistributions of source code must retain the above copyright 23 | * notice, this list of conditions and the following disclaimer. 24 | * 25 | * * Redistributions in binary form must reproduce the above copyright 26 | * notice, this list of conditions and the following disclaimer in the 27 | * documentation and/or other materials provided with the distribution. 28 | * 29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 32 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 35 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 | * 41 | * ------------------------------------------------------------------------ 42 | * 43 | * References: 44 | * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html 45 | * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html 46 | * 47 | * Todo list: 48 | * - Filter bogus Ctrl+ combinations. 49 | * - Win32 support 50 | * 51 | * Bloat: 52 | * - History search like Ctrl+r in readline? 53 | * 54 | * List of escape sequences used by this program, we do everything just 55 | * with three sequences. In order to be so cheap we may have some 56 | * flickering effect with some slow terminal, but the lesser sequences 57 | * the more compatible. 58 | * 59 | * EL (Erase Line) 60 | * Sequence: ESC [ n K 61 | * Effect: if n is 0 or missing, clear from cursor to end of line 62 | * Effect: if n is 1, clear from beginning of line to cursor 63 | * Effect: if n is 2, clear entire line 64 | * 65 | * CUF (CUrsor Forward) 66 | * Sequence: ESC [ n C 67 | * Effect: moves cursor forward n chars 68 | * 69 | * CUB (CUrsor Backward) 70 | * Sequence: ESC [ n D 71 | * Effect: moves cursor backward n chars 72 | * 73 | * The following is used to get the terminal width if getting 74 | * the width with the TIOCGWINSZ ioctl fails 75 | * 76 | * DSR (Device Status Report) 77 | * Sequence: ESC [ 6 n 78 | * Effect: reports the current cusor position as ESC [ n ; m R 79 | * where n is the row and m is the column 80 | * 81 | * When multi line mode is enabled, we also use an additional escape 82 | * sequence. However multi line editing is disabled by default. 83 | * 84 | * CUU (Cursor Up) 85 | * Sequence: ESC [ n A 86 | * Effect: moves cursor up of n chars. 87 | * 88 | * CUD (Cursor Down) 89 | * Sequence: ESC [ n B 90 | * Effect: moves cursor down of n chars. 91 | * 92 | * When linenoiseClearScreen() is called, two additional escape sequences 93 | * are used in order to clear the screen and position the cursor at home 94 | * position. 95 | * 96 | * CUP (Cursor position) 97 | * Sequence: ESC [ H 98 | * Effect: moves the cursor to upper left corner 99 | * 100 | * ED (Erase display) 101 | * Sequence: ESC [ 2 J 102 | * Effect: clear the whole screen 103 | * 104 | */ 105 | 106 | #include 107 | #include 108 | #include 109 | #include 110 | #include 111 | #include 112 | #include 113 | #include 114 | #include 115 | #include 116 | #include 117 | #include 118 | #include "linenoise.h" 119 | 120 | #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100 121 | #define LINENOISE_MAX_LINE 4096 122 | static char *unsupported_term[] = {"dumb","cons25","emacs",NULL}; 123 | static linenoiseCompletionCallback *completionCallback = NULL; 124 | static linenoiseHintsCallback *hintsCallback = NULL; 125 | static linenoiseFreeHintsCallback *freeHintsCallback = NULL; 126 | static char *linenoiseNoTTY(void); 127 | static void refreshLineWithCompletion(struct linenoiseState *ls, linenoiseCompletions *lc, int flags); 128 | static void refreshLineWithFlags(struct linenoiseState *l, int flags); 129 | 130 | static struct termios orig_termios; /* In order to restore at exit.*/ 131 | static int maskmode = 0; /* Show "***" instead of input. For passwords. */ 132 | static int rawmode = 0; /* For atexit() function to check if restore is needed*/ 133 | static int mlmode = 0; /* Multi line mode. Default is single line. */ 134 | static int atexit_registered = 0; /* Register atexit just 1 time. */ 135 | static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN; 136 | static int history_len = 0; 137 | static char **history = NULL; 138 | 139 | enum KEY_ACTION{ 140 | KEY_NULL = 0, /* NULL */ 141 | CTRL_A = 1, /* Ctrl+a */ 142 | CTRL_B = 2, /* Ctrl-b */ 143 | CTRL_C = 3, /* Ctrl-c */ 144 | CTRL_D = 4, /* Ctrl-d */ 145 | CTRL_E = 5, /* Ctrl-e */ 146 | CTRL_F = 6, /* Ctrl-f */ 147 | CTRL_H = 8, /* Ctrl-h */ 148 | TAB = 9, /* Tab */ 149 | CTRL_K = 11, /* Ctrl+k */ 150 | CTRL_L = 12, /* Ctrl+l */ 151 | ENTER = 13, /* Enter */ 152 | CTRL_N = 14, /* Ctrl-n */ 153 | CTRL_P = 16, /* Ctrl-p */ 154 | CTRL_T = 20, /* Ctrl-t */ 155 | CTRL_U = 21, /* Ctrl+u */ 156 | CTRL_W = 23, /* Ctrl+w */ 157 | ESC = 27, /* Escape */ 158 | BACKSPACE = 127 /* Backspace */ 159 | }; 160 | 161 | static void linenoiseAtExit(void); 162 | int linenoiseHistoryAdd(const char *line); 163 | #define REFRESH_CLEAN (1<<0) // Clean the old prompt from the screen 164 | #define REFRESH_WRITE (1<<1) // Rewrite the prompt on the screen. 165 | #define REFRESH_ALL (REFRESH_CLEAN|REFRESH_WRITE) // Do both. 166 | static void refreshLine(struct linenoiseState *l); 167 | 168 | /* Debugging macro. */ 169 | #if 0 170 | FILE *lndebug_fp = NULL; 171 | #define lndebug(...) \ 172 | do { \ 173 | if (lndebug_fp == NULL) { \ 174 | lndebug_fp = fopen("/tmp/lndebug.txt","a"); \ 175 | fprintf(lndebug_fp, \ 176 | "[%d %d %d] p: %d, rows: %d, rpos: %d, max: %d, oldmax: %d\n", \ 177 | (int)l->len,(int)l->pos,(int)l->oldpos,plen,rows,rpos, \ 178 | (int)l->oldrows,old_rows); \ 179 | } \ 180 | fprintf(lndebug_fp, ", " __VA_ARGS__); \ 181 | fflush(lndebug_fp); \ 182 | } while (0) 183 | #else 184 | #define lndebug(fmt, ...) 185 | #endif 186 | 187 | /* ======================= Low level terminal handling ====================== */ 188 | 189 | /* Enable "mask mode". When it is enabled, instead of the input that 190 | * the user is typing, the terminal will just display a corresponding 191 | * number of asterisks, like "****". This is useful for passwords and other 192 | * secrets that should not be displayed. */ 193 | void linenoiseMaskModeEnable(void) { 194 | maskmode = 1; 195 | } 196 | 197 | /* Disable mask mode. */ 198 | void linenoiseMaskModeDisable(void) { 199 | maskmode = 0; 200 | } 201 | 202 | /* Set if to use or not the multi line mode. */ 203 | void linenoiseSetMultiLine(int ml) { 204 | mlmode = ml; 205 | } 206 | 207 | /* Return true if the terminal name is in the list of terminals we know are 208 | * not able to understand basic escape sequences. */ 209 | static int isUnsupportedTerm(void) { 210 | char *term = getenv("TERM"); 211 | int j; 212 | 213 | if (term == NULL) return 0; 214 | for (j = 0; unsupported_term[j]; j++) 215 | if (!strcasecmp(term,unsupported_term[j])) return 1; 216 | return 0; 217 | } 218 | 219 | /* Raw mode: 1960 magic shit. */ 220 | static int enableRawMode(int fd) { 221 | struct termios raw; 222 | 223 | if (!isatty(STDIN_FILENO)) goto fatal; 224 | if (!atexit_registered) { 225 | atexit(linenoiseAtExit); 226 | atexit_registered = 1; 227 | } 228 | if (tcgetattr(fd,&orig_termios) == -1) goto fatal; 229 | 230 | raw = orig_termios; /* modify the original mode */ 231 | /* input modes: no break, no CR to NL, no parity check, no strip char, 232 | * no start/stop output control. */ 233 | raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); 234 | /* output modes - disable post processing */ 235 | raw.c_oflag &= ~(OPOST); 236 | /* control modes - set 8 bit chars */ 237 | raw.c_cflag |= (CS8); 238 | /* local modes - choing off, canonical off, no extended functions, 239 | * no signal chars (^Z,^C) */ 240 | raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); 241 | /* control chars - set return condition: min number of bytes and timer. 242 | * We want read to return every single byte, without timeout. */ 243 | raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */ 244 | 245 | /* put terminal in raw mode after flushing */ 246 | if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal; 247 | rawmode = 1; 248 | return 0; 249 | 250 | fatal: 251 | errno = ENOTTY; 252 | return -1; 253 | } 254 | 255 | static void disableRawMode(int fd) { 256 | /* Don't even check the return value as it's too late. */ 257 | if (rawmode && tcsetattr(fd,TCSAFLUSH,&orig_termios) != -1) 258 | rawmode = 0; 259 | } 260 | 261 | /* Use the ESC [6n escape sequence to query the horizontal cursor position 262 | * and return it. On error -1 is returned, on success the position of the 263 | * cursor. */ 264 | static int getCursorPosition(int ifd, int ofd) { 265 | char buf[32]; 266 | int cols, rows; 267 | unsigned int i = 0; 268 | 269 | /* Report cursor location */ 270 | if (write(ofd, "\x1b[6n", 4) != 4) return -1; 271 | 272 | /* Read the response: ESC [ rows ; cols R */ 273 | while (i < sizeof(buf)-1) { 274 | if (read(ifd,buf+i,1) != 1) break; 275 | if (buf[i] == 'R') break; 276 | i++; 277 | } 278 | buf[i] = '\0'; 279 | 280 | /* Parse it. */ 281 | if (buf[0] != ESC || buf[1] != '[') return -1; 282 | if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1; 283 | return cols; 284 | } 285 | 286 | /* Try to get the number of columns in the current terminal, or assume 80 287 | * if it fails. */ 288 | static int getColumns(int ifd, int ofd) { 289 | struct winsize ws; 290 | 291 | if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) { 292 | /* ioctl() failed. Try to query the terminal itself. */ 293 | int start, cols; 294 | 295 | /* Get the initial position so we can restore it later. */ 296 | start = getCursorPosition(ifd,ofd); 297 | if (start == -1) goto failed; 298 | 299 | /* Go to right margin and get position. */ 300 | if (write(ofd,"\x1b[999C",6) != 6) goto failed; 301 | cols = getCursorPosition(ifd,ofd); 302 | if (cols == -1) goto failed; 303 | 304 | /* Restore position. */ 305 | if (cols > start) { 306 | char seq[32]; 307 | snprintf(seq,32,"\x1b[%dD",cols-start); 308 | if (write(ofd,seq,strlen(seq)) == -1) { 309 | /* Can't recover... */ 310 | } 311 | } 312 | return cols; 313 | } else { 314 | return ws.ws_col; 315 | } 316 | 317 | failed: 318 | return 80; 319 | } 320 | 321 | /* Clear the screen. Used to handle ctrl+l */ 322 | void linenoiseClearScreen(void) { 323 | if (write(STDOUT_FILENO,"\x1b[H\x1b[2J",7) <= 0) { 324 | /* nothing to do, just to avoid warning. */ 325 | } 326 | } 327 | 328 | /* Beep, used for completion when there is nothing to complete or when all 329 | * the choices were already shown. */ 330 | static void linenoiseBeep(void) { 331 | fprintf(stderr, "\x7"); 332 | fflush(stderr); 333 | } 334 | 335 | /* ============================== Completion ================================ */ 336 | 337 | /* Free a list of completion option populated by linenoiseAddCompletion(). */ 338 | static void freeCompletions(linenoiseCompletions *lc) { 339 | size_t i; 340 | for (i = 0; i < lc->len; i++) 341 | free(lc->cvec[i]); 342 | if (lc->cvec != NULL) 343 | free(lc->cvec); 344 | } 345 | 346 | /* Called by completeLine() and linenoiseShow() to render the current 347 | * edited line with the proposed completion. If the current completion table 348 | * is already available, it is passed as second argument, otherwise the 349 | * function will use the callback to obtain it. 350 | * 351 | * Flags are the same as refreshLine*(), that is REFRESH_* macros. */ 352 | static void refreshLineWithCompletion(struct linenoiseState *ls, linenoiseCompletions *lc, int flags) { 353 | /* Obtain the table of completions if the caller didn't provide one. */ 354 | linenoiseCompletions ctable = { 0, NULL }; 355 | if (lc == NULL) { 356 | completionCallback(ls->buf,&ctable); 357 | lc = &ctable; 358 | } 359 | 360 | /* Show the edited line with completion if possible, or just refresh. */ 361 | if (ls->completion_idx < lc->len) { 362 | struct linenoiseState saved = *ls; 363 | ls->len = ls->pos = strlen(lc->cvec[ls->completion_idx]); 364 | ls->buf = lc->cvec[ls->completion_idx]; 365 | refreshLineWithFlags(ls,flags); 366 | ls->len = saved.len; 367 | ls->pos = saved.pos; 368 | ls->buf = saved.buf; 369 | } else { 370 | refreshLineWithFlags(ls,flags); 371 | } 372 | 373 | /* Free the completions table if needed. */ 374 | if (lc != &ctable) freeCompletions(&ctable); 375 | } 376 | 377 | /* This is an helper function for linenoiseEdit*() and is called when the 378 | * user types the key in order to complete the string currently in the 379 | * input. 380 | * 381 | * The state of the editing is encapsulated into the pointed linenoiseState 382 | * structure as described in the structure definition. 383 | * 384 | * If the function returns non-zero, the caller should handle the 385 | * returned value as a byte read from the standard input, and process 386 | * it as usually: this basically means that the function may return a byte 387 | * read from the termianl but not processed. Otherwise, if zero is returned, 388 | * the input was consumed by the completeLine() function to navigate the 389 | * possible completions, and the caller should read for the next characters 390 | * from stdin. */ 391 | static int completeLine(struct linenoiseState *ls, int keypressed) { 392 | linenoiseCompletions lc = { 0, NULL }; 393 | int nwritten; 394 | char c = keypressed; 395 | 396 | completionCallback(ls->buf,&lc); 397 | if (lc.len == 0) { 398 | linenoiseBeep(); 399 | ls->in_completion = 0; 400 | } else { 401 | switch(c) { 402 | case 9: /* tab */ 403 | if (ls->in_completion == 0) { 404 | ls->in_completion = 1; 405 | ls->completion_idx = 0; 406 | } else { 407 | ls->completion_idx = (ls->completion_idx+1) % (lc.len+1); 408 | if (ls->completion_idx == lc.len) linenoiseBeep(); 409 | } 410 | c = 0; 411 | break; 412 | case 27: /* escape */ 413 | /* Re-show original buffer */ 414 | if (ls->completion_idx < lc.len) refreshLine(ls); 415 | ls->in_completion = 0; 416 | c = 0; 417 | break; 418 | default: 419 | /* Update buffer and return */ 420 | if (ls->completion_idx < lc.len) { 421 | nwritten = snprintf(ls->buf,ls->buflen,"%s", 422 | lc.cvec[ls->completion_idx]); 423 | ls->len = ls->pos = nwritten; 424 | } 425 | ls->in_completion = 0; 426 | break; 427 | } 428 | 429 | /* Show completion or original buffer */ 430 | if (ls->in_completion && ls->completion_idx < lc.len) { 431 | refreshLineWithCompletion(ls,&lc,REFRESH_ALL); 432 | } else { 433 | refreshLine(ls); 434 | } 435 | } 436 | 437 | freeCompletions(&lc); 438 | return c; /* Return last read character */ 439 | } 440 | 441 | /* Register a callback function to be called for tab-completion. */ 442 | void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) { 443 | completionCallback = fn; 444 | } 445 | 446 | /* Register a hits function to be called to show hits to the user at the 447 | * right of the prompt. */ 448 | void linenoiseSetHintsCallback(linenoiseHintsCallback *fn) { 449 | hintsCallback = fn; 450 | } 451 | 452 | /* Register a function to free the hints returned by the hints callback 453 | * registered with linenoiseSetHintsCallback(). */ 454 | void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn) { 455 | freeHintsCallback = fn; 456 | } 457 | 458 | /* This function is used by the callback function registered by the user 459 | * in order to add completion options given the input string when the 460 | * user typed . See the example.c source code for a very easy to 461 | * understand example. */ 462 | void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) { 463 | size_t len = strlen(str); 464 | char *copy, **cvec; 465 | 466 | copy = malloc(len+1); 467 | if (copy == NULL) return; 468 | memcpy(copy,str,len+1); 469 | cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1)); 470 | if (cvec == NULL) { 471 | free(copy); 472 | return; 473 | } 474 | lc->cvec = cvec; 475 | lc->cvec[lc->len++] = copy; 476 | } 477 | 478 | /* =========================== Line editing ================================= */ 479 | 480 | /* We define a very simple "append buffer" structure, that is an heap 481 | * allocated string where we can append to. This is useful in order to 482 | * write all the escape sequences in a buffer and flush them to the standard 483 | * output in a single call, to avoid flickering effects. */ 484 | struct abuf { 485 | char *b; 486 | int len; 487 | }; 488 | 489 | static void abInit(struct abuf *ab) { 490 | ab->b = NULL; 491 | ab->len = 0; 492 | } 493 | 494 | static void abAppend(struct abuf *ab, const char *s, int len) { 495 | char *new = realloc(ab->b,ab->len+len); 496 | 497 | if (new == NULL) return; 498 | memcpy(new+ab->len,s,len); 499 | ab->b = new; 500 | ab->len += len; 501 | } 502 | 503 | static void abFree(struct abuf *ab) { 504 | free(ab->b); 505 | } 506 | 507 | /* Helper of refreshSingleLine() and refreshMultiLine() to show hints 508 | * to the right of the prompt. */ 509 | void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) { 510 | char seq[64]; 511 | if (hintsCallback && plen+l->len < l->cols) { 512 | int color = -1, bold = 0; 513 | char *hint = hintsCallback(l->buf,&color,&bold); 514 | if (hint) { 515 | int hintlen = strlen(hint); 516 | int hintmaxlen = l->cols-(plen+l->len); 517 | if (hintlen > hintmaxlen) hintlen = hintmaxlen; 518 | if (bold == 1 && color == -1) color = 37; 519 | if (color != -1 || bold != 0) 520 | snprintf(seq,64,"\033[%d;%d;49m",bold,color); 521 | else 522 | seq[0] = '\0'; 523 | abAppend(ab,seq,strlen(seq)); 524 | abAppend(ab,hint,hintlen); 525 | if (color != -1 || bold != 0) 526 | abAppend(ab,"\033[0m",4); 527 | /* Call the function to free the hint returned. */ 528 | if (freeHintsCallback) freeHintsCallback(hint); 529 | } 530 | } 531 | } 532 | 533 | /* Single line low level line refresh. 534 | * 535 | * Rewrite the currently edited line accordingly to the buffer content, 536 | * cursor position, and number of columns of the terminal. 537 | * 538 | * Flags is REFRESH_* macros. The function can just remove the old 539 | * prompt, just write it, or both. */ 540 | static void refreshSingleLine(struct linenoiseState *l, int flags) { 541 | char seq[64]; 542 | size_t plen = strlen(l->prompt); 543 | int fd = l->ofd; 544 | char *buf = l->buf; 545 | size_t len = l->len; 546 | size_t pos = l->pos; 547 | struct abuf ab; 548 | 549 | while((plen+pos) >= l->cols) { 550 | buf++; 551 | len--; 552 | pos--; 553 | } 554 | while (plen+len > l->cols) { 555 | len--; 556 | } 557 | 558 | abInit(&ab); 559 | /* Cursor to left edge */ 560 | snprintf(seq,sizeof(seq),"\r"); 561 | abAppend(&ab,seq,strlen(seq)); 562 | 563 | if (flags & REFRESH_WRITE) { 564 | /* Write the prompt and the current buffer content */ 565 | abAppend(&ab,l->prompt,strlen(l->prompt)); 566 | if (maskmode == 1) { 567 | while (len--) abAppend(&ab,"*",1); 568 | } else { 569 | abAppend(&ab,buf,len); 570 | } 571 | /* Show hits if any. */ 572 | refreshShowHints(&ab,l,plen); 573 | } 574 | 575 | /* Erase to right */ 576 | snprintf(seq,sizeof(seq),"\x1b[0K"); 577 | abAppend(&ab,seq,strlen(seq)); 578 | 579 | if (flags & REFRESH_WRITE) { 580 | /* Move cursor to original position. */ 581 | snprintf(seq,sizeof(seq),"\r\x1b[%dC", (int)(pos+plen)); 582 | abAppend(&ab,seq,strlen(seq)); 583 | } 584 | 585 | if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */ 586 | abFree(&ab); 587 | } 588 | 589 | /* Multi line low level line refresh. 590 | * 591 | * Rewrite the currently edited line accordingly to the buffer content, 592 | * cursor position, and number of columns of the terminal. 593 | * 594 | * Flags is REFRESH_* macros. The function can just remove the old 595 | * prompt, just write it, or both. */ 596 | static void refreshMultiLine(struct linenoiseState *l, int flags) { 597 | char seq[64]; 598 | int plen = strlen(l->prompt); 599 | int rows = (plen+l->len+l->cols-1)/l->cols; /* rows used by current buf. */ 600 | int rpos = (plen+l->oldpos+l->cols)/l->cols; /* cursor relative row. */ 601 | int rpos2; /* rpos after refresh. */ 602 | int col; /* colum position, zero-based. */ 603 | int old_rows = l->oldrows; 604 | int fd = l->ofd, j; 605 | struct abuf ab; 606 | 607 | l->oldrows = rows; 608 | 609 | /* First step: clear all the lines used before. To do so start by 610 | * going to the last row. */ 611 | abInit(&ab); 612 | 613 | if (flags & REFRESH_CLEAN) { 614 | if (old_rows-rpos > 0) { 615 | lndebug("go down %d", old_rows-rpos); 616 | snprintf(seq,64,"\x1b[%dB", old_rows-rpos); 617 | abAppend(&ab,seq,strlen(seq)); 618 | } 619 | 620 | /* Now for every row clear it, go up. */ 621 | for (j = 0; j < old_rows-1; j++) { 622 | lndebug("clear+up"); 623 | snprintf(seq,64,"\r\x1b[0K\x1b[1A"); 624 | abAppend(&ab,seq,strlen(seq)); 625 | } 626 | } 627 | 628 | if (flags & REFRESH_ALL) { 629 | /* Clean the top line. */ 630 | lndebug("clear"); 631 | snprintf(seq,64,"\r\x1b[0K"); 632 | abAppend(&ab,seq,strlen(seq)); 633 | } 634 | 635 | if (flags & REFRESH_WRITE) { 636 | /* Write the prompt and the current buffer content */ 637 | abAppend(&ab,l->prompt,strlen(l->prompt)); 638 | if (maskmode == 1) { 639 | unsigned int i; 640 | for (i = 0; i < l->len; i++) abAppend(&ab,"*",1); 641 | } else { 642 | abAppend(&ab,l->buf,l->len); 643 | } 644 | 645 | /* Show hits if any. */ 646 | refreshShowHints(&ab,l,plen); 647 | 648 | /* If we are at the very end of the screen with our prompt, we need to 649 | * emit a newline and move the prompt to the first column. */ 650 | if (l->pos && 651 | l->pos == l->len && 652 | (l->pos+plen) % l->cols == 0) 653 | { 654 | lndebug(""); 655 | abAppend(&ab,"\n",1); 656 | snprintf(seq,64,"\r"); 657 | abAppend(&ab,seq,strlen(seq)); 658 | rows++; 659 | if (rows > (int)l->oldrows) l->oldrows = rows; 660 | } 661 | 662 | /* Move cursor to right position. */ 663 | rpos2 = (plen+l->pos+l->cols)/l->cols; /* Current cursor relative row */ 664 | lndebug("rpos2 %d", rpos2); 665 | 666 | /* Go up till we reach the expected positon. */ 667 | if (rows-rpos2 > 0) { 668 | lndebug("go-up %d", rows-rpos2); 669 | snprintf(seq,64,"\x1b[%dA", rows-rpos2); 670 | abAppend(&ab,seq,strlen(seq)); 671 | } 672 | 673 | /* Set column. */ 674 | col = (plen+(int)l->pos) % (int)l->cols; 675 | lndebug("set col %d", 1+col); 676 | if (col) 677 | snprintf(seq,64,"\r\x1b[%dC", col); 678 | else 679 | snprintf(seq,64,"\r"); 680 | abAppend(&ab,seq,strlen(seq)); 681 | } 682 | 683 | lndebug("\n"); 684 | l->oldpos = l->pos; 685 | 686 | if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */ 687 | abFree(&ab); 688 | } 689 | 690 | /* Calls the two low level functions refreshSingleLine() or 691 | * refreshMultiLine() according to the selected mode. */ 692 | static void refreshLineWithFlags(struct linenoiseState *l, int flags) { 693 | if (mlmode) 694 | refreshMultiLine(l,flags); 695 | else 696 | refreshSingleLine(l,flags); 697 | } 698 | 699 | /* Utility function to avoid specifying REFRESH_ALL all the times. */ 700 | static void refreshLine(struct linenoiseState *l) { 701 | refreshLineWithFlags(l,REFRESH_ALL); 702 | } 703 | 704 | /* Hide the current line, when using the multiplexing API. */ 705 | void linenoiseHide(struct linenoiseState *l) { 706 | if (mlmode) 707 | refreshMultiLine(l,REFRESH_CLEAN); 708 | else 709 | refreshSingleLine(l,REFRESH_CLEAN); 710 | } 711 | 712 | /* Show the current line, when using the multiplexing API. */ 713 | void linenoiseShow(struct linenoiseState *l) { 714 | if (l->in_completion) { 715 | refreshLineWithCompletion(l,NULL,REFRESH_WRITE); 716 | } else { 717 | refreshLineWithFlags(l,REFRESH_WRITE); 718 | } 719 | } 720 | 721 | /* Insert the character 'c' at cursor current position. 722 | * 723 | * On error writing to the terminal -1 is returned, otherwise 0. */ 724 | int linenoiseEditInsert(struct linenoiseState *l, char c) { 725 | if (l->len < l->buflen) { 726 | if (l->len == l->pos) { 727 | l->buf[l->pos] = c; 728 | l->pos++; 729 | l->len++; 730 | l->buf[l->len] = '\0'; 731 | if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) { 732 | /* Avoid a full update of the line in the 733 | * trivial case. */ 734 | char d = (maskmode==1) ? '*' : c; 735 | if (write(l->ofd,&d,1) == -1) return -1; 736 | } else { 737 | refreshLine(l); 738 | } 739 | } else { 740 | memmove(l->buf+l->pos+1,l->buf+l->pos,l->len-l->pos); 741 | l->buf[l->pos] = c; 742 | l->len++; 743 | l->pos++; 744 | l->buf[l->len] = '\0'; 745 | refreshLine(l); 746 | } 747 | } 748 | return 0; 749 | } 750 | 751 | /* Move cursor on the left. */ 752 | void linenoiseEditMoveLeft(struct linenoiseState *l) { 753 | if (l->pos > 0) { 754 | l->pos--; 755 | refreshLine(l); 756 | } 757 | } 758 | 759 | /* Move cursor on the right. */ 760 | void linenoiseEditMoveRight(struct linenoiseState *l) { 761 | if (l->pos != l->len) { 762 | l->pos++; 763 | refreshLine(l); 764 | } 765 | } 766 | 767 | /* Move cursor to the start of the line. */ 768 | void linenoiseEditMoveHome(struct linenoiseState *l) { 769 | if (l->pos != 0) { 770 | l->pos = 0; 771 | refreshLine(l); 772 | } 773 | } 774 | 775 | /* Move cursor to the end of the line. */ 776 | void linenoiseEditMoveEnd(struct linenoiseState *l) { 777 | if (l->pos != l->len) { 778 | l->pos = l->len; 779 | refreshLine(l); 780 | } 781 | } 782 | 783 | /* Substitute the currently edited line with the next or previous history 784 | * entry as specified by 'dir'. */ 785 | #define LINENOISE_HISTORY_NEXT 0 786 | #define LINENOISE_HISTORY_PREV 1 787 | void linenoiseEditHistoryNext(struct linenoiseState *l, int dir) { 788 | if (history_len > 1) { 789 | /* Update the current history entry before to 790 | * overwrite it with the next one. */ 791 | free(history[history_len - 1 - l->history_index]); 792 | history[history_len - 1 - l->history_index] = strdup(l->buf); 793 | /* Show the new entry */ 794 | l->history_index += (dir == LINENOISE_HISTORY_PREV) ? 1 : -1; 795 | if (l->history_index < 0) { 796 | l->history_index = 0; 797 | return; 798 | } else if (l->history_index >= history_len) { 799 | l->history_index = history_len-1; 800 | return; 801 | } 802 | strncpy(l->buf,history[history_len - 1 - l->history_index],l->buflen); 803 | l->buf[l->buflen-1] = '\0'; 804 | l->len = l->pos = strlen(l->buf); 805 | refreshLine(l); 806 | } 807 | } 808 | 809 | /* Delete the character at the right of the cursor without altering the cursor 810 | * position. Basically this is what happens with the "Delete" keyboard key. */ 811 | void linenoiseEditDelete(struct linenoiseState *l) { 812 | if (l->len > 0 && l->pos < l->len) { 813 | memmove(l->buf+l->pos,l->buf+l->pos+1,l->len-l->pos-1); 814 | l->len--; 815 | l->buf[l->len] = '\0'; 816 | refreshLine(l); 817 | } 818 | } 819 | 820 | /* Backspace implementation. */ 821 | void linenoiseEditBackspace(struct linenoiseState *l) { 822 | if (l->pos > 0 && l->len > 0) { 823 | memmove(l->buf+l->pos-1,l->buf+l->pos,l->len-l->pos); 824 | l->pos--; 825 | l->len--; 826 | l->buf[l->len] = '\0'; 827 | refreshLine(l); 828 | } 829 | } 830 | 831 | /* Delete the previosu word, maintaining the cursor at the start of the 832 | * current word. */ 833 | void linenoiseEditDeletePrevWord(struct linenoiseState *l) { 834 | size_t old_pos = l->pos; 835 | size_t diff; 836 | 837 | while (l->pos > 0 && l->buf[l->pos-1] == ' ') 838 | l->pos--; 839 | while (l->pos > 0 && l->buf[l->pos-1] != ' ') 840 | l->pos--; 841 | diff = old_pos - l->pos; 842 | memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1); 843 | l->len -= diff; 844 | refreshLine(l); 845 | } 846 | 847 | /* This function is part of the multiplexed API of Linenoise, that is used 848 | * in order to implement the blocking variant of the API but can also be 849 | * called by the user directly in an event driven program. It will: 850 | * 851 | * 1. Initialize the linenoise state passed by the user. 852 | * 2. Put the terminal in RAW mode. 853 | * 3. Show the prompt. 854 | * 4. Return control to the user, that will have to call linenoiseEditFeed() 855 | * each time there is some data arriving in the standard input. 856 | * 857 | * The user can also call linenoiseEditHide() and linenoiseEditShow() if it 858 | * is required to show some input arriving asyncronously, without mixing 859 | * it with the currently edited line. 860 | * 861 | * When linenoiseEditFeed() returns non-NULL, the user finished with the 862 | * line editing session (pressed enter CTRL-D/C): in this case the caller 863 | * needs to call linenoiseEditStop() to put back the terminal in normal 864 | * mode. This will not destroy the buffer, as long as the linenoiseState 865 | * is still valid in the context of the caller. 866 | * 867 | * The function returns 0 on success, or -1 if writing to standard output 868 | * fails. If stdin_fd or stdout_fd are set to -1, the default is to use 869 | * STDIN_FILENO and STDOUT_FILENO. 870 | */ 871 | int linenoiseEditStart(struct linenoiseState *l, int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt) { 872 | /* Populate the linenoise state that we pass to functions implementing 873 | * specific editing functionalities. */ 874 | l->in_completion = 0; 875 | l->ifd = stdin_fd != -1 ? stdin_fd : STDIN_FILENO; 876 | l->ofd = stdout_fd != -1 ? stdout_fd : STDOUT_FILENO; 877 | l->buf = buf; 878 | l->buflen = buflen; 879 | l->prompt = prompt; 880 | l->plen = strlen(prompt); 881 | l->oldpos = l->pos = 0; 882 | l->len = 0; 883 | 884 | /* Enter raw mode. */ 885 | if (enableRawMode(l->ifd) == -1) return -1; 886 | 887 | l->cols = getColumns(stdin_fd, stdout_fd); 888 | l->oldrows = 0; 889 | l->history_index = 0; 890 | 891 | /* Buffer starts empty. */ 892 | l->buf[0] = '\0'; 893 | l->buflen--; /* Make sure there is always space for the nulterm */ 894 | 895 | /* If stdin is not a tty, stop here with the initialization. We 896 | * will actually just read a line from standard input in blocking 897 | * mode later, in linenoiseEditFeed(). */ 898 | if (!isatty(l->ifd)) return 0; 899 | 900 | /* The latest history entry is always our current buffer, that 901 | * initially is just an empty string. */ 902 | linenoiseHistoryAdd(""); 903 | 904 | if (write(l->ofd,prompt,l->plen) == -1) return -1; 905 | return 0; 906 | } 907 | 908 | char *linenoiseEditMore = "If you see this, you are misusing the API: when linenoiseEditFeed() is called, if it returns linenoiseEditMore the user is yet editing the line. See the README file for more information."; 909 | 910 | /* This function is part of the multiplexed API of linenoise, see the top 911 | * comment on linenoiseEditStart() for more information. Call this function 912 | * each time there is some data to read from the standard input file 913 | * descriptor. In the case of blocking operations, this function can just be 914 | * called in a loop, and block. 915 | * 916 | * The function returns linenoiseEditMore to signal that line editing is still 917 | * in progress, that is, the user didn't yet pressed enter / CTRL-D. Otherwise 918 | * the function returns the pointer to the heap-allocated buffer with the 919 | * edited line, that the user should free with linenoiseFree(). 920 | * 921 | * On special conditions, NULL is returned and errno is populated: 922 | * 923 | * EAGAIN if the user pressed Ctrl-C 924 | * ENOENT if the user pressed Ctrl-D 925 | * 926 | * Some other errno: I/O error. 927 | */ 928 | char *linenoiseEditFeed(struct linenoiseState *l) { 929 | /* Not a TTY, pass control to line reading without character 930 | * count limits. */ 931 | if (!isatty(l->ifd)) return linenoiseNoTTY(); 932 | 933 | char c; 934 | int nread; 935 | char seq[3]; 936 | 937 | nread = read(l->ifd,&c,1); 938 | if (nread <= 0) return NULL; 939 | 940 | /* Only autocomplete when the callback is set. It returns < 0 when 941 | * there was an error reading from fd. Otherwise it will return the 942 | * character that should be handled next. */ 943 | if ((l->in_completion || c == 9) && completionCallback != NULL) { 944 | c = completeLine(l,c); 945 | /* Return on errors */ 946 | if (c < 0) return NULL; 947 | /* Read next character when 0 */ 948 | if (c == 0) return linenoiseEditMore; 949 | } 950 | 951 | switch(c) { 952 | case ENTER: /* enter */ 953 | history_len--; 954 | free(history[history_len]); 955 | if (mlmode) linenoiseEditMoveEnd(l); 956 | if (hintsCallback) { 957 | /* Force a refresh without hints to leave the previous 958 | * line as the user typed it after a newline. */ 959 | linenoiseHintsCallback *hc = hintsCallback; 960 | hintsCallback = NULL; 961 | refreshLine(l); 962 | hintsCallback = hc; 963 | } 964 | return strdup(l->buf); 965 | case CTRL_C: /* ctrl-c */ 966 | errno = EAGAIN; 967 | return NULL; 968 | case BACKSPACE: /* backspace */ 969 | case 8: /* ctrl-h */ 970 | linenoiseEditBackspace(l); 971 | break; 972 | case CTRL_D: /* ctrl-d, remove char at right of cursor, or if the 973 | line is empty, act as end-of-file. */ 974 | if (l->len > 0) { 975 | linenoiseEditDelete(l); 976 | } else { 977 | history_len--; 978 | free(history[history_len]); 979 | errno = ENOENT; 980 | return NULL; 981 | } 982 | break; 983 | case CTRL_T: /* ctrl-t, swaps current character with previous. */ 984 | if (l->pos > 0 && l->pos < l->len) { 985 | int aux = l->buf[l->pos-1]; 986 | l->buf[l->pos-1] = l->buf[l->pos]; 987 | l->buf[l->pos] = aux; 988 | if (l->pos != l->len-1) l->pos++; 989 | refreshLine(l); 990 | } 991 | break; 992 | case CTRL_B: /* ctrl-b */ 993 | linenoiseEditMoveLeft(l); 994 | break; 995 | case CTRL_F: /* ctrl-f */ 996 | linenoiseEditMoveRight(l); 997 | break; 998 | case CTRL_P: /* ctrl-p */ 999 | linenoiseEditHistoryNext(l, LINENOISE_HISTORY_PREV); 1000 | break; 1001 | case CTRL_N: /* ctrl-n */ 1002 | linenoiseEditHistoryNext(l, LINENOISE_HISTORY_NEXT); 1003 | break; 1004 | case ESC: /* escape sequence */ 1005 | /* Read the next two bytes representing the escape sequence. 1006 | * Use two calls to handle slow terminals returning the two 1007 | * chars at different times. */ 1008 | if (read(l->ifd,seq,1) == -1) break; 1009 | if (read(l->ifd,seq+1,1) == -1) break; 1010 | 1011 | /* ESC [ sequences. */ 1012 | if (seq[0] == '[') { 1013 | if (seq[1] >= '0' && seq[1] <= '9') { 1014 | /* Extended escape, read additional byte. */ 1015 | if (read(l->ifd,seq+2,1) == -1) break; 1016 | if (seq[2] == '~') { 1017 | switch(seq[1]) { 1018 | case '3': /* Delete key. */ 1019 | linenoiseEditDelete(l); 1020 | break; 1021 | } 1022 | } 1023 | } else { 1024 | switch(seq[1]) { 1025 | case 'A': /* Up */ 1026 | linenoiseEditHistoryNext(l, LINENOISE_HISTORY_PREV); 1027 | break; 1028 | case 'B': /* Down */ 1029 | linenoiseEditHistoryNext(l, LINENOISE_HISTORY_NEXT); 1030 | break; 1031 | case 'C': /* Right */ 1032 | linenoiseEditMoveRight(l); 1033 | break; 1034 | case 'D': /* Left */ 1035 | linenoiseEditMoveLeft(l); 1036 | break; 1037 | case 'H': /* Home */ 1038 | linenoiseEditMoveHome(l); 1039 | break; 1040 | case 'F': /* End*/ 1041 | linenoiseEditMoveEnd(l); 1042 | break; 1043 | } 1044 | } 1045 | } 1046 | 1047 | /* ESC O sequences. */ 1048 | else if (seq[0] == 'O') { 1049 | switch(seq[1]) { 1050 | case 'H': /* Home */ 1051 | linenoiseEditMoveHome(l); 1052 | break; 1053 | case 'F': /* End*/ 1054 | linenoiseEditMoveEnd(l); 1055 | break; 1056 | } 1057 | } 1058 | break; 1059 | default: 1060 | if (linenoiseEditInsert(l,c)) return NULL; 1061 | break; 1062 | case CTRL_U: /* Ctrl+u, delete the whole line. */ 1063 | l->buf[0] = '\0'; 1064 | l->pos = l->len = 0; 1065 | refreshLine(l); 1066 | break; 1067 | case CTRL_K: /* Ctrl+k, delete from current to end of line. */ 1068 | l->buf[l->pos] = '\0'; 1069 | l->len = l->pos; 1070 | refreshLine(l); 1071 | break; 1072 | case CTRL_A: /* Ctrl+a, go to the start of the line */ 1073 | linenoiseEditMoveHome(l); 1074 | break; 1075 | case CTRL_E: /* ctrl+e, go to the end of the line */ 1076 | linenoiseEditMoveEnd(l); 1077 | break; 1078 | case CTRL_L: /* ctrl+l, clear screen */ 1079 | linenoiseClearScreen(); 1080 | refreshLine(l); 1081 | break; 1082 | case CTRL_W: /* ctrl+w, delete previous word */ 1083 | linenoiseEditDeletePrevWord(l); 1084 | break; 1085 | } 1086 | return linenoiseEditMore; 1087 | } 1088 | 1089 | /* This is part of the multiplexed linenoise API. See linenoiseEditStart() 1090 | * for more information. This function is called when linenoiseEditFeed() 1091 | * returns something different than NULL. At this point the user input 1092 | * is in the buffer, and we can restore the terminal in normal mode. */ 1093 | void linenoiseEditStop(struct linenoiseState *l) { 1094 | if (!isatty(l->ifd)) return; 1095 | disableRawMode(l->ifd); 1096 | printf("\n"); 1097 | } 1098 | 1099 | /* This just implements a blocking loop for the multiplexed API. 1100 | * In many applications that are not event-drivern, we can just call 1101 | * the blocking linenoise API, wait for the user to complete the editing 1102 | * and return the buffer. */ 1103 | static char *linenoiseBlockingEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt) 1104 | { 1105 | struct linenoiseState l; 1106 | 1107 | /* Editing without a buffer is invalid. */ 1108 | if (buflen == 0) { 1109 | errno = EINVAL; 1110 | return NULL; 1111 | } 1112 | 1113 | linenoiseEditStart(&l,stdin_fd,stdout_fd,buf,buflen,prompt); 1114 | char *res; 1115 | while((res = linenoiseEditFeed(&l)) == linenoiseEditMore); 1116 | linenoiseEditStop(&l); 1117 | return res; 1118 | } 1119 | 1120 | /* This special mode is used by linenoise in order to print scan codes 1121 | * on screen for debugging / development purposes. It is implemented 1122 | * by the linenoise_example program using the --keycodes option. */ 1123 | void linenoisePrintKeyCodes(void) { 1124 | char quit[4]; 1125 | 1126 | printf("Linenoise key codes debugging mode.\n" 1127 | "Press keys to see scan codes. Type 'quit' at any time to exit.\n"); 1128 | if (enableRawMode(STDIN_FILENO) == -1) return; 1129 | memset(quit,' ',4); 1130 | while(1) { 1131 | char c; 1132 | int nread; 1133 | 1134 | nread = read(STDIN_FILENO,&c,1); 1135 | if (nread <= 0) continue; 1136 | memmove(quit,quit+1,sizeof(quit)-1); /* shift string to left. */ 1137 | quit[sizeof(quit)-1] = c; /* Insert current char on the right. */ 1138 | if (memcmp(quit,"quit",sizeof(quit)) == 0) break; 1139 | 1140 | printf("'%c' %02x (%d) (type quit to exit)\n", 1141 | isprint(c) ? c : '?', (int)c, (int)c); 1142 | printf("\r"); /* Go left edge manually, we are in raw mode. */ 1143 | fflush(stdout); 1144 | } 1145 | disableRawMode(STDIN_FILENO); 1146 | } 1147 | 1148 | /* This function is called when linenoise() is called with the standard 1149 | * input file descriptor not attached to a TTY. So for example when the 1150 | * program using linenoise is called in pipe or with a file redirected 1151 | * to its standard input. In this case, we want to be able to return the 1152 | * line regardless of its length (by default we are limited to 4k). */ 1153 | static char *linenoiseNoTTY(void) { 1154 | char *line = NULL; 1155 | size_t len = 0, maxlen = 0; 1156 | 1157 | while(1) { 1158 | if (len == maxlen) { 1159 | if (maxlen == 0) maxlen = 16; 1160 | maxlen *= 2; 1161 | char *oldval = line; 1162 | line = realloc(line,maxlen); 1163 | if (line == NULL) { 1164 | if (oldval) free(oldval); 1165 | return NULL; 1166 | } 1167 | } 1168 | int c = fgetc(stdin); 1169 | if (c == EOF || c == '\n') { 1170 | if (c == EOF && len == 0) { 1171 | free(line); 1172 | return NULL; 1173 | } else { 1174 | line[len] = '\0'; 1175 | return line; 1176 | } 1177 | } else { 1178 | line[len] = c; 1179 | len++; 1180 | } 1181 | } 1182 | } 1183 | 1184 | /* The high level function that is the main API of the linenoise library. 1185 | * This function checks if the terminal has basic capabilities, just checking 1186 | * for a blacklist of stupid terminals, and later either calls the line 1187 | * editing function or uses dummy fgets() so that you will be able to type 1188 | * something even in the most desperate of the conditions. */ 1189 | char *linenoise(const char *prompt) { 1190 | char buf[LINENOISE_MAX_LINE]; 1191 | 1192 | if (!isatty(STDIN_FILENO)) { 1193 | /* Not a tty: read from file / pipe. In this mode we don't want any 1194 | * limit to the line size, so we call a function to handle that. */ 1195 | return linenoiseNoTTY(); 1196 | } else if (isUnsupportedTerm()) { 1197 | size_t len; 1198 | 1199 | printf("%s",prompt); 1200 | fflush(stdout); 1201 | if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL; 1202 | len = strlen(buf); 1203 | while(len && (buf[len-1] == '\n' || buf[len-1] == '\r')) { 1204 | len--; 1205 | buf[len] = '\0'; 1206 | } 1207 | return strdup(buf); 1208 | } else { 1209 | char *retval = linenoiseBlockingEdit(STDIN_FILENO,STDOUT_FILENO,buf,LINENOISE_MAX_LINE,prompt); 1210 | return retval; 1211 | } 1212 | } 1213 | 1214 | /* This is just a wrapper the user may want to call in order to make sure 1215 | * the linenoise returned buffer is freed with the same allocator it was 1216 | * created with. Useful when the main program is using an alternative 1217 | * allocator. */ 1218 | void linenoiseFree(void *ptr) { 1219 | if (ptr == linenoiseEditMore) return; // Protect from API misuse. 1220 | free(ptr); 1221 | } 1222 | 1223 | /* ================================ History ================================= */ 1224 | 1225 | /* Free the history, but does not reset it. Only used when we have to 1226 | * exit() to avoid memory leaks are reported by valgrind & co. */ 1227 | static void freeHistory(void) { 1228 | if (history) { 1229 | int j; 1230 | 1231 | for (j = 0; j < history_len; j++) 1232 | free(history[j]); 1233 | free(history); 1234 | } 1235 | } 1236 | 1237 | /* At exit we'll try to fix the terminal to the initial conditions. */ 1238 | static void linenoiseAtExit(void) { 1239 | disableRawMode(STDIN_FILENO); 1240 | freeHistory(); 1241 | } 1242 | 1243 | /* This is the API call to add a new entry in the linenoise history. 1244 | * It uses a fixed array of char pointers that are shifted (memmoved) 1245 | * when the history max length is reached in order to remove the older 1246 | * entry and make room for the new one, so it is not exactly suitable for huge 1247 | * histories, but will work well for a few hundred of entries. 1248 | * 1249 | * Using a circular buffer is smarter, but a bit more complex to handle. */ 1250 | int linenoiseHistoryAdd(const char *line) { 1251 | char *linecopy; 1252 | 1253 | if (history_max_len == 0) return 0; 1254 | 1255 | /* Initialization on first call. */ 1256 | if (history == NULL) { 1257 | history = malloc(sizeof(char*)*history_max_len); 1258 | if (history == NULL) return 0; 1259 | memset(history,0,(sizeof(char*)*history_max_len)); 1260 | } 1261 | 1262 | /* Don't add duplicated lines. */ 1263 | if (history_len && !strcmp(history[history_len-1], line)) return 0; 1264 | 1265 | /* Add an heap allocated copy of the line in the history. 1266 | * If we reached the max length, remove the older line. */ 1267 | linecopy = strdup(line); 1268 | if (!linecopy) return 0; 1269 | if (history_len == history_max_len) { 1270 | free(history[0]); 1271 | memmove(history,history+1,sizeof(char*)*(history_max_len-1)); 1272 | history_len--; 1273 | } 1274 | history[history_len] = linecopy; 1275 | history_len++; 1276 | return 1; 1277 | } 1278 | 1279 | /* Set the maximum length for the history. This function can be called even 1280 | * if there is already some history, the function will make sure to retain 1281 | * just the latest 'len' elements if the new history length value is smaller 1282 | * than the amount of items already inside the history. */ 1283 | int linenoiseHistorySetMaxLen(int len) { 1284 | char **new; 1285 | 1286 | if (len < 1) return 0; 1287 | if (history) { 1288 | int tocopy = history_len; 1289 | 1290 | new = malloc(sizeof(char*)*len); 1291 | if (new == NULL) return 0; 1292 | 1293 | /* If we can't copy everything, free the elements we'll not use. */ 1294 | if (len < tocopy) { 1295 | int j; 1296 | 1297 | for (j = 0; j < tocopy-len; j++) free(history[j]); 1298 | tocopy = len; 1299 | } 1300 | memset(new,0,sizeof(char*)*len); 1301 | memcpy(new,history+(history_len-tocopy), sizeof(char*)*tocopy); 1302 | free(history); 1303 | history = new; 1304 | } 1305 | history_max_len = len; 1306 | if (history_len > history_max_len) 1307 | history_len = history_max_len; 1308 | return 1; 1309 | } 1310 | 1311 | /* Save the history in the specified file. On success 0 is returned 1312 | * otherwise -1 is returned. */ 1313 | int linenoiseHistorySave(const char *filename) { 1314 | mode_t old_umask = umask(S_IXUSR|S_IRWXG|S_IRWXO); 1315 | FILE *fp; 1316 | int j; 1317 | 1318 | fp = fopen(filename,"w"); 1319 | umask(old_umask); 1320 | if (fp == NULL) return -1; 1321 | chmod(filename,S_IRUSR|S_IWUSR); 1322 | for (j = 0; j < history_len; j++) 1323 | fprintf(fp,"%s\n",history[j]); 1324 | fclose(fp); 1325 | return 0; 1326 | } 1327 | 1328 | /* Load the history from the specified file. If the file does not exist 1329 | * zero is returned and no operation is performed. 1330 | * 1331 | * If the file exists and the operation succeeded 0 is returned, otherwise 1332 | * on error -1 is returned. */ 1333 | int linenoiseHistoryLoad(const char *filename) { 1334 | FILE *fp = fopen(filename,"r"); 1335 | char buf[LINENOISE_MAX_LINE]; 1336 | 1337 | if (fp == NULL) return -1; 1338 | 1339 | while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) { 1340 | char *p; 1341 | 1342 | p = strchr(buf,'\r'); 1343 | if (!p) p = strchr(buf,'\n'); 1344 | if (p) *p = '\0'; 1345 | linenoiseHistoryAdd(buf); 1346 | } 1347 | fclose(fp); 1348 | return 0; 1349 | } 1350 | -------------------------------------------------------------------------------- /linenoise.h: -------------------------------------------------------------------------------- 1 | /* linenoise.h -- VERSION 1.0 2 | * 3 | * Guerrilla line editing library against the idea that a line editing lib 4 | * needs to be 20,000 lines of C code. 5 | * 6 | * See linenoise.c for more information. 7 | * 8 | * ------------------------------------------------------------------------ 9 | * 10 | * Copyright (c) 2010-2023, Salvatore Sanfilippo 11 | * Copyright (c) 2010-2013, Pieter Noordhuis 12 | * 13 | * All rights reserved. 14 | * 15 | * Redistribution and use in source and binary forms, with or without 16 | * modification, are permitted provided that the following conditions are 17 | * met: 18 | * 19 | * * Redistributions of source code must retain the above copyright 20 | * notice, this list of conditions and the following disclaimer. 21 | * 22 | * * Redistributions in binary form must reproduce the above copyright 23 | * notice, this list of conditions and the following disclaimer in the 24 | * documentation and/or other materials provided with the distribution. 25 | * 26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 29 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 30 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 32 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | */ 38 | 39 | #ifndef __LINENOISE_H 40 | #define __LINENOISE_H 41 | 42 | #ifdef __cplusplus 43 | extern "C" { 44 | #endif 45 | 46 | #include /* For size_t. */ 47 | 48 | extern char *linenoiseEditMore; 49 | 50 | /* The linenoiseState structure represents the state during line editing. 51 | * We pass this state to functions implementing specific editing 52 | * functionalities. */ 53 | struct linenoiseState { 54 | int in_completion; /* The user pressed TAB and we are now in completion 55 | * mode, so input is handled by completeLine(). */ 56 | size_t completion_idx; /* Index of next completion to propose. */ 57 | int ifd; /* Terminal stdin file descriptor. */ 58 | int ofd; /* Terminal stdout file descriptor. */ 59 | char *buf; /* Edited line buffer. */ 60 | size_t buflen; /* Edited line buffer size. */ 61 | const char *prompt; /* Prompt to display. */ 62 | size_t plen; /* Prompt length. */ 63 | size_t pos; /* Current cursor position. */ 64 | size_t oldpos; /* Previous refresh cursor position. */ 65 | size_t len; /* Current edited line length. */ 66 | size_t cols; /* Number of columns in terminal. */ 67 | size_t oldrows; /* Rows used by last refrehsed line (multiline mode) */ 68 | int history_index; /* The history index we are currently editing. */ 69 | }; 70 | 71 | typedef struct linenoiseCompletions { 72 | size_t len; 73 | char **cvec; 74 | } linenoiseCompletions; 75 | 76 | /* Non blocking API. */ 77 | int linenoiseEditStart(struct linenoiseState *l, int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt); 78 | char *linenoiseEditFeed(struct linenoiseState *l); 79 | void linenoiseEditStop(struct linenoiseState *l); 80 | void linenoiseHide(struct linenoiseState *l); 81 | void linenoiseShow(struct linenoiseState *l); 82 | 83 | /* Blocking API. */ 84 | char *linenoise(const char *prompt); 85 | void linenoiseFree(void *ptr); 86 | 87 | /* Completion API. */ 88 | typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *); 89 | typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold); 90 | typedef void(linenoiseFreeHintsCallback)(void *); 91 | void linenoiseSetCompletionCallback(linenoiseCompletionCallback *); 92 | void linenoiseSetHintsCallback(linenoiseHintsCallback *); 93 | void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *); 94 | void linenoiseAddCompletion(linenoiseCompletions *, const char *); 95 | 96 | /* History API. */ 97 | int linenoiseHistoryAdd(const char *line); 98 | int linenoiseHistorySetMaxLen(int len); 99 | int linenoiseHistorySave(const char *filename); 100 | int linenoiseHistoryLoad(const char *filename); 101 | 102 | /* Other utilities. */ 103 | void linenoiseClearScreen(void); 104 | void linenoiseSetMultiLine(int ml); 105 | void linenoisePrintKeyCodes(void); 106 | void linenoiseMaskModeEnable(void); 107 | void linenoiseMaskModeDisable(void); 108 | 109 | #ifdef __cplusplus 110 | } 111 | #endif 112 | 113 | #endif /* __LINENOISE_H */ 114 | --------------------------------------------------------------------------------