aboutsummaryrefslogtreecommitdiff
path: root/examples/redis-unstable/deps/linenoise
diff options
context:
space:
mode:
Diffstat (limited to 'examples/redis-unstable/deps/linenoise')
-rw-r--r--examples/redis-unstable/deps/linenoise/.gitignore3
-rw-r--r--examples/redis-unstable/deps/linenoise/Makefile21
-rw-r--r--examples/redis-unstable/deps/linenoise/README.markdown247
-rw-r--r--examples/redis-unstable/deps/linenoise/example.c79
-rw-r--r--examples/redis-unstable/deps/linenoise/linenoise.c1457
-rw-r--r--examples/redis-unstable/deps/linenoise/linenoise.h75
6 files changed, 1882 insertions, 0 deletions
diff --git a/examples/redis-unstable/deps/linenoise/.gitignore b/examples/redis-unstable/deps/linenoise/.gitignore
new file mode 100644
index 0000000..7ab7825
--- /dev/null
+++ b/examples/redis-unstable/deps/linenoise/.gitignore
@@ -0,0 +1,3 @@
1linenoise_example
2*.dSYM
3history.txt
diff --git a/examples/redis-unstable/deps/linenoise/Makefile b/examples/redis-unstable/deps/linenoise/Makefile
new file mode 100644
index 0000000..1dd894b
--- /dev/null
+++ b/examples/redis-unstable/deps/linenoise/Makefile
@@ -0,0 +1,21 @@
1STD=
2WARN= -Wall
3OPT= -Os
4
5R_CFLAGS= $(STD) $(WARN) $(OPT) $(DEBUG) $(CFLAGS)
6R_LDFLAGS= $(LDFLAGS)
7DEBUG= -g
8
9R_CC=$(CC) $(R_CFLAGS)
10R_LD=$(CC) $(R_LDFLAGS)
11
12linenoise.o: linenoise.h linenoise.c
13
14linenoise_example: linenoise.o example.o
15 $(R_LD) -o $@ $^
16
17.c.o:
18 $(R_CC) -c $<
19
20clean:
21 rm -f linenoise_example *.o
diff --git a/examples/redis-unstable/deps/linenoise/README.markdown b/examples/redis-unstable/deps/linenoise/README.markdown
new file mode 100644
index 0000000..b3752da
--- /dev/null
+++ b/examples/redis-unstable/deps/linenoise/README.markdown
@@ -0,0 +1,247 @@
1# Linenoise
2
3A minimal, zero-config, BSD licensed, readline replacement used in Redis,
4MongoDB, and Android.
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* About 1,100 lines of BSD license source code.
11* Only uses a subset of VT100 escapes (ANSI.SYS compatible).
12
13## Can a line editing library be 20k lines of code?
14
15Line 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?
16
17So what usually happens is either:
18
19 * 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).
20 * Smaller programs not using a configure script not supporting line editing at all (A problem we had with Redis-cli for instance).
21
22The result is a pollution of binaries without line editing support.
23
24So 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.
25
26## Terminals, in 2010.
27
28Apparently 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
29VT220 specific sequences are used anymore.
30
31The library is currently about 1100 lines of code. In order to use it in your project just look at the *example.c* file in the source distribution, it is trivial. Linenoise is BSD code, so you can use both in free software and commercial software.
32
33## Tested with...
34
35 * Linux text only console ($TERM = linux)
36 * Linux KDE terminal application ($TERM = xterm)
37 * Linux xterm ($TERM = xterm)
38 * Linux Buildroot ($TERM = vt100)
39 * Mac OS X iTerm ($TERM = xterm)
40 * Mac OS X default Terminal.app ($TERM = xterm)
41 * OpenBSD 4.5 through an OSX Terminal.app ($TERM = screen)
42 * IBM AIX 6.1
43 * FreeBSD xterm ($TERM = xterm)
44 * ANSI.SYS
45 * Emacs comint mode ($TERM = dumb)
46
47Please test it everywhere you can and report back!
48
49## Let's push this forward!
50
51Patches should be provided in the respect of Linenoise sensibility for small
52easy to understand code.
53
54Send feedbacks to antirez at gmail
55
56# The API
57
58Linenoise is very easy to use, and reading the example shipped with the
59library should get you up to speed ASAP. Here is a list of API calls
60and how to use them.
61
62 char *linenoise(const char *prompt);
63
64This is the main Linenoise call: it shows the user a prompt with line editing
65and history capabilities. The prompt you specify is used as a prompt, that is,
66it will be printed to the left of the cursor. The library returns a buffer
67with the line composed by the user, or NULL on end of file or when there
68is an out of memory condition.
69
70When a tty is detected (the user is actually typing into a terminal session)
71the maximum editable line length is `LINENOISE_MAX_LINE`. When instead the
72standard input is not a tty, which happens every time you redirect a file
73to a program, or use it in an Unix pipeline, there are no limits to the
74length of the line that can be returned.
75
76The returned line should be freed with the `free()` standard system call.
77However sometimes it could happen that your program uses a different dynamic
78allocation library, so you may also used `linenoiseFree` to make sure the
79line is freed with the same allocator it was created.
80
81The canonical loop used by a program using Linenoise will be something like
82this:
83
84 while((line = linenoise("hello> ")) != NULL) {
85 printf("You wrote: %s\n", line);
86 linenoiseFree(line); /* Or just free(line) if you use libc malloc. */
87 }
88
89## Single line VS multi line editing
90
91By default, Linenoise uses single line editing, that is, a single row on the
92screen will be used, and as the user types more, the text will scroll towards
93left to make room. This works if your program is one where the user is
94unlikely to write a lot of text, otherwise multi line editing, where multiple
95screens rows are used, can be a lot more comfortable.
96
97In order to enable multi line editing use the following API call:
98
99 linenoiseSetMultiLine(1);
100
101You can disable it using `0` as argument.
102
103## History
104
105Linenoise supporst history, so that the user does not have to retype
106again and again the same things, but can use the down and up arrows in order
107to search and re-edit already inserted lines of text.
108
109The followings are the history API calls:
110
111 int linenoiseHistoryAdd(const char *line, int is_sensitive);
112 int linenoiseHistorySetMaxLen(int len);
113 int linenoiseHistorySave(const char *filename);
114 int linenoiseHistoryLoad(const char *filename);
115
116Use `linenoiseHistoryAdd` every time you want to add a new element
117to the top of the history (it will be the first the user will see when
118using the up arrow).
119
120Note that for history to work, you have to set a length for the history
121(which is zero by default, so history will be disabled if you don't set
122a proper one). This is accomplished using the `linenoiseHistorySetMaxLen`
123function.
124
125Linenoise has direct support for persisting the history into an history
126file. The functions `linenoiseHistorySave` and `linenoiseHistoryLoad` do
127just that. Both functions return -1 on error and 0 on success.
128
129## Mask mode
130
131Sometimes it is useful to allow the user to type passwords or other
132secrets that should not be displayed. For such situations linenoise supports
133a "mask mode" that will just replace the characters the user is typing
134with `*` characters, like in the following example:
135
136 $ ./linenoise_example
137 hello> get mykey
138 echo: 'get mykey'
139 hello> /mask
140 hello> *********
141
142You can enable and disable mask mode using the following two functions:
143
144 void linenoiseMaskModeEnable(void);
145 void linenoiseMaskModeDisable(void);
146
147## Completion
148
149Linenoise supports completion, which is the ability to complete the user
150input when she or he presses the `<TAB>` key.
151
152In order to use completion, you need to register a completion callback, which
153is called every time the user presses `<TAB>`. Your callback will return a
154list of items that are completions for the current string.
155
156The following is an example of registering a completion callback:
157
158 linenoiseSetCompletionCallback(completion);
159
160The completion must be a function returning `void` and getting as input
161a `const char` pointer, which is the line the user has typed so far, and
162a `linenoiseCompletions` object pointer, which is used as argument of
163`linenoiseAddCompletion` in order to add completions inside the callback.
164An example will make it more clear:
165
166 void completion(const char *buf, linenoiseCompletions *lc) {
167 if (buf[0] == 'h') {
168 linenoiseAddCompletion(lc,"hello");
169 linenoiseAddCompletion(lc,"hello there");
170 }
171 }
172
173Basically in your completion callback, you inspect the input, and return
174a list of items that are good completions by using `linenoiseAddCompletion`.
175
176If you want to test the completion feature, compile the example program
177with `make`, run it, type `h` and press `<TAB>`.
178
179## Hints
180
181Linenoise has a feature called *hints* which is very useful when you
182use Linenoise in order to implement a REPL (Read Eval Print Loop) for
183a program that accepts commands and arguments, but may also be useful in
184other conditions.
185
186The feature shows, on the right of the cursor, as the user types, hints that
187may be useful. The hints can be displayed using a different color compared
188to the color the user is typing, and can also be bold.
189
190For example as the user starts to type `"git remote add"`, with hints it's
191possible to show on the right of the prompt a string `<name> <url>`.
192
193The feature works similarly to the history feature, using a callback.
194To register the callback we use:
195
196 linenoiseSetHintsCallback(hints);
197
198The callback itself is implemented like this:
199
200 char *hints(const char *buf, int *color, int *bold) {
201 if (!strcasecmp(buf,"git remote add")) {
202 *color = 35;
203 *bold = 0;
204 return " <name> <url>";
205 }
206 return NULL;
207 }
208
209The callback function returns the string that should be displayed or NULL
210if no hint is available for the text the user currently typed. The returned
211string will be trimmed as needed depending on the number of columns available
212on the screen.
213
214It is possible to return a string allocated in dynamic way, by also registering
215a function to deallocate the hint string once used:
216
217 void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
218
219The free hint callback will just receive the pointer and free the string
220as needed (depending on how the hits callback allocated it).
221
222As you can see in the example above, a `color` (in xterm color terminal codes)
223can be provided together with a `bold` attribute. If no color is set, the
224current terminal foreground color is used. If no bold attribute is set,
225non-bold text is printed.
226
227Color codes are:
228
229 red = 31
230 green = 32
231 yellow = 33
232 blue = 34
233 magenta = 35
234 cyan = 36
235 white = 37;
236
237## Screen handling
238
239Sometimes you may want to clear the screen as a result of something the
240user typed. You can do this by calling the following function:
241
242 void linenoiseClearScreen(void);
243
244## Related projects
245
246* [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.
247* [Linenoise-swift](https://github.com/andybest/linenoise-swift) is a reimplementation of Linenoise written in Swift.
diff --git a/examples/redis-unstable/deps/linenoise/example.c b/examples/redis-unstable/deps/linenoise/example.c
new file mode 100644
index 0000000..74358c3
--- /dev/null
+++ b/examples/redis-unstable/deps/linenoise/example.c
@@ -0,0 +1,79 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include "linenoise.h"
5
6
7void completion(const char *buf, linenoiseCompletions *lc) {
8 if (buf[0] == 'h') {
9 linenoiseAddCompletion(lc,"hello");
10 linenoiseAddCompletion(lc,"hello there");
11 }
12}
13
14char *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
23int main(int argc, char **argv) {
24 char *line;
25 char *prgname = argv[0];
26
27 /* Parse options, with --multiline we enable multi line editing. */
28 while(argc > 1) {
29 argc--;
30 argv++;
31 if (!strcmp(*argv,"--multiline")) {
32 linenoiseSetMultiLine(1);
33 printf("Multi-line mode enabled.\n");
34 } else if (!strcmp(*argv,"--keycodes")) {
35 linenoisePrintKeyCodes();
36 exit(0);
37 } else {
38 fprintf(stderr, "Usage: %s [--multiline] [--keycodes]\n", prgname);
39 exit(1);
40 }
41 }
42
43 /* Set the completion callback. This will be called every time the
44 * user uses the <tab> key. */
45 linenoiseSetCompletionCallback(completion);
46 linenoiseSetHintsCallback(hints);
47
48 /* Load history from file. The history file is just a plain text file
49 * where entries are separated by newlines. */
50 linenoiseHistoryLoad("history.txt"); /* Load the history at startup */
51
52 /* Now this is the main loop of the typical linenoise-based application.
53 * The call to linenoise() will block as long as the user types something
54 * and presses enter.
55 *
56 * The typed string is returned as a malloc() allocated string by
57 * linenoise, so the user needs to free() it. */
58
59 while((line = linenoise("hello> ")) != NULL) {
60 /* Do something with the string. */
61 if (line[0] != '\0' && line[0] != '/') {
62 printf("echo: '%s'\n", line);
63 linenoiseHistoryAdd(line); /* Add to the history. */
64 linenoiseHistorySave("history.txt"); /* Save the history on disk. */
65 } else if (!strncmp(line,"/historylen",11)) {
66 /* The "/historylen" command will change the history len. */
67 int len = atoi(line+11);
68 linenoiseHistorySetMaxLen(len);
69 } else if (!strncmp(line, "/mask", 5)) {
70 linenoiseMaskModeEnable();
71 } else if (!strncmp(line, "/unmask", 7)) {
72 linenoiseMaskModeDisable();
73 } else if (line[0] == '/') {
74 printf("Unreconized command: %s\n", line);
75 }
76 free(line);
77 }
78 return 0;
79}
diff --git a/examples/redis-unstable/deps/linenoise/linenoise.c b/examples/redis-unstable/deps/linenoise/linenoise.c
new file mode 100644
index 0000000..c0934f3
--- /dev/null
+++ b/examples/redis-unstable/deps/linenoise/linenoise.c
@@ -0,0 +1,1457 @@
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-2016, Salvatore Sanfilippo <antirez at gmail dot com>
14 * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
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+<char> 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#define _DEFAULT_SOURCE /* For fchmod() */
107#define _BSD_SOURCE /* For fchmod() */
108#include <termios.h>
109#include <unistd.h>
110#include <stdlib.h>
111#include <stdio.h>
112#include <errno.h>
113#include <string.h>
114#include <stdlib.h>
115#include <ctype.h>
116#include <sys/stat.h>
117#include <sys/types.h>
118#include <sys/ioctl.h>
119#include <unistd.h>
120#include <assert.h>
121#include "linenoise.h"
122
123#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
124#define LINENOISE_MAX_LINE 4096
125static char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
126static linenoiseCompletionCallback *completionCallback = NULL;
127static linenoiseHintsCallback *hintsCallback = NULL;
128static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
129
130static struct termios orig_termios; /* In order to restore at exit.*/
131static int maskmode = 0; /* Show "***" instead of input. For passwords. */
132static int rawmode = 0; /* For atexit() function to check if restore is needed*/
133static int mlmode = 0; /* Multi line mode. Default is single line. */
134static int atexit_registered = 0; /* Register atexit just 1 time. */
135static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
136static int history_len = 0;
137static char **history = NULL;
138static int *history_sensitive = NULL; /* An array records whether each line in
139 * history is sensitive. */
140
141static int reverse_search_mode_enabled = 0;
142static int reverse_search_direction = 0; /* 1 means forward, -1 means backward. */
143static int cycle_to_next_search = 0; /* indicates whether to continue the search with CTRL+S or CTRL+R. */
144static char search_result[LINENOISE_MAX_LINE];
145static char search_result_friendly[LINENOISE_MAX_LINE];
146static int search_result_history_index = 0;
147static int search_result_start_offset = 0;
148static int ignore_once_hint = 0; /* Flag to ignore hint once, preventing it from interfering
149 * with search results right after exiting search mode. */
150
151/* The linenoiseState structure represents the state during line editing.
152 * We pass this state to functions implementing specific editing
153 * functionalities. */
154struct linenoiseState {
155 int ifd; /* Terminal stdin file descriptor. */
156 int ofd; /* Terminal stdout file descriptor. */
157 char *buf; /* Edited line buffer. */
158 size_t buflen; /* Edited line buffer size. */
159 const char *origin_prompt; /* Original prompt, used to restore when exiting search mode. */
160 const char *prompt; /* Prompt to display. */
161 size_t plen; /* Prompt length. */
162 size_t pos; /* Current cursor position. */
163 size_t oldpos; /* Previous refresh cursor position. */
164 size_t len; /* Current edited line length. */
165 size_t cols; /* Number of columns in terminal. */
166 size_t maxrows; /* Maximum num of rows used so far (multiline mode) */
167 int history_index; /* The history index we are currently editing. */
168};
169
170typedef struct {
171 int len; /* Length of the result string. */
172 char *result; /* Search result string. */
173 int search_term_index; /* Position of the search term in the history record. */
174 int search_term_len; /* Length of the search term. */
175} linenoiseHistorySearchResult;
176
177enum KEY_ACTION{
178 KEY_NULL = 0, /* NULL */
179 CTRL_A = 1, /* Ctrl+a */
180 CTRL_B = 2, /* Ctrl-b */
181 CTRL_C = 3, /* Ctrl-c */
182 CTRL_D = 4, /* Ctrl-d */
183 CTRL_E = 5, /* Ctrl-e */
184 CTRL_F = 6, /* Ctrl-f */
185 CTRL_G = 7, /* Ctrl-g */
186 CTRL_H = 8, /* Ctrl-h */
187 TAB = 9, /* Tab */
188 NL = 10, /* Enter typed before raw mode was enabled */
189 CTRL_K = 11, /* Ctrl+k */
190 CTRL_L = 12, /* Ctrl+l */
191 ENTER = 13, /* Enter */
192 CTRL_N = 14, /* Ctrl-n */
193 CTRL_P = 16, /* Ctrl-p */
194 CTRL_R = 18, /* Ctrl-r */
195 CTRL_S = 19, /* Ctrl-s */
196 CTRL_T = 20, /* Ctrl-t */
197 CTRL_U = 21, /* Ctrl+u */
198 CTRL_W = 23, /* Ctrl+w */
199 ESC = 27, /* Escape */
200 BACKSPACE = 127 /* Backspace */
201};
202
203static void linenoiseAtExit(void);
204int linenoiseHistoryAdd(const char *line, int is_sensitive);
205static void refreshLine(struct linenoiseState *l);
206static void refreshSearchResult(struct linenoiseState *ls);
207
208static inline void resetSearchResult(void) {
209 memset(search_result, 0, sizeof(search_result));
210 memset(search_result_friendly, 0, sizeof(search_result_friendly));
211}
212
213/* Debugging macro. */
214#if 0
215FILE *lndebug_fp = NULL;
216#define lndebug(...) \
217 do { \
218 if (lndebug_fp == NULL) { \
219 lndebug_fp = fopen("/tmp/lndebug.txt","a"); \
220 fprintf(lndebug_fp, \
221 "[%d %d %d] p: %d, rows: %d, rpos: %d, max: %d, oldmax: %d\n", \
222 (int)l->len,(int)l->pos,(int)l->oldpos,plen,rows,rpos, \
223 (int)l->maxrows,old_rows); \
224 } \
225 fprintf(lndebug_fp, ", " __VA_ARGS__); \
226 fflush(lndebug_fp); \
227 } while (0)
228#else
229#define lndebug(fmt, ...)
230#endif
231
232/* ======================= Low level terminal handling ====================== */
233
234/* Enable "mask mode". When it is enabled, instead of the input that
235 * the user is typing, the terminal will just display a corresponding
236 * number of asterisks, like "****". This is useful for passwords and other
237 * secrets that should not be displayed. */
238void linenoiseMaskModeEnable(void) {
239 maskmode = 1;
240}
241
242/* Disable mask mode. */
243void linenoiseMaskModeDisable(void) {
244 maskmode = 0;
245}
246
247/* Set if to use or not the multi line mode. */
248void linenoiseSetMultiLine(int ml) {
249 mlmode = ml;
250}
251
252#define REVERSE_SEARCH_PROMPT(direction) ((direction) == -1 ? "(reverse-i-search): " : "(i-search): ")
253
254/* Enables the reverse search mode and refreshes the prompt. */
255static void enableReverseSearchMode(struct linenoiseState *l) {
256 assert(reverse_search_mode_enabled != 1);
257 reverse_search_mode_enabled = 1;
258 l->origin_prompt = l->prompt;
259 l->prompt = REVERSE_SEARCH_PROMPT(reverse_search_direction);
260 refreshLine(l);
261}
262
263/* This function disables the reverse search mode and returns the terminal to its original state.
264 * If the 'discard' parameter is true, it discards the user's input search keyword and search result.
265 * Otherwise, it copies the search result into 'buf', If there is no search result, it copies the
266 * input search keyword instead. */
267static void disableReverseSearchMode(struct linenoiseState *l, char *buf, size_t buflen, int discard) {
268 if (discard) {
269 buf[0] = '\0';
270 l->pos = l->len = 0;
271 } else {
272 ignore_once_hint = 1;
273 if (strlen(search_result)) {
274 strncpy(buf, search_result, buflen);
275 buf[buflen-1] = '\0';
276 l->pos = l->len = strlen(buf);
277 }
278 }
279
280 /* Reset the state to non-search state. */
281 reverse_search_mode_enabled = 0;
282 l->prompt = l->origin_prompt;
283 resetSearchResult();
284 refreshLine(l);
285}
286
287/* Return true if the terminal name is in the list of terminals we know are
288 * not able to understand basic escape sequences. */
289static int isUnsupportedTerm(void) {
290 char *term = getenv("TERM");
291 int j;
292
293 if (term == NULL) return 0;
294 for (j = 0; unsupported_term[j]; j++)
295 if (!strcasecmp(term,unsupported_term[j])) return 1;
296 return 0;
297}
298
299/* Raw mode: 1960's magic. */
300static int enableRawMode(int fd) {
301 if (getenv("FAKETTY_WITH_PROMPT") != NULL) {
302 return 0;
303 }
304
305 struct termios raw;
306
307 if (!isatty(STDIN_FILENO)) goto fatal;
308 if (!atexit_registered) {
309 atexit(linenoiseAtExit);
310 atexit_registered = 1;
311 }
312 if (tcgetattr(fd,&orig_termios) == -1) goto fatal;
313
314 raw = orig_termios; /* modify the original mode */
315 /* input modes: no break, no CR to NL, no parity check, no strip char,
316 * no start/stop output control. */
317 raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
318 /* output modes - disable post processing */
319 raw.c_oflag &= ~(OPOST);
320 /* control modes - set 8 bit chars */
321 raw.c_cflag |= (CS8);
322 /* local modes - choing off, canonical off, no extended functions,
323 * no signal chars (^Z,^C) */
324 raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
325 /* control chars - set return condition: min number of bytes and timer.
326 * We want read to return every single byte, without timeout. */
327 raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
328
329 /* put terminal in raw mode */
330 if (tcsetattr(fd,TCSANOW,&raw) < 0) goto fatal;
331 rawmode = 1;
332 return 0;
333
334fatal:
335 errno = ENOTTY;
336 return -1;
337}
338
339static void disableRawMode(int fd) {
340 /* Don't even check the return value as it's too late. */
341 if (rawmode && tcsetattr(fd,TCSANOW,&orig_termios) != -1)
342 rawmode = 0;
343}
344
345/* Use the ESC [6n escape sequence to query the horizontal cursor position
346 * and return it. On error -1 is returned, on success the position of the
347 * cursor. */
348static int getCursorPosition(int ifd, int ofd) {
349 char buf[32];
350 int cols, rows;
351 unsigned int i = 0;
352
353 /* Report cursor location */
354 if (write(ofd, "\x1b[6n", 4) != 4) return -1;
355
356 /* Read the response: ESC [ rows ; cols R */
357 while (i < sizeof(buf)-1) {
358 if (read(ifd,buf+i,1) != 1) break;
359 if (buf[i] == 'R') break;
360 i++;
361 }
362 buf[i] = '\0';
363
364 /* Parse it. */
365 if (buf[0] != ESC || buf[1] != '[') return -1;
366 if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1;
367 return cols;
368}
369
370/* Try to get the number of columns in the current terminal, or assume 80
371 * if it fails. */
372static int getColumns(int ifd, int ofd) {
373 if (getenv("FAKETTY_WITH_PROMPT") != NULL) {
374 goto failed;
375 }
376 struct winsize ws;
377
378 if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
379 /* ioctl() failed. Try to query the terminal itself. */
380 int start, cols;
381
382 /* Get the initial position so we can restore it later. */
383 start = getCursorPosition(ifd,ofd);
384 if (start == -1) goto failed;
385
386 /* Go to right margin and get position. */
387 if (write(ofd,"\x1b[999C",6) != 6) goto failed;
388 cols = getCursorPosition(ifd,ofd);
389 if (cols == -1) goto failed;
390
391 /* Restore position. */
392 if (cols > start) {
393 char seq[32];
394 snprintf(seq,32,"\x1b[%dD",cols-start);
395 if (write(ofd,seq,strlen(seq)) == -1) {
396 /* Can't recover... */
397 }
398 }
399 return cols;
400 } else {
401 return ws.ws_col;
402 }
403
404failed:
405 return 80;
406}
407
408/* Clear the screen. Used to handle ctrl+l */
409void linenoiseClearScreen(void) {
410 if (write(STDOUT_FILENO,"\x1b[H\x1b[2J",7) <= 0) {
411 /* nothing to do, just to avoid warning. */
412 }
413}
414
415/* Beep, used for completion when there is nothing to complete or when all
416 * the choices were already shown. */
417static void linenoiseBeep(void) {
418 fprintf(stderr, "\x7");
419 fflush(stderr);
420}
421
422/* ============================== Completion ================================ */
423
424/* Free a list of completion option populated by linenoiseAddCompletion(). */
425static void freeCompletions(linenoiseCompletions *lc) {
426 size_t i;
427 for (i = 0; i < lc->len; i++)
428 free(lc->cvec[i]);
429 if (lc->cvec != NULL)
430 free(lc->cvec);
431}
432
433/* This is an helper function for linenoiseEdit() and is called when the
434 * user types the <tab> key in order to complete the string currently in the
435 * input.
436 *
437 * The state of the editing is encapsulated into the pointed linenoiseState
438 * structure as described in the structure definition. */
439static int completeLine(struct linenoiseState *ls) {
440 linenoiseCompletions lc = { 0, NULL };
441 int nread, nwritten;
442 char c = 0;
443
444 completionCallback(ls->buf,&lc);
445 if (lc.len == 0) {
446 linenoiseBeep();
447 } else {
448 size_t stop = 0, i = 0;
449
450 while(!stop) {
451 /* Show completion or original buffer */
452 if (i < lc.len) {
453 struct linenoiseState saved = *ls;
454
455 ls->len = ls->pos = strlen(lc.cvec[i]);
456 ls->buf = lc.cvec[i];
457 refreshLine(ls);
458 ls->len = saved.len;
459 ls->pos = saved.pos;
460 ls->buf = saved.buf;
461 } else {
462 refreshLine(ls);
463 }
464
465 nread = read(ls->ifd,&c,1);
466 if (nread <= 0) {
467 freeCompletions(&lc);
468 return -1;
469 }
470
471 switch(c) {
472 case 9: /* tab */
473 i = (i+1) % (lc.len+1);
474 if (i == lc.len) linenoiseBeep();
475 break;
476 case 27: /* escape */
477 /* Re-show original buffer */
478 if (i < lc.len) refreshLine(ls);
479 stop = 1;
480 break;
481 default:
482 /* Update buffer and return */
483 if (i < lc.len) {
484 nwritten = snprintf(ls->buf,ls->buflen,"%s",lc.cvec[i]);
485 ls->len = ls->pos = nwritten;
486 }
487 stop = 1;
488 break;
489 }
490 }
491 }
492
493 freeCompletions(&lc);
494 return c; /* Return last read character */
495}
496
497/* Register a callback function to be called for tab-completion. */
498void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
499 completionCallback = fn;
500}
501
502/* Register a hits function to be called to show hits to the user at the
503 * right of the prompt. */
504void linenoiseSetHintsCallback(linenoiseHintsCallback *fn) {
505 hintsCallback = fn;
506}
507
508/* Register a function to free the hints returned by the hints callback
509 * registered with linenoiseSetHintsCallback(). */
510void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn) {
511 freeHintsCallback = fn;
512}
513
514/* This function is used by the callback function registered by the user
515 * in order to add completion options given the input string when the
516 * user typed <tab>. See the example.c source code for a very easy to
517 * understand example. */
518void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
519 size_t len = strlen(str);
520 char *copy, **cvec;
521
522 copy = malloc(len+1);
523 if (copy == NULL) return;
524 memcpy(copy,str,len+1);
525 cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1));
526 if (cvec == NULL) {
527 free(copy);
528 return;
529 }
530 lc->cvec = cvec;
531 lc->cvec[lc->len++] = copy;
532}
533
534/* =========================== Line editing ================================= */
535
536/* We define a very simple "append buffer" structure, that is an heap
537 * allocated string where we can append to. This is useful in order to
538 * write all the escape sequences in a buffer and flush them to the standard
539 * output in a single call, to avoid flickering effects. */
540struct abuf {
541 char *b;
542 int len;
543};
544
545static void abInit(struct abuf *ab) {
546 ab->b = NULL;
547 ab->len = 0;
548}
549
550static void abAppend(struct abuf *ab, const char *s, int len) {
551 char *new = realloc(ab->b,ab->len+len);
552
553 if (new == NULL) return;
554 memcpy(new+ab->len,s,len);
555 ab->b = new;
556 ab->len += len;
557}
558
559static void abFree(struct abuf *ab) {
560 free(ab->b);
561}
562
563/* Helper of refreshSingleLine() and refreshMultiLine() to show hints
564 * to the right of the prompt. */
565void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) {
566 char seq[64];
567
568 /* Show hits when not in reverse search mode and not instructed to ignore once. */
569 if (reverse_search_mode_enabled || ignore_once_hint) {
570 ignore_once_hint = 0;
571 return;
572 }
573
574 if (hintsCallback && plen+l->len < l->cols) {
575 int color = -1, bold = 0;
576 char *hint = hintsCallback(l->buf,&color,&bold);
577 if (hint) {
578 int hintlen = strlen(hint);
579 int hintmaxlen = l->cols-(plen+l->len);
580 if (hintlen > hintmaxlen) hintlen = hintmaxlen;
581 if (bold == 1 && color == -1) color = 37;
582 if (color != -1 || bold != 0)
583 snprintf(seq,64,"\033[%d;%d;49m",bold,color);
584 else
585 seq[0] = '\0';
586 abAppend(ab,seq,strlen(seq));
587 abAppend(ab,hint,hintlen);
588 if (color != -1 || bold != 0)
589 abAppend(ab,"\033[0m",4);
590 /* Call the function to free the hint returned. */
591 if (freeHintsCallback) freeHintsCallback(hint);
592 }
593 }
594}
595
596/* Single line low level line refresh.
597 *
598 * Rewrite the currently edited line accordingly to the buffer content,
599 * cursor position, and number of columns of the terminal. */
600static void refreshSingleLine(struct linenoiseState *l) {
601 char seq[64];
602 size_t plen = strlen(l->prompt);
603 int fd = l->ofd;
604 char *buf = l->buf;
605 size_t len = l->len;
606 size_t pos = l->pos;
607 struct abuf ab;
608
609 while((plen+pos) >= l->cols) {
610 buf++;
611 len--;
612 pos--;
613 }
614 while (plen+len > l->cols) {
615 len--;
616 }
617
618 abInit(&ab);
619 /* Cursor to left edge */
620 snprintf(seq,64,"\r");
621 abAppend(&ab,seq,strlen(seq));
622 /* Write the prompt and the current buffer content */
623 abAppend(&ab,l->prompt,strlen(l->prompt));
624 if (maskmode == 1) {
625 while (len--) abAppend(&ab,"*",1);
626 } else {
627 abAppend(&ab,buf,len);
628 }
629 /* Show hits if any. */
630 refreshShowHints(&ab,l,plen);
631 /* Erase to right */
632 snprintf(seq,64,"\x1b[0K");
633 abAppend(&ab,seq,strlen(seq));
634 /* Move cursor to original position. */
635 snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen));
636 abAppend(&ab,seq,strlen(seq));
637 if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
638 abFree(&ab);
639}
640
641/* Multi line low level line refresh.
642 *
643 * Rewrite the currently edited line accordingly to the buffer content,
644 * cursor position, and number of columns of the terminal. */
645static void refreshMultiLine(struct linenoiseState *l) {
646 char seq[64];
647 int plen = strlen(l->prompt);
648 int rows = (plen+l->len+l->cols-1)/l->cols; /* rows used by current buf. */
649 int rpos = (plen+l->oldpos+l->cols)/l->cols; /* cursor relative row. */
650 int rpos2; /* rpos after refresh. */
651 int col; /* colum position, zero-based. */
652 int old_rows = l->maxrows;
653 int fd = l->ofd, j;
654 struct abuf ab;
655
656 /* Update maxrows if needed. */
657 if (rows > (int)l->maxrows) l->maxrows = rows;
658
659 /* First step: clear all the lines used before. To do so start by
660 * going to the last row. */
661 abInit(&ab);
662 if (old_rows-rpos > 0) {
663 lndebug("go down %d", old_rows-rpos);
664 snprintf(seq,64,"\x1b[%dB", old_rows-rpos);
665 abAppend(&ab,seq,strlen(seq));
666 }
667
668 /* Now for every row clear it, go up. */
669 for (j = 0; j < old_rows-1; j++) {
670 lndebug("clear+up");
671 snprintf(seq,64,"\r\x1b[0K\x1b[1A");
672 abAppend(&ab,seq,strlen(seq));
673 }
674
675 /* Clean the top line. */
676 lndebug("clear");
677 snprintf(seq,64,"\r\x1b[0K");
678 abAppend(&ab,seq,strlen(seq));
679
680 /* Write the prompt and the current buffer content */
681 abAppend(&ab,l->prompt,strlen(l->prompt));
682 if (maskmode == 1) {
683 unsigned int i;
684 for (i = 0; i < l->len; i++) abAppend(&ab,"*",1);
685 } else {
686 refreshSearchResult(l);
687 if (strlen(search_result) > 0) {
688 abAppend(&ab, search_result_friendly, strlen(search_result_friendly));
689 } else {
690 abAppend(&ab,l->buf,l->len);
691 }
692 }
693
694 /* Show hits if any. */
695 refreshShowHints(&ab,l,plen);
696
697 /* If we are at the very end of the screen with our prompt, we need to
698 * emit a newline and move the prompt to the first column. */
699 if (l->pos &&
700 l->pos == l->len &&
701 (l->pos+plen) % l->cols == 0)
702 {
703 lndebug("<newline>");
704 abAppend(&ab,"\n",1);
705 snprintf(seq,64,"\r");
706 abAppend(&ab,seq,strlen(seq));
707 rows++;
708 if (rows > (int)l->maxrows) l->maxrows = rows;
709 }
710
711 /* Move cursor to right position. */
712 rpos2 = (plen+l->pos+l->cols)/l->cols; /* current cursor relative row. */
713 lndebug("rpos2 %d", rpos2);
714
715 /* Go up till we reach the expected position. */
716 if (rows-rpos2 > 0) {
717 lndebug("go-up %d", rows-rpos2);
718 snprintf(seq,64,"\x1b[%dA", rows-rpos2);
719 abAppend(&ab,seq,strlen(seq));
720 }
721
722 /* Set column. */
723 col = (plen+(int)l->pos) % (int)l->cols;
724 if (strlen(search_result) > 0) {
725 col += search_result_start_offset;
726 }
727 lndebug("set col %d", 1+col);
728 if (col)
729 snprintf(seq,64,"\r\x1b[%dC", col);
730 else
731 snprintf(seq,64,"\r");
732 abAppend(&ab,seq,strlen(seq));
733
734 lndebug("\n");
735 l->oldpos = l->pos;
736
737 if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
738 abFree(&ab);
739}
740
741/* Calls the two low level functions refreshSingleLine() or
742 * refreshMultiLine() according to the selected mode. */
743static void refreshLine(struct linenoiseState *l) {
744 if (mlmode)
745 refreshMultiLine(l);
746 else
747 refreshSingleLine(l);
748}
749
750/* Insert the character 'c' at cursor current position.
751 *
752 * On error writing to the terminal -1 is returned, otherwise 0. */
753int linenoiseEditInsert(struct linenoiseState *l, char c) {
754 if (l->len < l->buflen) {
755 if (l->len == l->pos) {
756 l->buf[l->pos] = c;
757 l->pos++;
758 l->len++;
759 l->buf[l->len] = '\0';
760 if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) {
761 /* Avoid a full update of the line in the
762 * trivial case. */
763 char d = (maskmode==1) ? '*' : c;
764 if (write(l->ofd,&d,1) == -1) return -1;
765 } else {
766 refreshLine(l);
767 }
768 } else {
769 memmove(l->buf+l->pos+1,l->buf+l->pos,l->len-l->pos);
770 l->buf[l->pos] = c;
771 l->len++;
772 l->pos++;
773 l->buf[l->len] = '\0';
774 refreshLine(l);
775 }
776 }
777 return 0;
778}
779
780/* Move cursor on the left. */
781void linenoiseEditMoveLeft(struct linenoiseState *l) {
782 if (l->pos > 0) {
783 l->pos--;
784 refreshLine(l);
785 }
786}
787
788/* Move cursor on the right. */
789void linenoiseEditMoveRight(struct linenoiseState *l) {
790 if (l->pos != l->len) {
791 l->pos++;
792 refreshLine(l);
793 }
794}
795
796/* Move cursor to the start of the line. */
797void linenoiseEditMoveHome(struct linenoiseState *l) {
798 if (l->pos != 0) {
799 l->pos = 0;
800 refreshLine(l);
801 }
802}
803
804/* Move cursor to the end of the line. */
805void linenoiseEditMoveEnd(struct linenoiseState *l) {
806 if (l->pos != l->len) {
807 l->pos = l->len;
808 refreshLine(l);
809 }
810}
811
812/* Substitute the currently edited line with the next or previous history
813 * entry as specified by 'dir'. */
814#define LINENOISE_HISTORY_NEXT 0
815#define LINENOISE_HISTORY_PREV 1
816void linenoiseEditHistoryNext(struct linenoiseState *l, int dir) {
817 if (history_len > 1) {
818 /* Update the current history entry before to
819 * overwrite it with the next one. */
820 free(history[history_len - 1 - l->history_index]);
821 history[history_len - 1 - l->history_index] = strdup(l->buf);
822 /* Show the new entry */
823 l->history_index += (dir == LINENOISE_HISTORY_PREV) ? 1 : -1;
824 if (l->history_index < 0) {
825 l->history_index = 0;
826 return;
827 } else if (l->history_index >= history_len) {
828 l->history_index = history_len-1;
829 return;
830 }
831 strncpy(l->buf,history[history_len - 1 - l->history_index],l->buflen);
832 l->buf[l->buflen-1] = '\0';
833 l->len = l->pos = strlen(l->buf);
834 refreshLine(l);
835 }
836}
837
838/* Delete the character at the right of the cursor without altering the cursor
839 * position. Basically this is what happens with the "Delete" keyboard key. */
840void linenoiseEditDelete(struct linenoiseState *l) {
841 if (l->len > 0 && l->pos < l->len) {
842 memmove(l->buf+l->pos,l->buf+l->pos+1,l->len-l->pos-1);
843 l->len--;
844 l->buf[l->len] = '\0';
845 refreshLine(l);
846 }
847}
848
849/* Backspace implementation. */
850void linenoiseEditBackspace(struct linenoiseState *l) {
851 if (l->pos > 0 && l->len > 0) {
852 memmove(l->buf+l->pos-1,l->buf+l->pos,l->len-l->pos);
853 l->pos--;
854 l->len--;
855 l->buf[l->len] = '\0';
856 refreshLine(l);
857 }
858}
859
860/* Delete the previous word, maintaining the cursor at the start of the
861 * current word. */
862void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
863 size_t old_pos = l->pos;
864 size_t diff;
865
866 while (l->pos > 0 && l->buf[l->pos-1] == ' ')
867 l->pos--;
868 while (l->pos > 0 && l->buf[l->pos-1] != ' ')
869 l->pos--;
870 diff = old_pos - l->pos;
871 memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1);
872 l->len -= diff;
873 refreshLine(l);
874}
875
876/* This function is the core of the line editing capability of linenoise.
877 * It expects 'fd' to be already in "raw mode" so that every key pressed
878 * will be returned ASAP to read().
879 *
880 * The resulting string is put into 'buf' when the user type enter, or
881 * when ctrl+d is typed.
882 *
883 * The function returns the length of the current buffer. */
884static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt)
885{
886 struct linenoiseState l;
887
888 /* Populate the linenoise state that we pass to functions implementing
889 * specific editing functionalities. */
890 l.ifd = stdin_fd;
891 l.ofd = stdout_fd;
892 l.buf = buf;
893 l.buflen = buflen;
894 l.prompt = prompt;
895 l.plen = strlen(prompt);
896 l.oldpos = l.pos = 0;
897 l.len = 0;
898 l.cols = getColumns(stdin_fd, stdout_fd);
899 l.maxrows = 0;
900 l.history_index = 0;
901
902 /* Buffer starts empty. */
903 l.buf[0] = '\0';
904 l.buflen--; /* Make sure there is always space for the nulterm */
905
906 /* The latest history entry is always our current buffer, that
907 * initially is just an empty string. */
908 linenoiseHistoryAdd("", 0);
909
910 if (write(l.ofd,prompt,l.plen) == -1) return -1;
911 while(1) {
912 char c;
913 int nread;
914 char seq[3];
915
916 nread = read(l.ifd,&c,1);
917 if (nread <= 0) return l.len;
918
919 /* Only autocomplete when the callback is set. It returns < 0 when
920 * there was an error reading from fd. Otherwise it will return the
921 * character that should be handled next. */
922 if (c == TAB && completionCallback != NULL && !reverse_search_mode_enabled) {
923 c = completeLine(&l);
924 /* Return on errors */
925 if (c < 0) return l.len;
926 /* Read next character when 0 */
927 if (c == 0) continue;
928 }
929
930 switch(c) {
931 case NL: /* enter, typed before raw mode was enabled */
932 break;
933 case TAB:
934 if (reverse_search_mode_enabled) disableReverseSearchMode(&l, buf, buflen, 0);
935 break;
936 case ENTER: /* enter */
937 history_len--;
938 free(history[history_len]);
939 if (mlmode) linenoiseEditMoveEnd(&l);
940 if (hintsCallback) {
941 /* Force a refresh without hints to leave the previous
942 * line as the user typed it after a newline. */
943 linenoiseHintsCallback *hc = hintsCallback;
944 hintsCallback = NULL;
945 refreshLine(&l);
946 hintsCallback = hc;
947 }
948
949 if (reverse_search_mode_enabled) disableReverseSearchMode(&l, buf, buflen, 0);
950 return (int)l.len;
951 case CTRL_C: /* ctrl-c */
952 if (reverse_search_mode_enabled) {
953 disableReverseSearchMode(&l, buf, buflen, 1);
954 break;
955 }
956 errno = EAGAIN;
957 return -1;
958 case BACKSPACE: /* backspace */
959 case 8: /* ctrl-h */
960 linenoiseEditBackspace(&l);
961 break;
962 case CTRL_D: /* ctrl-d, remove char at right of cursor, or if the
963 line is empty, act as end-of-file. */
964 if (l.len > 0) {
965 linenoiseEditDelete(&l);
966 } else {
967 history_len--;
968 free(history[history_len]);
969 return -1;
970 }
971 break;
972 case CTRL_T: /* ctrl-t, swaps current character with previous. */
973 if (l.pos > 0 && l.pos < l.len) {
974 int aux = buf[l.pos-1];
975 buf[l.pos-1] = buf[l.pos];
976 buf[l.pos] = aux;
977 if (l.pos != l.len-1) l.pos++;
978 refreshLine(&l);
979 }
980 break;
981 case CTRL_B: /* ctrl-b */
982 linenoiseEditMoveLeft(&l);
983 break;
984 case CTRL_F: /* ctrl-f */
985 linenoiseEditMoveRight(&l);
986 break;
987 case CTRL_P: /* ctrl-p */
988 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
989 break;
990 case CTRL_R:
991 case CTRL_S:
992 reverse_search_direction = c == CTRL_R ? -1 : 1;
993 if (reverse_search_mode_enabled) {
994 /* cycle search results */
995 cycle_to_next_search = 1;
996 l.prompt = REVERSE_SEARCH_PROMPT(reverse_search_direction);
997 refreshLine(&l);
998 break;
999 }
1000 buf[0] = '\0';
1001 l.pos = l.len = 0;
1002 enableReverseSearchMode(&l);
1003 break;
1004 case CTRL_G:
1005 if (reverse_search_mode_enabled) disableReverseSearchMode(&l, buf, buflen, 1);
1006 break;
1007 case CTRL_N: /* ctrl-n */
1008 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
1009 break;
1010 case ESC: /* escape sequence */
1011 /* Read the next two bytes representing the escape sequence.
1012 * Use two calls to handle slow terminals returning the two
1013 * chars at different times. */
1014 if (read(l.ifd,seq,1) == -1) break;
1015 if (read(l.ifd,seq+1,1) == -1) break;
1016
1017 if (reverse_search_mode_enabled) {
1018 disableReverseSearchMode(&l, buf, buflen, 1);
1019 break;
1020 }
1021
1022 /* ESC [ sequences. */
1023 if (seq[0] == '[') {
1024 if (seq[1] >= '0' && seq[1] <= '9') {
1025 /* Extended escape, read additional byte. */
1026 if (read(l.ifd,seq+2,1) == -1) break;
1027 if (seq[2] == '~') {
1028 switch(seq[1]) {
1029 case '3': /* Delete key. */
1030 linenoiseEditDelete(&l);
1031 break;
1032 }
1033 }
1034 } else {
1035 switch(seq[1]) {
1036 case 'A': /* Up */
1037 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
1038 break;
1039 case 'B': /* Down */
1040 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
1041 break;
1042 case 'C': /* Right */
1043 linenoiseEditMoveRight(&l);
1044 break;
1045 case 'D': /* Left */
1046 linenoiseEditMoveLeft(&l);
1047 break;
1048 case 'H': /* Home */
1049 linenoiseEditMoveHome(&l);
1050 break;
1051 case 'F': /* End*/
1052 linenoiseEditMoveEnd(&l);
1053 break;
1054 }
1055 }
1056 }
1057
1058 /* ESC O sequences. */
1059 else if (seq[0] == 'O') {
1060 switch(seq[1]) {
1061 case 'H': /* Home */
1062 linenoiseEditMoveHome(&l);
1063 break;
1064 case 'F': /* End*/
1065 linenoiseEditMoveEnd(&l);
1066 break;
1067 }
1068 }
1069 break;
1070 default:
1071 if (linenoiseEditInsert(&l,c)) return -1;
1072 break;
1073 case CTRL_U: /* Ctrl+u, delete the whole line. */
1074 buf[0] = '\0';
1075 l.pos = l.len = 0;
1076 refreshLine(&l);
1077 break;
1078 case CTRL_K: /* Ctrl+k, delete from current to end of line. */
1079 buf[l.pos] = '\0';
1080 l.len = l.pos;
1081 refreshLine(&l);
1082 break;
1083 case CTRL_A: /* Ctrl+a, go to the start of the line */
1084 linenoiseEditMoveHome(&l);
1085 break;
1086 case CTRL_E: /* ctrl+e, go to the end of the line */
1087 linenoiseEditMoveEnd(&l);
1088 break;
1089 case CTRL_L: /* ctrl+l, clear screen */
1090 linenoiseClearScreen();
1091 refreshLine(&l);
1092 break;
1093 case CTRL_W: /* ctrl+w, delete previous word */
1094 linenoiseEditDeletePrevWord(&l);
1095 break;
1096 }
1097 }
1098 return l.len;
1099}
1100
1101/* This special mode is used by linenoise in order to print scan codes
1102 * on screen for debugging / development purposes. It is implemented
1103 * by the linenoise_example program using the --keycodes option. */
1104void linenoisePrintKeyCodes(void) {
1105 char quit[4];
1106
1107 printf("Linenoise key codes debugging mode.\n"
1108 "Press keys to see scan codes. Type 'quit' at any time to exit.\n");
1109 if (enableRawMode(STDIN_FILENO) == -1) return;
1110 memset(quit,' ',4);
1111 while(1) {
1112 char c;
1113 int nread;
1114
1115 nread = read(STDIN_FILENO,&c,1);
1116 if (nread <= 0) continue;
1117 memmove(quit,quit+1,sizeof(quit)-1); /* shift string to left. */
1118 quit[sizeof(quit)-1] = c; /* Insert current char on the right. */
1119 if (memcmp(quit,"quit",sizeof(quit)) == 0) break;
1120
1121 printf("'%c' %02x (%d) (type quit to exit)\n",
1122 isprint(c) ? c : '?', (int)c, (int)c);
1123 printf("\r"); /* Go left edge manually, we are in raw mode. */
1124 fflush(stdout);
1125 }
1126 disableRawMode(STDIN_FILENO);
1127}
1128
1129/* This function calls the line editing function linenoiseEdit() using
1130 * the STDIN file descriptor set in raw mode. */
1131static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
1132 int count;
1133
1134 if (buflen == 0) {
1135 errno = EINVAL;
1136 return -1;
1137 }
1138
1139 if (enableRawMode(STDIN_FILENO) == -1) return -1;
1140 count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt);
1141 disableRawMode(STDIN_FILENO);
1142 printf("\n");
1143 return count;
1144}
1145
1146/* This function is called when linenoise() is called with the standard
1147 * input file descriptor not attached to a TTY. So for example when the
1148 * program using linenoise is called in pipe or with a file redirected
1149 * to its standard input. In this case, we want to be able to return the
1150 * line regardless of its length (by default we are limited to 4k). */
1151static char *linenoiseNoTTY(void) {
1152 char *line = NULL;
1153 size_t len = 0, maxlen = 0;
1154
1155 while(1) {
1156 if (len == maxlen) {
1157 if (maxlen == 0) maxlen = 16;
1158 maxlen *= 2;
1159 char *oldval = line;
1160 line = realloc(line,maxlen);
1161 if (line == NULL) {
1162 if (oldval) free(oldval);
1163 return NULL;
1164 }
1165 }
1166 int c = fgetc(stdin);
1167 if (c == EOF || c == '\n') {
1168 if (c == EOF && len == 0) {
1169 free(line);
1170 return NULL;
1171 } else {
1172 line[len] = '\0';
1173 return line;
1174 }
1175 } else {
1176 line[len] = c;
1177 len++;
1178 }
1179 }
1180}
1181
1182/* The high level function that is the main API of the linenoise library.
1183 * This function checks if the terminal has basic capabilities, just checking
1184 * for a blacklist of stupid terminals, and later either calls the line
1185 * editing function or uses dummy fgets() so that you will be able to type
1186 * something even in the most desperate of the conditions. */
1187char *linenoise(const char *prompt) {
1188 char buf[LINENOISE_MAX_LINE] = {0};
1189 int count;
1190
1191 if (getenv("FAKETTY_WITH_PROMPT") == NULL && !isatty(STDIN_FILENO)) {
1192 /* Not a tty: read from file / pipe. In this mode we don't want any
1193 * limit to the line size, so we call a function to handle that. */
1194 return linenoiseNoTTY();
1195 } else if (getenv("FAKETTY_WITH_PROMPT") == NULL && isUnsupportedTerm()) {
1196 size_t len;
1197
1198 printf("%s",prompt);
1199 fflush(stdout);
1200 if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL;
1201 len = strlen(buf);
1202 while(len && (buf[len-1] == '\n' || buf[len-1] == '\r')) {
1203 len--;
1204 buf[len] = '\0';
1205 }
1206 return strdup(buf);
1207 } else {
1208 count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt);
1209 if (count == -1) return NULL;
1210 return strdup(buf);
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. */
1218void linenoiseFree(void *ptr) {
1219 free(ptr);
1220}
1221
1222/* ================================ History ================================= */
1223
1224/* Free the history, but does not reset it. Only used when we have to
1225 * exit() to avoid memory leaks are reported by valgrind & co. */
1226static void freeHistory(void) {
1227 if (history) {
1228 int j;
1229
1230 for (j = 0; j < history_len; j++)
1231 free(history[j]);
1232 free(history);
1233 free(history_sensitive);
1234 }
1235}
1236
1237/* At exit we'll try to fix the terminal to the initial conditions. */
1238static 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. */
1250int linenoiseHistoryAdd(const char *line, int is_sensitive) {
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 history_sensitive = malloc(sizeof(int)*history_max_len);
1260 if (history_sensitive == NULL) {
1261 free(history);
1262 history = NULL;
1263 return 0;
1264 }
1265 memset(history,0,(sizeof(char*)*history_max_len));
1266 memset(history_sensitive,0,(sizeof(int)*history_max_len));
1267 }
1268
1269 /* Don't add duplicated lines. */
1270 if (history_len && !strcmp(history[history_len-1], line)) return 0;
1271
1272 /* Add an heap allocated copy of the line in the history.
1273 * If we reached the max length, remove the older line. */
1274 linecopy = strdup(line);
1275 if (!linecopy) return 0;
1276 if (history_len == history_max_len) {
1277 free(history[0]);
1278 memmove(history,history+1,sizeof(char*)*(history_max_len-1));
1279 memmove(history_sensitive,history_sensitive+1,sizeof(int)*(history_max_len-1));
1280 history_len--;
1281 }
1282 history[history_len] = linecopy;
1283 history_sensitive[history_len] = is_sensitive;
1284 history_len++;
1285 return 1;
1286}
1287
1288/* Set the maximum length for the history. This function can be called even
1289 * if there is already some history, the function will make sure to retain
1290 * just the latest 'len' elements if the new history length value is smaller
1291 * than the amount of items already inside the history. */
1292int linenoiseHistorySetMaxLen(int len) {
1293 char **new;
1294 int *new_sensitive;
1295
1296 if (len < 1) return 0;
1297 if (history) {
1298 int tocopy = history_len;
1299
1300 new = malloc(sizeof(char*)*len);
1301 if (new == NULL) return 0;
1302 new_sensitive = malloc(sizeof(int)*len);
1303 if (new_sensitive == NULL) {
1304 free(new);
1305 return 0;
1306 }
1307
1308 /* If we can't copy everything, free the elements we'll not use. */
1309 if (len < tocopy) {
1310 int j;
1311
1312 for (j = 0; j < tocopy-len; j++) free(history[j]);
1313 tocopy = len;
1314 }
1315 memset(new,0,sizeof(char*)*len);
1316 memset(new_sensitive,0,sizeof(int)*len);
1317 memcpy(new,history+(history_len-tocopy), sizeof(char*)*tocopy);
1318 memcpy(new_sensitive,history_sensitive+(history_len-tocopy), sizeof(int)*tocopy);
1319 free(history);
1320 free(history_sensitive);
1321 history = new;
1322 history_sensitive = new_sensitive;
1323 }
1324 history_max_len = len;
1325 if (history_len > history_max_len)
1326 history_len = history_max_len;
1327 return 1;
1328}
1329
1330/* Save the history in the specified file. On success 0 is returned
1331 * otherwise -1 is returned. */
1332int linenoiseHistorySave(const char *filename) {
1333 mode_t old_umask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
1334 FILE *fp;
1335 int j;
1336
1337 fp = fopen(filename,"w");
1338 umask(old_umask);
1339 if (fp == NULL) return -1;
1340 fchmod(fileno(fp),S_IRUSR|S_IWUSR);
1341 for (j = 0; j < history_len; j++)
1342 if (!history_sensitive[j]) fprintf(fp,"%s\n",history[j]);
1343 fclose(fp);
1344 return 0;
1345}
1346
1347/* Load the history from the specified file. If the file does not exist
1348 * zero is returned and no operation is performed.
1349 *
1350 * If the file exists and the operation succeeded 0 is returned, otherwise
1351 * on error -1 is returned. */
1352int linenoiseHistoryLoad(const char *filename) {
1353 FILE *fp = fopen(filename,"r");
1354 char buf[LINENOISE_MAX_LINE];
1355
1356 if (fp == NULL) return -1;
1357
1358 while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) {
1359 char *p;
1360
1361 p = strchr(buf,'\r');
1362 if (!p) p = strchr(buf,'\n');
1363 if (p) *p = '\0';
1364 linenoiseHistoryAdd(buf, 0);
1365 }
1366 fclose(fp);
1367 return 0;
1368}
1369
1370/* This function updates the search index based on the direction of the search.
1371 * Returns 0 if the beginning or end of the history is reached, otherwise, returns 1. */
1372static int setNextSearchIndex(int *i) {
1373 if (reverse_search_direction == 1) {
1374 if (*i == history_len-1) return 0;
1375 *i = *i + 1;
1376 } else {
1377 if (*i <= 0) return 0;
1378 *i = *i - 1;
1379 }
1380 return 1;
1381}
1382
1383linenoiseHistorySearchResult searchInHistory(char *search_term) {
1384 linenoiseHistorySearchResult result = {0};
1385
1386 if (!history_len || !strlen(search_term)) return result;
1387
1388 int i = cycle_to_next_search ? search_result_history_index :
1389 (reverse_search_direction == -1 ? history_len-1 : 0);
1390
1391 while (1) {
1392 char *found = strstr(history[i], search_term);
1393
1394 /* check if we found the same string at another index when cycling, this would be annoying to cycle through
1395 * as it might appear that cycling isn't working */
1396 int strings_are_the_same = cycle_to_next_search && strcmp(history[i], history[search_result_history_index]) == 0;
1397
1398 if (found && !strings_are_the_same) {
1399 int haystack_index = found - history[i];
1400 result.result = history[i];
1401 result.len = strlen(history[i]);
1402 result.search_term_index = haystack_index;
1403 result.search_term_len = strlen(search_term);
1404 search_result_history_index = i;
1405 break;
1406 }
1407
1408 /* Exit if reached the end. */
1409 if (!setNextSearchIndex(&i)) break;
1410 }
1411
1412 return result;
1413}
1414
1415static void refreshSearchResult(struct linenoiseState *ls) {
1416 if (!reverse_search_mode_enabled) {
1417 return;
1418 }
1419
1420 linenoiseHistorySearchResult sr = searchInHistory(ls->buf);
1421 int found = sr.result && sr.len;
1422
1423 /* If the search term has not changed and we are cycling to the next search result
1424 * (using CTRL+R or CTRL+S), there is no need to reset the old search result. */
1425 if (!cycle_to_next_search || found)
1426 resetSearchResult();
1427 cycle_to_next_search = 0;
1428
1429 if (found) {
1430 char *bold = "\x1B[1m";
1431 char *normal = "\x1B[0m";
1432
1433 int size_needed = sr.search_term_index + sr.search_term_len + sr.len -
1434 (sr.search_term_index+sr.search_term_len) + sizeof(normal) + sizeof(bold) + sizeof(normal);
1435 if (size_needed > sizeof(search_result_friendly) - 1) {
1436 return;
1437 }
1438
1439 /* Allocate memory for the prefix, match, and suffix strings, one extra byte for `\0`. */
1440 char *prefix = calloc(sizeof(char), sr.search_term_index + 1);
1441 char *match = calloc(sizeof(char), sr.search_term_len + 1);
1442 char *suffix = calloc(sizeof(char), sr.len - (sr.search_term_index+sr.search_term_len) + 1);
1443
1444 memcpy(prefix, sr.result, sr.search_term_index);
1445 memcpy(match, sr.result + sr.search_term_index, sr.search_term_len);
1446 memcpy(suffix, sr.result + sr.search_term_index + sr.search_term_len,
1447 sr.len - (sr.search_term_index+sr.search_term_len));
1448 sprintf(search_result, "%s%s%s", prefix, match, suffix);
1449 sprintf(search_result_friendly, "%s%s%s%s%s%s", normal, prefix, bold, match, normal, suffix);
1450
1451 free(prefix);
1452 free(match);
1453 free(suffix);
1454
1455 search_result_start_offset = sr.search_term_index;
1456 }
1457}
diff --git a/examples/redis-unstable/deps/linenoise/linenoise.h b/examples/redis-unstable/deps/linenoise/linenoise.h
new file mode 100644
index 0000000..beac6df
--- /dev/null
+++ b/examples/redis-unstable/deps/linenoise/linenoise.h
@@ -0,0 +1,75 @@
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-2014, Salvatore Sanfilippo <antirez at gmail dot com>
11 * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
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
43extern "C" {
44#endif
45
46typedef struct linenoiseCompletions {
47 size_t len;
48 char **cvec;
49} linenoiseCompletions;
50
51typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
52typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold);
53typedef void(linenoiseFreeHintsCallback)(void *);
54void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
55void linenoiseSetHintsCallback(linenoiseHintsCallback *);
56void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
57void linenoiseAddCompletion(linenoiseCompletions *, const char *);
58
59char *linenoise(const char *prompt);
60void linenoiseFree(void *ptr);
61int linenoiseHistoryAdd(const char *line, int is_sensitive);
62int linenoiseHistorySetMaxLen(int len);
63int linenoiseHistorySave(const char *filename);
64int linenoiseHistoryLoad(const char *filename);
65void linenoiseClearScreen(void);
66void linenoiseSetMultiLine(int ml);
67void linenoisePrintKeyCodes(void);
68void linenoiseMaskModeEnable(void);
69void linenoiseMaskModeDisable(void);
70
71#ifdef __cplusplus
72}
73#endif
74
75#endif /* __LINENOISE_H */