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 #include <unistd.h>
107 #include <stdlib.h>
108 #include <stdio.h>
109 #include <stdio_ext.h>
110 #include <errno.h>
111 #include <string.h>
112 #include <stdlib.h>
113 #include <ctype.h>
114 #include <sys/stat.h>
115 #include <sys/types.h>
116 #include <sys/fcntl.h>
117 #include <unistd.h>
118 #include "linenoise.h"
119 
120 #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
121 #define LINENOISE_MAX_LINE 4096
122 
123 static linenoiseCompletionCallback *completionCallback = NULL;
124 static linenoiseHintsCallback *hintsCallback = NULL;
125 static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
126 
127 static int mlmode = 0;  /* Multi line mode. Default is single line. */
128 static int dumbmode = 0; /* Dumb mode where line editing is disabled. Off by default */
129 static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
130 static int history_len = 0;
131 static char **history = NULL;
132 static bool allow_empty = true;
133 
134 /* The linenoiseState structure represents the state during line editing.
135  * We pass this state to functions implementing specific editing
136  * functionalities. */
137 struct linenoiseState {
138     char *buf;          /* Edited line buffer. */
139     size_t buflen;      /* Edited line buffer size. */
140     const char *prompt; /* Prompt to display. */
141     size_t plen;        /* Prompt length. */
142     size_t pos;         /* Current cursor position. */
143     size_t oldpos;      /* Previous refresh cursor position. */
144     size_t len;         /* Current edited line length. */
145     size_t cols;        /* Number of columns in terminal. */
146     size_t maxrows;     /* Maximum num of rows used so far (multiline mode) */
147     int history_index;  /* The history index we are currently editing. */
148 };
149 
150 enum KEY_ACTION{
151 	KEY_NULL = 0,	    /* NULL */
152 	CTRL_A = 1,         /* Ctrl+a */
153 	CTRL_B = 2,         /* Ctrl-b */
154 	CTRL_C = 3,         /* Ctrl-c */
155 	CTRL_D = 4,         /* Ctrl-d */
156 	CTRL_E = 5,         /* Ctrl-e */
157 	CTRL_F = 6,         /* Ctrl-f */
158 	CTRL_H = 8,         /* Ctrl-h */
159 	TAB = 9,            /* Tab */
160 	CTRL_K = 11,        /* Ctrl+k */
161 	CTRL_L = 12,        /* Ctrl+l */
162 	ENTER = 10,         /* Enter */
163 	CTRL_N = 14,        /* Ctrl-n */
164 	CTRL_P = 16,        /* Ctrl-p */
165 	CTRL_T = 20,        /* Ctrl-t */
166 	CTRL_U = 21,        /* Ctrl+u */
167 	CTRL_W = 23,        /* Ctrl+w */
168 	ESC = 27,           /* Escape */
169 	BACKSPACE =  127    /* Backspace */
170 };
171 
172 int linenoiseHistoryAdd(const char *line);
173 static void refreshLine(struct linenoiseState *l);
174 
175 /* Debugging macro. */
176 #if 0
177 FILE *lndebug_fp = NULL;
178 #define lndebug(...) \
179     do { \
180         if (lndebug_fp == NULL) { \
181             lndebug_fp = fopen("/tmp/lndebug.txt","a"); \
182             fprintf(lndebug_fp, \
183             "[%d %d %d] p: %d, rows: %d, rpos: %d, max: %d, oldmax: %d\n", \
184             (int)l->len,(int)l->pos,(int)l->oldpos,plen,rows,rpos, \
185             (int)l->maxrows,old_rows); \
186         } \
187         fprintf(lndebug_fp, ", " __VA_ARGS__); \
188         fflush(lndebug_fp); \
189     } while (0)
190 #else
191 #define lndebug(fmt, ...)
192 #endif
193 
194 /* ======================= Low level terminal handling ====================== */
195 
196 /* Set if to use or not the multi line mode. */
linenoiseSetMultiLine(int ml)197 void linenoiseSetMultiLine(int ml) {
198     mlmode = ml;
199 }
200 
201 /* Set if terminal does not recognize escape sequences */
linenoiseSetDumbMode(int set)202 void linenoiseSetDumbMode(int set) {
203     dumbmode = set;
204 }
205 
flushWrite(void)206 static void flushWrite(void) {
207     if (__fbufsize(stdout) > 0) {
208         fflush(stdout);
209     }
210     fsync(fileno(stdout));
211 }
212 
213 /* Use the ESC [6n escape sequence to query the horizontal cursor position
214  * and return it. On error -1 is returned, on success the position of the
215  * cursor. */
getCursorPosition(void)216 static int getCursorPosition(void) {
217     char buf[32];
218     int cols, rows;
219     unsigned int i = 0;
220 
221     /* Report cursor location */
222     fprintf(stdout, "\x1b[6n");
223     flushWrite();
224     /* Read the response: ESC [ rows ; cols R */
225     while (i < sizeof(buf)-1) {
226         if (fread(buf+i, 1, 1, stdin) != 1) break;
227         if (buf[i] == 'R') break;
228         i++;
229     }
230     buf[i] = '\0';
231     /* Parse it. */
232     if (buf[0] != ESC || buf[1] != '[') return -1;
233     if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1;
234     return cols;
235 }
236 
237 /* Try to get the number of columns in the current terminal, or assume 80
238  * if it fails. */
getColumns(void)239 static int getColumns(void) {
240     int start, cols;
241     int fd = fileno(stdout);
242 
243     /* Get the initial position so we can restore it later. */
244     start = getCursorPosition();
245     if (start == -1) goto failed;
246 
247     /* Go to right margin and get position. */
248     if (fwrite("\x1b[999C", 1, 6, stdout) != 6) goto failed;
249     flushWrite();
250     cols = getCursorPosition();
251     if (cols == -1) goto failed;
252 
253     /* Restore position. */
254     if (cols > start) {
255         char seq[32];
256         snprintf(seq,32,"\x1b[%dD",cols-start);
257         if (write(fd, seq, strlen(seq)) == -1) {
258             /* Can't recover... */
259         }
260         flushWrite();
261     }
262     return cols;
263 
264 failed:
265     return 80;
266 }
267 
268 /* Clear the screen. Used to handle ctrl+l */
linenoiseClearScreen(void)269 void linenoiseClearScreen(void) {
270     fprintf(stdout,"\x1b[H\x1b[2J");
271     flushWrite();
272 }
273 
274 /* Beep, used for completion when there is nothing to complete or when all
275  * the choices were already shown. */
linenoiseBeep(void)276 static void linenoiseBeep(void) {
277     fprintf(stdout, "\x7");
278     flushWrite();
279 }
280 
281 /* ============================== Completion ================================ */
282 
283 /* Free a list of completion option populated by linenoiseAddCompletion(). */
freeCompletions(linenoiseCompletions * lc)284 static void freeCompletions(linenoiseCompletions *lc) {
285     size_t i;
286     for (i = 0; i < lc->len; i++)
287         free(lc->cvec[i]);
288     if (lc->cvec != NULL)
289         free(lc->cvec);
290 }
291 
292 /* This is an helper function for linenoiseEdit() and is called when the
293  * user types the <tab> key in order to complete the string currently in the
294  * input.
295  *
296  * The state of the editing is encapsulated into the pointed linenoiseState
297  * structure as described in the structure definition. */
completeLine(struct linenoiseState * ls)298 static int completeLine(struct linenoiseState *ls) {
299     linenoiseCompletions lc = { 0, NULL };
300     int nread, nwritten;
301     char c = 0;
302     int in_fd = fileno(stdin);
303 
304     completionCallback(ls->buf,&lc);
305     if (lc.len == 0) {
306         linenoiseBeep();
307     } else {
308         size_t stop = 0, i = 0;
309 
310         while(!stop) {
311             /* Show completion or original buffer */
312             if (i < lc.len) {
313                 struct linenoiseState saved = *ls;
314 
315                 ls->len = ls->pos = strlen(lc.cvec[i]);
316                 ls->buf = lc.cvec[i];
317                 refreshLine(ls);
318                 ls->len = saved.len;
319                 ls->pos = saved.pos;
320                 ls->buf = saved.buf;
321             } else {
322                 refreshLine(ls);
323             }
324 
325             nread = read(in_fd, &c, 1);
326             if (nread <= 0) {
327                 freeCompletions(&lc);
328                 return -1;
329             }
330 
331             switch(c) {
332                 case TAB: /* tab */
333                     i = (i+1) % (lc.len+1);
334                     if (i == lc.len) linenoiseBeep();
335                     break;
336                 case ESC: /* escape */
337                     /* Re-show original buffer */
338                     if (i < lc.len) refreshLine(ls);
339                     stop = 1;
340                     break;
341                 default:
342                     /* Update buffer and return */
343                     if (i < lc.len) {
344                         nwritten = snprintf(ls->buf,ls->buflen,"%s",lc.cvec[i]);
345                         ls->len = ls->pos = nwritten;
346                     }
347                     stop = 1;
348                     break;
349             }
350         }
351     }
352 
353     freeCompletions(&lc);
354     return c; /* Return last read character */
355 }
356 
357 /* Register a callback function to be called for tab-completion. */
linenoiseSetCompletionCallback(linenoiseCompletionCallback * fn)358 void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
359     completionCallback = fn;
360 }
361 
362 /* Register a hits function to be called to show hits to the user at the
363  * right of the prompt. */
linenoiseSetHintsCallback(linenoiseHintsCallback * fn)364 void linenoiseSetHintsCallback(linenoiseHintsCallback *fn) {
365     hintsCallback = fn;
366 }
367 
368 /* Register a function to free the hints returned by the hints callback
369  * registered with linenoiseSetHintsCallback(). */
linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback * fn)370 void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn) {
371     freeHintsCallback = fn;
372 }
373 
374 /* This function is used by the callback function registered by the user
375  * in order to add completion options given the input string when the
376  * user typed <tab>. See the example.c source code for a very easy to
377  * understand example. */
linenoiseAddCompletion(linenoiseCompletions * lc,const char * str)378 void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
379     size_t len = strlen(str);
380     char *copy, **cvec;
381 
382     copy = malloc(len+1);
383     if (copy == NULL) return;
384     memcpy(copy,str,len+1);
385     cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1));
386     if (cvec == NULL) {
387         free(copy);
388         return;
389     }
390     lc->cvec = cvec;
391     lc->cvec[lc->len++] = copy;
392 }
393 
394 /* =========================== Line editing ================================= */
395 
396 /* We define a very simple "append buffer" structure, that is an heap
397  * allocated string where we can append to. This is useful in order to
398  * write all the escape sequences in a buffer and flush them to the standard
399  * output in a single call, to avoid flickering effects. */
400 struct abuf {
401     char *b;
402     int len;
403 };
404 
abInit(struct abuf * ab)405 static void abInit(struct abuf *ab) {
406     ab->b = NULL;
407     ab->len = 0;
408 }
409 
abAppend(struct abuf * ab,const char * s,int len)410 static void abAppend(struct abuf *ab, const char *s, int len) {
411     char *new = realloc(ab->b,ab->len+len);
412 
413     if (new == NULL) return;
414     memcpy(new+ab->len,s,len);
415     ab->b = new;
416     ab->len += len;
417 }
418 
abFree(struct abuf * ab)419 static void abFree(struct abuf *ab) {
420     free(ab->b);
421 }
422 
423 /* Helper of refreshSingleLine() and refreshMultiLine() to show hints
424  * to the right of the prompt. */
refreshShowHints(struct abuf * ab,struct linenoiseState * l,int plen)425 void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) {
426     char seq[64];
427     if (hintsCallback && plen+l->len < l->cols) {
428         int color = -1, bold = 0;
429         char *hint = hintsCallback(l->buf,&color,&bold);
430         if (hint) {
431             int hintlen = strlen(hint);
432             int hintmaxlen = l->cols-(plen+l->len);
433             if (hintlen > hintmaxlen) hintlen = hintmaxlen;
434             if (bold == 1 && color == -1) color = 37;
435             if (color != -1 || bold != 0)
436                 snprintf(seq,64,"\033[%d;%d;49m",bold,color);
437             abAppend(ab,seq,strlen(seq));
438             abAppend(ab,hint,hintlen);
439             if (color != -1 || bold != 0)
440                 abAppend(ab,"\033[0m",4);
441             /* Call the function to free the hint returned. */
442             if (freeHintsCallback) freeHintsCallback(hint);
443         }
444     }
445 }
446 
447 /* Single line low level line refresh.
448  *
449  * Rewrite the currently edited line accordingly to the buffer content,
450  * cursor position, and number of columns of the terminal. */
refreshSingleLine(struct linenoiseState * l)451 static void refreshSingleLine(struct linenoiseState *l) {
452     char seq[64];
453     size_t plen = l->plen;
454     int fd = fileno(stdout);
455     char *buf = l->buf;
456     size_t len = l->len;
457     size_t pos = l->pos;
458     struct abuf ab;
459 
460     while((plen+pos) >= l->cols) {
461         buf++;
462         len--;
463         pos--;
464     }
465     while (plen+len > l->cols) {
466         len--;
467     }
468 
469     abInit(&ab);
470     /* Cursor to left edge */
471     snprintf(seq,64,"\r");
472     abAppend(&ab,seq,strlen(seq));
473     /* Write the prompt and the current buffer content */
474     abAppend(&ab,l->prompt,strlen(l->prompt));
475     abAppend(&ab,buf,len);
476     /* Show hits if any. */
477     refreshShowHints(&ab,l,plen);
478     /* Erase to right */
479     snprintf(seq,64,"\x1b[0K");
480     abAppend(&ab,seq,strlen(seq));
481     /* Move cursor to original position. */
482     snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen));
483     abAppend(&ab,seq,strlen(seq));
484     if (write(fd, ab.b, ab.len) == -1) {} /* Can't recover from write error. */
485     flushWrite();
486     abFree(&ab);
487 }
488 
489 /* Multi line low level line refresh.
490  *
491  * Rewrite the currently edited line accordingly to the buffer content,
492  * cursor position, and number of columns of the terminal. */
refreshMultiLine(struct linenoiseState * l)493 static void refreshMultiLine(struct linenoiseState *l) {
494     char seq[64];
495     int plen = l->plen;
496     int rows = (plen+l->len+l->cols-1)/l->cols; /* rows used by current buf. */
497     int rpos = (plen+l->oldpos+l->cols)/l->cols; /* cursor relative row. */
498     int rpos2; /* rpos after refresh. */
499     int col; /* colum position, zero-based. */
500     int old_rows = l->maxrows;
501     int j;
502     int fd = fileno(stdout);
503     struct abuf ab;
504 
505     /* Update maxrows if needed. */
506     if (rows > (int)l->maxrows) l->maxrows = rows;
507 
508     /* First step: clear all the lines used before. To do so start by
509      * going to the last row. */
510     abInit(&ab);
511     if (old_rows-rpos > 0) {
512         lndebug("go down %d", old_rows-rpos);
513         snprintf(seq,64,"\x1b[%dB", old_rows-rpos);
514         abAppend(&ab,seq,strlen(seq));
515     }
516 
517     /* Now for every row clear it, go up. */
518     for (j = 0; j < old_rows-1; j++) {
519         lndebug("clear+up");
520         snprintf(seq,64,"\r\x1b[0K\x1b[1A");
521         abAppend(&ab,seq,strlen(seq));
522     }
523 
524     /* Clean the top line. */
525     lndebug("clear");
526     snprintf(seq,64,"\r\x1b[0K");
527     abAppend(&ab,seq,strlen(seq));
528 
529     /* Write the prompt and the current buffer content */
530     abAppend(&ab,l->prompt,strlen(l->prompt));
531     abAppend(&ab,l->buf,l->len);
532 
533     /* Show hits if any. */
534     refreshShowHints(&ab,l,plen);
535 
536     /* If we are at the very end of the screen with our prompt, we need to
537      * emit a newline and move the prompt to the first column. */
538     if (l->pos &&
539         l->pos == l->len &&
540         (l->pos+plen) % l->cols == 0)
541     {
542         lndebug("<newline>");
543         abAppend(&ab,"\n",1);
544         snprintf(seq,64,"\r");
545         abAppend(&ab,seq,strlen(seq));
546         rows++;
547         if (rows > (int)l->maxrows) l->maxrows = rows;
548     }
549 
550     /* Move cursor to right position. */
551     rpos2 = (plen+l->pos+l->cols)/l->cols; /* current cursor relative row. */
552     lndebug("rpos2 %d", rpos2);
553 
554     /* Go up till we reach the expected positon. */
555     if (rows-rpos2 > 0) {
556         lndebug("go-up %d", rows-rpos2);
557         snprintf(seq,64,"\x1b[%dA", rows-rpos2);
558         abAppend(&ab,seq,strlen(seq));
559     }
560 
561     /* Set column. */
562     col = (plen+(int)l->pos) % (int)l->cols;
563     lndebug("set col %d", 1+col);
564     if (col)
565         snprintf(seq,64,"\r\x1b[%dC", col);
566     else
567         snprintf(seq,64,"\r");
568     abAppend(&ab,seq,strlen(seq));
569 
570     lndebug("\n");
571     l->oldpos = l->pos;
572 
573     if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
574     flushWrite();
575     abFree(&ab);
576 }
577 
578 /* Calls the two low level functions refreshSingleLine() or
579  * refreshMultiLine() according to the selected mode. */
refreshLine(struct linenoiseState * l)580 static void refreshLine(struct linenoiseState *l) {
581     if (mlmode)
582         refreshMultiLine(l);
583     else
584         refreshSingleLine(l);
585 }
586 
587 /* Insert the character 'c' at cursor current position.
588  *
589  * On error writing to the terminal -1 is returned, otherwise 0. */
linenoiseEditInsert(struct linenoiseState * l,char c)590 int linenoiseEditInsert(struct linenoiseState *l, char c) {
591     int fd = fileno(stdout);
592     if (l->len < l->buflen) {
593         if (l->len == l->pos) {
594             l->buf[l->pos] = c;
595             l->pos++;
596             l->len++;
597             l->buf[l->len] = '\0';
598             if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) {
599                 /* Avoid a full update of the line in the
600                  * trivial case. */
601                 if (write(fd, &c,1) == -1) {
602                     return -1;
603                 }
604                 flushWrite();
605             } else {
606                 refreshLine(l);
607             }
608         } else {
609             memmove(l->buf+l->pos+1,l->buf+l->pos,l->len-l->pos);
610             l->buf[l->pos] = c;
611             l->len++;
612             l->pos++;
613             l->buf[l->len] = '\0';
614             refreshLine(l);
615         }
616     }
617     return 0;
618 }
619 
620 /* Move cursor on the left. */
linenoiseEditMoveLeft(struct linenoiseState * l)621 void linenoiseEditMoveLeft(struct linenoiseState *l) {
622     if (l->pos > 0) {
623         l->pos--;
624         refreshLine(l);
625     }
626 }
627 
628 /* Move cursor on the right. */
linenoiseEditMoveRight(struct linenoiseState * l)629 void linenoiseEditMoveRight(struct linenoiseState *l) {
630     if (l->pos != l->len) {
631         l->pos++;
632         refreshLine(l);
633     }
634 }
635 
636 /* Move cursor to the start of the line. */
linenoiseEditMoveHome(struct linenoiseState * l)637 void linenoiseEditMoveHome(struct linenoiseState *l) {
638     if (l->pos != 0) {
639         l->pos = 0;
640         refreshLine(l);
641     }
642 }
643 
644 /* Move cursor to the end of the line. */
linenoiseEditMoveEnd(struct linenoiseState * l)645 void linenoiseEditMoveEnd(struct linenoiseState *l) {
646     if (l->pos != l->len) {
647         l->pos = l->len;
648         refreshLine(l);
649     }
650 }
651 
652 /* Substitute the currently edited line with the next or previous history
653  * entry as specified by 'dir'. */
654 #define LINENOISE_HISTORY_NEXT 0
655 #define LINENOISE_HISTORY_PREV 1
linenoiseEditHistoryNext(struct linenoiseState * l,int dir)656 void linenoiseEditHistoryNext(struct linenoiseState *l, int dir) {
657     if (history_len > 1) {
658         /* Update the current history entry before to
659          * overwrite it with the next one. */
660         free(history[history_len - 1 - l->history_index]);
661         history[history_len - 1 - l->history_index] = strdup(l->buf);
662         /* Show the new entry */
663         l->history_index += (dir == LINENOISE_HISTORY_PREV) ? 1 : -1;
664         if (l->history_index < 0) {
665             l->history_index = 0;
666             return;
667         } else if (l->history_index >= history_len) {
668             l->history_index = history_len-1;
669             return;
670         }
671         strncpy(l->buf,history[history_len - 1 - l->history_index],l->buflen);
672         l->buf[l->buflen-1] = '\0';
673         l->len = l->pos = strlen(l->buf);
674         refreshLine(l);
675     }
676 }
677 
678 /* Delete the character at the right of the cursor without altering the cursor
679  * position. Basically this is what happens with the "Delete" keyboard key. */
linenoiseEditDelete(struct linenoiseState * l)680 void linenoiseEditDelete(struct linenoiseState *l) {
681     if (l->len > 0 && l->pos < l->len) {
682         memmove(l->buf+l->pos,l->buf+l->pos+1,l->len-l->pos-1);
683         l->len--;
684         l->buf[l->len] = '\0';
685         refreshLine(l);
686     }
687 }
688 
689 /* Backspace implementation. */
linenoiseEditBackspace(struct linenoiseState * l)690 void linenoiseEditBackspace(struct linenoiseState *l) {
691     if (l->pos > 0 && l->len > 0) {
692         memmove(l->buf+l->pos-1,l->buf+l->pos,l->len-l->pos);
693         l->pos--;
694         l->len--;
695         l->buf[l->len] = '\0';
696         refreshLine(l);
697     }
698 }
699 
700 /* Delete the previosu word, maintaining the cursor at the start of the
701  * current word. */
linenoiseEditDeletePrevWord(struct linenoiseState * l)702 void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
703     size_t old_pos = l->pos;
704     size_t diff;
705 
706     while (l->pos > 0 && l->buf[l->pos-1] == ' ')
707         l->pos--;
708     while (l->pos > 0 && l->buf[l->pos-1] != ' ')
709         l->pos--;
710     diff = old_pos - l->pos;
711     memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1);
712     l->len -= diff;
713     refreshLine(l);
714 }
715 
716 /* This function is the core of the line editing capability of linenoise.
717  * It expects 'fd' to be already in "raw mode" so that every key pressed
718  * will be returned ASAP to read().
719  *
720  * The resulting string is put into 'buf' when the user type enter, or
721  * when ctrl+d is typed.
722  *
723  * The function returns the length of the current buffer. */
linenoiseEdit(char * buf,size_t buflen,const char * prompt)724 static int linenoiseEdit(char *buf, size_t buflen, const char *prompt)
725 {
726     struct linenoiseState l;
727     int out_fd = fileno(stdout);
728     int in_fd = fileno(stdin);
729 
730     /* Populate the linenoise state that we pass to functions implementing
731      * specific editing functionalities. */
732     l.buf = buf;
733     l.buflen = buflen;
734     l.prompt = prompt;
735     l.plen = strlen(prompt);
736     l.oldpos = l.pos = 0;
737     l.len = 0;
738     l.cols = getColumns();
739     l.maxrows = 0;
740     l.history_index = 0;
741 
742     /* Buffer starts empty. */
743     l.buf[0] = '\0';
744     l.buflen--; /* Make sure there is always space for the nulterm */
745 
746     /* The latest history entry is always our current buffer, that
747      * initially is just an empty string. */
748     linenoiseHistoryAdd("");
749 
750     int pos1 = getCursorPosition();
751     if (write(out_fd, prompt,l.plen) == -1) {
752         return -1;
753     }
754     flushWrite();
755     int pos2 = getCursorPosition();
756     if (pos1 >= 0 && pos2 >= 0) {
757         l.plen = pos2 - pos1;
758     }
759     while(1) {
760         char c;
761         int nread;
762         char seq[3];
763 
764         nread = read(in_fd, &c, 1);
765         if (nread <= 0) return l.len;
766 
767         /* Only autocomplete when the callback is set. It returns < 0 when
768          * there was an error reading from fd. Otherwise it will return the
769          * character that should be handled next. */
770         if (c == 9 && completionCallback != NULL) {
771             int c2 = completeLine(&l);
772             /* Return on errors */
773             if (c2 < 0) return l.len;
774             /* Read next character when 0 */
775             if (c2 == 0) continue;
776             c = c2;
777         }
778 
779         switch(c) {
780         case ENTER:    /* enter */
781             history_len--;
782             free(history[history_len]);
783             if (mlmode) linenoiseEditMoveEnd(&l);
784             if (hintsCallback) {
785                 /* Force a refresh without hints to leave the previous
786                  * line as the user typed it after a newline. */
787                 linenoiseHintsCallback *hc = hintsCallback;
788                 hintsCallback = NULL;
789                 refreshLine(&l);
790                 hintsCallback = hc;
791             }
792             return (int)l.len;
793         case CTRL_C:     /* ctrl-c */
794             errno = EAGAIN;
795             return -1;
796         case BACKSPACE:   /* backspace */
797         case 8:     /* ctrl-h */
798             linenoiseEditBackspace(&l);
799             break;
800         case CTRL_D:     /* ctrl-d, remove char at right of cursor, or if the
801                             line is empty, act as end-of-file. */
802             if (l.len > 0) {
803                 linenoiseEditDelete(&l);
804             } else {
805                 history_len--;
806                 free(history[history_len]);
807                 return -1;
808             }
809             break;
810         case CTRL_T:    /* ctrl-t, swaps current character with previous. */
811             if (l.pos > 0 && l.pos < l.len) {
812                 int aux = buf[l.pos-1];
813                 buf[l.pos-1] = buf[l.pos];
814                 buf[l.pos] = aux;
815                 if (l.pos != l.len-1) l.pos++;
816                 refreshLine(&l);
817             }
818             break;
819         case CTRL_B:     /* ctrl-b */
820             linenoiseEditMoveLeft(&l);
821             break;
822         case CTRL_F:     /* ctrl-f */
823             linenoiseEditMoveRight(&l);
824             break;
825         case CTRL_P:    /* ctrl-p */
826             linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
827             break;
828         case CTRL_N:    /* ctrl-n */
829             linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
830             break;
831         case ESC:    /* escape sequence */
832             /* Read the next two bytes representing the escape sequence. */
833             if (read(in_fd, seq, 2) < 2) {
834                 break;
835             }
836 
837             /* ESC [ sequences. */
838             if (seq[0] == '[') {
839                 if (seq[1] >= '0' && seq[1] <= '9') {
840                     /* Extended escape, read additional byte. */
841                     if (read(in_fd, seq+2, 1) == -1) {
842                         break;
843                     }
844                     if (seq[2] == '~') {
845                         switch(seq[1]) {
846                         case '3': /* Delete key. */
847                             linenoiseEditDelete(&l);
848                             break;
849                         }
850                     }
851                 } else {
852                     switch(seq[1]) {
853                     case 'A': /* Up */
854                         linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
855                         break;
856                     case 'B': /* Down */
857                         linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
858                         break;
859                     case 'C': /* Right */
860                         linenoiseEditMoveRight(&l);
861                         break;
862                     case 'D': /* Left */
863                         linenoiseEditMoveLeft(&l);
864                         break;
865                     case 'H': /* Home */
866                         linenoiseEditMoveHome(&l);
867                         break;
868                     case 'F': /* End*/
869                         linenoiseEditMoveEnd(&l);
870                         break;
871                     }
872                 }
873             }
874 
875             /* ESC O sequences. */
876             else if (seq[0] == 'O') {
877                 switch(seq[1]) {
878                 case 'H': /* Home */
879                     linenoiseEditMoveHome(&l);
880                     break;
881                 case 'F': /* End*/
882                     linenoiseEditMoveEnd(&l);
883                     break;
884                 }
885             }
886             break;
887         default:
888             if (linenoiseEditInsert(&l,c)) return -1;
889             break;
890         case CTRL_U: /* Ctrl+u, delete the whole line. */
891             buf[0] = '\0';
892             l.pos = l.len = 0;
893             refreshLine(&l);
894             break;
895         case CTRL_K: /* Ctrl+k, delete from current to end of line. */
896             buf[l.pos] = '\0';
897             l.len = l.pos;
898             refreshLine(&l);
899             break;
900         case CTRL_A: /* Ctrl+a, go to the start of the line */
901             linenoiseEditMoveHome(&l);
902             break;
903         case CTRL_E: /* ctrl+e, go to the end of the line */
904             linenoiseEditMoveEnd(&l);
905             break;
906         case CTRL_L: /* ctrl+l, clear screen */
907             linenoiseClearScreen();
908             refreshLine(&l);
909             break;
910         case CTRL_W: /* ctrl+w, delete previous word */
911             linenoiseEditDeletePrevWord(&l);
912             break;
913         }
914         flushWrite();
915     }
916     return l.len;
917 }
918 
linenoiseAllowEmpty(bool val)919 void linenoiseAllowEmpty(bool val) {
920     allow_empty = val;
921 }
922 
linenoiseProbe(void)923 int linenoiseProbe(void) {
924     /* Switch to non-blocking mode */
925     int stdin_fileno = fileno(stdin);
926     int flags = fcntl(stdin_fileno, F_GETFL);
927     flags |= O_NONBLOCK;
928     int res = fcntl(stdin_fileno, F_SETFL, flags);
929     if (res != 0) {
930         return -1;
931     }
932     /* Device status request */
933     fprintf(stdout, "\x1b[5n");
934     flushWrite();
935 
936     /* Try to read response */
937     int timeout_ms = 200;
938     const int retry_ms = 10;
939     size_t read_bytes = 0;
940     while (timeout_ms > 0 && read_bytes < 4) { // response is ESC[0n or ESC[3n
941         usleep(retry_ms * 1000);
942         timeout_ms -= retry_ms;
943         char c;
944         int cb = read(stdin_fileno, &c, 1);
945         if (cb < 0) {
946             continue;
947         }
948         read_bytes += cb;
949     }
950     /* Restore old mode */
951     flags &= ~O_NONBLOCK;
952     res = fcntl(stdin_fileno, F_SETFL, flags);
953     if (res != 0) {
954         return -1;
955     }
956     if (read_bytes < 4) {
957         return -2;
958     }
959     return 0;
960 }
961 
linenoiseRaw(char * buf,size_t buflen,const char * prompt)962 static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
963     int count;
964 
965     if (buflen == 0) {
966         errno = EINVAL;
967         return -1;
968     }
969 
970     count = linenoiseEdit(buf, buflen, prompt);
971     fputc('\n', stdout);
972     flushWrite();
973     return count;
974 }
975 
linenoiseDumb(char * buf,size_t buflen,const char * prompt)976 static int linenoiseDumb(char* buf, size_t buflen, const char* prompt) {
977     /* dumb terminal, fall back to fgets */
978     fputs(prompt, stdout);
979     size_t count = 0;
980     while (count < buflen) {
981         int c = fgetc(stdin);
982         if (c == '\n') {
983             break;
984         } else if (c >= 0x1c && c <= 0x1f){
985             continue; /* consume arrow keys */
986         } else if (c == BACKSPACE || c == 0x8) {
987             if (count > 0) {
988                 buf[count - 1] = 0;
989                 count --;
990             }
991             fputs("\x08 ", stdout); /* Windows CMD: erase symbol under cursor */
992         } else {
993             buf[count] = c;
994             ++count;
995         }
996         fputc(c, stdout); /* echo */
997     }
998     fputc('\n', stdout);
999     flushWrite();
1000     return count;
1001 }
1002 
sanitize(char * src)1003 static void sanitize(char* src) {
1004     char* dst = src;
1005     for (int c = *src; c != 0; src++, c = *src) {
1006         if (isprint(c)) {
1007             *dst = c;
1008             ++dst;
1009         }
1010     }
1011     *dst = 0;
1012 }
1013 
1014 /* The high level function that is the main API of the linenoise library. */
linenoise(const char * prompt)1015 char *linenoise(const char *prompt) {
1016     char *buf = calloc(1, LINENOISE_MAX_LINE);
1017     int count = 0;
1018     if (buf == NULL) {
1019         return NULL;
1020     }
1021     if (!dumbmode) {
1022         count = linenoiseRaw(buf, LINENOISE_MAX_LINE, prompt);
1023     } else {
1024         count = linenoiseDumb(buf, LINENOISE_MAX_LINE, prompt);
1025     }
1026     if (count > 0) {
1027         sanitize(buf);
1028         count = strlen(buf);
1029     } else if (count == 0 && allow_empty) {
1030         /* will return an empty (0-length) string */
1031     } else {
1032         free(buf);
1033         return NULL;
1034     }
1035     return buf;
1036 }
1037 
1038 /* This is just a wrapper the user may want to call in order to make sure
1039  * the linenoise returned buffer is freed with the same allocator it was
1040  * created with. Useful when the main program is using an alternative
1041  * allocator. */
linenoiseFree(void * ptr)1042 void linenoiseFree(void *ptr) {
1043     free(ptr);
1044 }
1045 
1046 /* ================================ History ================================= */
1047 
linenoiseHistoryFree(void)1048 void linenoiseHistoryFree(void) {
1049     if (history) {
1050         for (int j = 0; j < history_len; j++) {
1051             free(history[j]);
1052         }
1053         free(history);
1054     }
1055     history = NULL;
1056 }
1057 
1058 /* This is the API call to add a new entry in the linenoise history.
1059  * It uses a fixed array of char pointers that are shifted (memmoved)
1060  * when the history max length is reached in order to remove the older
1061  * entry and make room for the new one, so it is not exactly suitable for huge
1062  * histories, but will work well for a few hundred of entries.
1063  *
1064  * Using a circular buffer is smarter, but a bit more complex to handle. */
linenoiseHistoryAdd(const char * line)1065 int linenoiseHistoryAdd(const char *line) {
1066     char *linecopy;
1067 
1068     if (history_max_len == 0) return 0;
1069 
1070     /* Initialization on first call. */
1071     if (history == NULL) {
1072         history = malloc(sizeof(char*)*history_max_len);
1073         if (history == NULL) return 0;
1074         memset(history,0,(sizeof(char*)*history_max_len));
1075     }
1076 
1077     /* Don't add duplicated lines. */
1078     if (history_len && !strcmp(history[history_len-1], line)) return 0;
1079 
1080     /* Add an heap allocated copy of the line in the history.
1081      * If we reached the max length, remove the older line. */
1082     linecopy = strdup(line);
1083     if (!linecopy) return 0;
1084     if (history_len == history_max_len) {
1085         free(history[0]);
1086         memmove(history,history+1,sizeof(char*)*(history_max_len-1));
1087         history_len--;
1088     }
1089     history[history_len] = linecopy;
1090     history_len++;
1091     return 1;
1092 }
1093 
1094 /* Set the maximum length for the history. This function can be called even
1095  * if there is already some history, the function will make sure to retain
1096  * just the latest 'len' elements if the new history length value is smaller
1097  * than the amount of items already inside the history. */
linenoiseHistorySetMaxLen(int len)1098 int linenoiseHistorySetMaxLen(int len) {
1099     char **new;
1100 
1101     if (len < 1) return 0;
1102     if (history) {
1103         int tocopy = history_len;
1104 
1105         new = malloc(sizeof(char*)*len);
1106         if (new == NULL) return 0;
1107 
1108         /* If we can't copy everything, free the elements we'll not use. */
1109         if (len < tocopy) {
1110             int j;
1111 
1112             for (j = 0; j < tocopy-len; j++) free(history[j]);
1113             tocopy = len;
1114         }
1115         memset(new,0,sizeof(char*)*len);
1116         memcpy(new,history+(history_len-tocopy), sizeof(char*)*tocopy);
1117         free(history);
1118         history = new;
1119     }
1120     history_max_len = len;
1121     if (history_len > history_max_len)
1122         history_len = history_max_len;
1123     return 1;
1124 }
1125 
1126 /* Save the history in the specified file. On success 0 is returned
1127  * otherwise -1 is returned. */
linenoiseHistorySave(const char * filename)1128 int linenoiseHistorySave(const char *filename) {
1129     FILE *fp;
1130     int j;
1131 
1132     fp = fopen(filename,"w");
1133     if (fp == NULL) return -1;
1134     for (j = 0; j < history_len; j++)
1135         fprintf(fp,"%s\n",history[j]);
1136     fclose(fp);
1137     return 0;
1138 }
1139 
1140 /* Load the history from the specified file. If the file does not exist
1141  * zero is returned and no operation is performed.
1142  *
1143  * If the file exists and the operation succeeded 0 is returned, otherwise
1144  * on error -1 is returned. */
linenoiseHistoryLoad(const char * filename)1145 int linenoiseHistoryLoad(const char *filename) {
1146     FILE *fp = fopen(filename,"r");
1147     if (fp == NULL) {
1148         return -1;
1149     }
1150 
1151     char *buf = calloc(1, LINENOISE_MAX_LINE);
1152     if (buf == NULL) {
1153         fclose(fp);
1154         return -1;
1155     }
1156 
1157     while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) {
1158         char *p;
1159 
1160         p = strchr(buf,'\r');
1161         if (!p) p = strchr(buf,'\n');
1162         if (p) *p = '\0';
1163         linenoiseHistoryAdd(buf);
1164     }
1165 
1166     free(buf);
1167     fclose(fp);
1168 
1169     return 0;
1170 }
1171