blob: ade47918870362338bdeb69ad184c61b2bf0fa07 [file] [log] [blame]
Michal Vasko203b4e72015-06-30 15:25:15 +02001/* linenoise.c -- 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 * You can find the latest source code at:
7 *
8 * http://github.com/antirez/linenoise
9 *
10 * Does a number of crazy assumptions that happen to be true in 99.9999% of
11 * the 2010 UNIX computers around.
12 *
13 * ------------------------------------------------------------------------
14 *
15 * Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
16 * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
17 *
18 * All rights reserved.
19 *
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions are
22 * met:
23 *
24 * * Redistributions of source code must retain the above copyright
25 * notice, this list of conditions and the following disclaimer.
26 *
27 * * Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
37 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
38 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
39 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
41 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 *
43 * ------------------------------------------------------------------------
44 *
45 * References:
46 * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
47 * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html
48 *
49 * Todo list:
50 * - Filter bogus Ctrl+<char> combinations.
51 * - Win32 support
52 *
53 * Bloat:
54 * - History search like Ctrl+r in readline?
55 *
56 * List of escape sequences used by this program, we do everything just
57 * with three sequences. In order to be so cheap we may have some
58 * flickering effect with some slow terminal, but the lesser sequences
59 * the more compatible.
60 *
61 * EL (Erase Line)
62 * Sequence: ESC [ n K
63 * Effect: if n is 0 or missing, clear from cursor to end of line
64 * Effect: if n is 1, clear from beginning of line to cursor
65 * Effect: if n is 2, clear entire line
66 *
67 * CUF (CUrsor Forward)
68 * Sequence: ESC [ n C
69 * Effect: moves cursor forward n chars
70 *
71 * CUB (CUrsor Backward)
72 * Sequence: ESC [ n D
73 * Effect: moves cursor backward n chars
74 *
75 * The following is used to get the terminal width if getting
76 * the width with the TIOCGWINSZ ioctl fails
77 *
78 * DSR (Device Status Report)
79 * Sequence: ESC [ 6 n
80 * Effect: reports the current cusor position as ESC [ n ; m R
81 * where n is the row and m is the column
82 *
83 * When multi line mode is enabled, we also use an additional escape
84 * sequence. However multi line editing is disabled by default.
85 *
86 * CUU (Cursor Up)
87 * Sequence: ESC [ n A
88 * Effect: moves cursor up of n chars.
89 *
90 * CUD (Cursor Down)
91 * Sequence: ESC [ n B
92 * Effect: moves cursor down of n chars.
93 *
94 * When linenoiseClearScreen() is called, two additional escape sequences
95 * are used in order to clear the screen and position the cursor at home
96 * position.
97 *
98 * CUP (Cursor position)
99 * Sequence: ESC [ H
100 * Effect: moves the cursor to upper left corner
101 *
102 * ED (Erase display)
103 * Sequence: ESC [ 2 J
104 * Effect: clear the whole screen
105 *
106 */
107
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>
Michal Vasko62056bb2015-12-16 13:24:39 +0100116#include <dirent.h>
Michal Vasko203b4e72015-06-30 15:25:15 +0200117#include <sys/types.h>
118#include <sys/ioctl.h>
Michal Vasko62056bb2015-12-16 13:24:39 +0100119#include <sys/stat.h>
Michal Vasko203b4e72015-06-30 15:25:15 +0200120#include <unistd.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;
127
128static struct termios orig_termios; /* In order to restore at exit.*/
Michal Vasko203b4e72015-06-30 15:25:15 +0200129static int mlmode = 0; /* Multi line mode. Default is single line. */
130static int atexit_registered = 0; /* Register atexit just 1 time. */
131static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
132static int history_len = 0;
133static char **history = NULL;
134
135/* The linenoiseState structure represents the state during line editing.
136 * We pass this state to functions implementing specific editing
137 * functionalities. */
Michal Vasko62056bb2015-12-16 13:24:39 +0100138struct linenoiseState ls;
Michal Vasko203b4e72015-06-30 15:25:15 +0200139
140enum KEY_ACTION{
141 KEY_NULL = 0, /* NULL */
142 CTRL_A = 1, /* Ctrl+a */
143 CTRL_B = 2, /* Ctrl-b */
144 CTRL_C = 3, /* Ctrl-c */
145 CTRL_D = 4, /* Ctrl-d */
146 CTRL_E = 5, /* Ctrl-e */
147 CTRL_F = 6, /* Ctrl-f */
148 CTRL_H = 8, /* Ctrl-h */
149 TAB = 9, /* Tab */
150 CTRL_K = 11, /* Ctrl+k */
151 CTRL_L = 12, /* Ctrl+l */
152 ENTER = 13, /* Enter */
153 CTRL_N = 14, /* Ctrl-n */
154 CTRL_P = 16, /* Ctrl-p */
155 CTRL_T = 20, /* Ctrl-t */
156 CTRL_U = 21, /* Ctrl+u */
157 CTRL_W = 23, /* Ctrl+w */
158 ESC = 27, /* Escape */
159 BACKSPACE = 127 /* Backspace */
160};
161
162static void linenoiseAtExit(void);
163int linenoiseHistoryAdd(const char *line);
Michal Vasko203b4e72015-06-30 15:25:15 +0200164
165/* Debugging macro. */
166#if 0
167FILE *lndebug_fp = NULL;
168#define lndebug(...) \
169 do { \
170 if (lndebug_fp == NULL) { \
171 lndebug_fp = fopen("/tmp/lndebug.txt","a"); \
172 fprintf(lndebug_fp, \
173 "[%d %d %d] p: %d, rows: %d, rpos: %d, max: %d, oldmax: %d\n", \
174 (int)l->len,(int)l->pos,(int)l->oldpos,plen,rows,rpos, \
175 (int)l->maxrows,old_rows); \
176 } \
177 fprintf(lndebug_fp, ", " __VA_ARGS__); \
178 fflush(lndebug_fp); \
179 } while (0)
180#else
181#define lndebug(fmt, ...)
182#endif
183
184/* ======================= Low level terminal handling ====================== */
185
186/* Set if to use or not the multi line mode. */
187void linenoiseSetMultiLine(int ml) {
188 mlmode = ml;
189}
190
191/* Return true if the terminal name is in the list of terminals we know are
192 * not able to understand basic escape sequences. */
193static int isUnsupportedTerm(void) {
194 char *term = getenv("TERM");
195 int j;
196
197 if (term == NULL) return 0;
198 for (j = 0; unsupported_term[j]; j++)
199 if (!strcasecmp(term,unsupported_term[j])) return 1;
200 return 0;
201}
202
203/* Raw mode: 1960 magic shit. */
Michal Vasko62056bb2015-12-16 13:24:39 +0100204int linenoiseEnableRawMode(int fd) {
Michal Vasko203b4e72015-06-30 15:25:15 +0200205 struct termios raw;
206
207 if (!isatty(STDIN_FILENO)) goto fatal;
208 if (!atexit_registered) {
209 atexit(linenoiseAtExit);
210 atexit_registered = 1;
211 }
212 if (tcgetattr(fd,&orig_termios) == -1) goto fatal;
213
214 raw = orig_termios; /* modify the original mode */
215 /* input modes: no break, no CR to NL, no parity check, no strip char,
216 * no start/stop output control. */
217 raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
218 /* output modes - disable post processing */
219 raw.c_oflag &= ~(OPOST);
220 /* control modes - set 8 bit chars */
221 raw.c_cflag |= (CS8);
222 /* local modes - choing off, canonical off, no extended functions,
223 * no signal chars (^Z,^C) */
224 raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
225 /* control chars - set return condition: min number of bytes and timer.
226 * We want read to return every single byte, without timeout. */
227 raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
228
229 /* put terminal in raw mode after flushing */
230 if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal;
Michal Vasko62056bb2015-12-16 13:24:39 +0100231 ls.rawmode = 1;
Michal Vasko203b4e72015-06-30 15:25:15 +0200232 return 0;
233
234fatal:
235 errno = ENOTTY;
236 return -1;
237}
238
Michal Vasko62056bb2015-12-16 13:24:39 +0100239void linenoiseDisableRawMode(int fd) {
Michal Vasko203b4e72015-06-30 15:25:15 +0200240 /* Don't even check the return value as it's too late. */
Michal Vasko62056bb2015-12-16 13:24:39 +0100241 if (ls.rawmode && tcsetattr(fd,TCSAFLUSH,&orig_termios) != -1)
242 ls.rawmode = 0;
Michal Vasko203b4e72015-06-30 15:25:15 +0200243}
244
245/* Use the ESC [6n escape sequence to query the horizontal cursor position
246 * and return it. On error -1 is returned, on success the position of the
247 * cursor. */
248static int getCursorPosition(int ifd, int ofd) {
249 char buf[32];
250 int cols, rows;
251 unsigned int i = 0;
252
253 /* Report cursor location */
254 if (write(ofd, "\x1b[6n", 4) != 4) return -1;
255
256 /* Read the response: ESC [ rows ; cols R */
257 while (i < sizeof(buf)-1) {
258 if (read(ifd,buf+i,1) != 1) break;
259 if (buf[i] == 'R') break;
260 i++;
261 }
262 buf[i] = '\0';
263
264 /* Parse it. */
265 if (buf[0] != ESC || buf[1] != '[') return -1;
266 if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1;
267 return cols;
268}
269
270/* Try to get the number of columns in the current terminal, or assume 80
271 * if it fails. */
272static int getColumns(int ifd, int ofd) {
273 struct winsize ws;
274
275 if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
276 /* ioctl() failed. Try to query the terminal itself. */
277 int start, cols;
278
279 /* Get the initial position so we can restore it later. */
280 start = getCursorPosition(ifd,ofd);
281 if (start == -1) goto failed;
282
283 /* Go to right margin and get position. */
284 if (write(ofd,"\x1b[999C",6) != 6) goto failed;
285 cols = getCursorPosition(ifd,ofd);
286 if (cols == -1) goto failed;
287
288 /* Restore position. */
289 if (cols > start) {
290 char seq[32];
291 snprintf(seq,32,"\x1b[%dD",cols-start);
292 if (write(ofd,seq,strlen(seq)) == -1) {
293 /* Can't recover... */
294 }
295 }
296 return cols;
297 } else {
298 return ws.ws_col;
299 }
300
301failed:
302 return 80;
303}
304
305/* Clear the screen. Used to handle ctrl+l */
306void linenoiseClearScreen(void) {
307 if (write(STDOUT_FILENO,"\x1b[H\x1b[2J",7) <= 0) {
308 /* nothing to do, just to avoid warning. */
309 }
310}
311
312/* Beep, used for completion when there is nothing to complete or when all
313 * the choices were already shown. */
314static void linenoiseBeep(void) {
315 fprintf(stderr, "\x7");
316 fflush(stderr);
317}
318
319/* ============================== Completion ================================ */
320
321/* Free a list of completion option populated by linenoiseAddCompletion(). */
322static void freeCompletions(linenoiseCompletions *lc) {
323 size_t i;
324 for (i = 0; i < lc->len; i++)
325 free(lc->cvec[i]);
326 if (lc->cvec != NULL)
327 free(lc->cvec);
328}
329
330/* This is an helper function for linenoiseEdit() and is called when the
331 * user types the <tab> key in order to complete the string currently in the
332 * input.
333 *
334 * The state of the editing is encapsulated into the pointed linenoiseState
335 * structure as described in the structure definition. */
336static int completeLine(struct linenoiseState *ls) {
Michal Vasko62056bb2015-12-16 13:24:39 +0100337 linenoiseCompletions lc = {0, 0, NULL};
338 int nread, nwritten, hint_len, hint_line_count, char_count;
339 char c = 0, *common, *hint;
340 struct winsize w;
Michal Vasko203b4e72015-06-30 15:25:15 +0200341
Michal Vasko62056bb2015-12-16 13:24:39 +0100342 /* Hint is only the string after the last space */
343 hint = strrchr(ls->buf, ' ');
344 if (!hint) {
345 hint = ls->buf;
346 } else {
347 ++hint;
348 }
349
350 completionCallback(ls->buf, hint, &lc);
Michal Vasko203b4e72015-06-30 15:25:15 +0200351 if (lc.len == 0) {
352 linenoiseBeep();
353 } else {
Michal Vasko62056bb2015-12-16 13:24:39 +0100354 unsigned int i, j;
Michal Vasko203b4e72015-06-30 15:25:15 +0200355
Michal Vasko62056bb2015-12-16 13:24:39 +0100356 /* Learn the longest common part */
357 common = strdup(lc.cvec[0]);
358 for (i = 1; i < lc.len; ++i) {
359 for (j = 0; j < strlen(lc.cvec[i]); ++j) {
360 if (lc.cvec[i][j] != common[j]) {
Michal Vasko62056bb2015-12-16 13:24:39 +0100361 break;
362 }
363 }
Michal Vasko326a88e2016-02-05 14:44:37 +0100364 common[j] = '\0';
Michal Vasko62056bb2015-12-16 13:24:39 +0100365 }
Michal Vasko203b4e72015-06-30 15:25:15 +0200366
Michal Vasko62056bb2015-12-16 13:24:39 +0100367 /* Path completions have a different hint */
368 if (lc.path && strrchr(hint, '/')) {
369 hint = strrchr(hint, '/');
370 ++hint;
371 }
372
373 /* Show completion */
374 if ((lc.len == 1) && (common[strlen(common) - 1] != '/')) {
375 nwritten = snprintf(hint, ls->buflen - (hint - ls->buf), "%s ", common);
376 } else {
377 nwritten = snprintf(hint, ls->buflen - (hint - ls->buf), "%s", common);
378 }
379 free(common);
380 ls->len = ls->pos = (hint - ls->buf) + nwritten;
381 linenoiseRefreshLine();
382
383 /* A single hint */
384 if (lc.len == 1) {
385 freeCompletions(&lc);
386 return 0;
387 }
388
389 /* Read a char */
390 nread = read(ls->ifd,&c,1);
391 if (nread <= 0) {
392 freeCompletions(&lc);
393 return -1;
394 }
395
396 /* Not a tab */
397 if (c != 9) {
398 freeCompletions(&lc);
399 return c;
400 }
401
402 /* Learn terminal window size */
403 ioctl(ls->ifd, TIOCGWINSZ, &w);
404
405 /* Learn the longest hint */
406 hint_len = strlen(lc.cvec[0]);
407 for (i = 1; i < lc.len; ++i) {
408 if (strlen(lc.cvec[i]) > (unsigned)hint_len) {
409 hint_len = strlen(lc.cvec[i]);
410 }
411 }
412
413 /* Learn the number of hints that fit a line */
414 hint_line_count = 0;
415 while (1) {
416 char_count = 0;
417 if (hint_line_count) {
418 char_count += hint_line_count * (hint_len + 2);
419 }
420 char_count += hint_len;
421
422 /* Too much */
423 if (char_count > w.ws_col) {
424 break;
Michal Vasko203b4e72015-06-30 15:25:15 +0200425 }
426
Michal Vasko62056bb2015-12-16 13:24:39 +0100427 /* Still fits */
428 ++hint_line_count;
429 }
430
431 /* No hint fits, too bad */
432 if (!hint_line_count) {
433 freeCompletions(&lc);
434 return c;
435 }
436
437 while (c == 9) {
438 /* Second tab */
439 linenoiseDisableRawMode(ls->ifd);
440 printf("\n");
441 for (i = 0; i < lc.len; ++i) {
442 printf("%-*s", hint_len, lc.cvec[i]);
443 /* Line full or last hint */
444 if (((i + 1) % hint_line_count == 0) || (i == lc.len - 1)) {
445 printf("\n");
446 } else {
447 printf(" ");
448 }
449 }
450 linenoiseEnableRawMode(ls->ifd);
451 linenoiseRefreshLine();
452
453 /* Read a char */
Michal Vasko203b4e72015-06-30 15:25:15 +0200454 nread = read(ls->ifd,&c,1);
455 if (nread <= 0) {
456 freeCompletions(&lc);
457 return -1;
458 }
Michal Vasko203b4e72015-06-30 15:25:15 +0200459 }
460 }
461
462 freeCompletions(&lc);
463 return c; /* Return last read character */
464}
465
466/* Register a callback function to be called for tab-completion. */
467void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
468 completionCallback = fn;
469}
470
Michal Vasko62056bb2015-12-16 13:24:39 +0100471/* This function can be called in user completion callback to fill
472 * path completion for them. hint parameter is actually the whole path
473 * and buf is unused, but included to match the completion callback prototype. */
474void linenoisePathCompletion(const char *buf, const char *hint, linenoiseCompletions *lc) {
475 const char *ptr;
476 char *full_path, *hint_ptr, match[FILENAME_MAX + 2];
477 DIR *dir;
478 struct dirent *ent;
479 struct stat st;
480
481 (void)buf;
482
483 lc->path = 1;
484
485 ptr = strrchr(hint, '/');
486
487 /* new relative path */
488 if (ptr == NULL) {
489 full_path = malloc(2 + FILENAME_MAX + 1);
490 strcpy(full_path, "./");
491
492 ptr = hint;
493 } else {
494 full_path = malloc((int)(ptr - hint) + FILENAME_MAX + 1);
495 ++ptr;
496 sprintf(full_path, "%.*s", (int)(ptr - hint), hint);
497 }
498 hint_ptr = full_path + strlen(full_path);
499
500 dir = opendir(full_path);
501 if (dir == NULL) {
Radek Krejcicf533992015-12-17 09:15:38 +0100502 free(full_path);
Michal Vasko62056bb2015-12-16 13:24:39 +0100503 return;
504 }
505
506 while ((ent = readdir(dir))) {
507 if (ent->d_name[0] == '.') {
508 continue;
509 }
510
Michal Vasko62056bb2015-12-16 13:24:39 +0100511 if (!strncmp(ptr, ent->d_name, strlen(ptr))) {
512 /* is it a directory? */
513 strcpy(hint_ptr, ent->d_name);
Radek Krejcif320f272015-12-17 09:18:58 +0100514 if (stat(full_path, &st)) {
515 /* skip this item */
516 continue;
517 }
Michal Vasko62056bb2015-12-16 13:24:39 +0100518
519 strcpy(match, ent->d_name);
520 if (S_ISDIR(st.st_mode)) {
521 strcat(match, "/");
522 }
523
524 linenoiseAddCompletion(lc, match);
525 }
526 }
527
528 free(full_path);
529 closedir(dir);
530}
531
Michal Vasko203b4e72015-06-30 15:25:15 +0200532/* This function is used by the callback function registered by the user
533 * in order to add completion options given the input string when the
534 * user typed <tab>. See the example.c source code for a very easy to
535 * understand example. */
536void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
537 size_t len = strlen(str);
538 char *copy, **cvec;
539
540 copy = malloc(len+1);
541 if (copy == NULL) return;
542 memcpy(copy,str,len+1);
543 cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1));
544 if (cvec == NULL) {
545 free(copy);
546 return;
547 }
548 lc->cvec = cvec;
549 lc->cvec[lc->len++] = copy;
550}
551
552/* =========================== Line editing ================================= */
553
554/* We define a very simple "append buffer" structure, that is an heap
555 * allocated string where we can append to. This is useful in order to
556 * write all the escape sequences in a buffer and flush them to the standard
557 * output in a single call, to avoid flickering effects. */
558struct abuf {
559 char *b;
560 int len;
561};
562
563static void abInit(struct abuf *ab) {
564 ab->b = NULL;
565 ab->len = 0;
566}
567
568static void abAppend(struct abuf *ab, const char *s, int len) {
569 char *new = realloc(ab->b,ab->len+len);
570
571 if (new == NULL) return;
572 memcpy(new+ab->len,s,len);
573 ab->b = new;
574 ab->len += len;
575}
576
577static void abFree(struct abuf *ab) {
578 free(ab->b);
579}
580
581/* Single line low level line refresh.
582 *
583 * Rewrite the currently edited line accordingly to the buffer content,
584 * cursor position, and number of columns of the terminal. */
585static void refreshSingleLine(struct linenoiseState *l) {
586 char seq[64];
587 size_t plen = strlen(l->prompt);
588 int fd = l->ofd;
589 char *buf = l->buf;
590 size_t len = l->len;
591 size_t pos = l->pos;
592 struct abuf ab;
593
594 while((plen+pos) >= l->cols) {
595 buf++;
596 len--;
597 pos--;
598 }
599 while (plen+len > l->cols) {
600 len--;
601 }
602
603 abInit(&ab);
604 /* Cursor to left edge */
605 snprintf(seq,64,"\r");
606 abAppend(&ab,seq,strlen(seq));
607 /* Write the prompt and the current buffer content */
608 abAppend(&ab,l->prompt,strlen(l->prompt));
609 abAppend(&ab,buf,len);
610 /* Erase to right */
611 snprintf(seq,64,"\x1b[0K");
612 abAppend(&ab,seq,strlen(seq));
613 /* Move cursor to original position. */
614 snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen));
615 abAppend(&ab,seq,strlen(seq));
616 if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
617 abFree(&ab);
618}
619
620/* Multi line low level line refresh.
621 *
622 * Rewrite the currently edited line accordingly to the buffer content,
623 * cursor position, and number of columns of the terminal. */
624static void refreshMultiLine(struct linenoiseState *l) {
625 char seq[64];
626 int plen = strlen(l->prompt);
627 int rows = (plen+l->len+l->cols-1)/l->cols; /* rows used by current buf. */
628 int rpos = (plen+l->oldpos+l->cols)/l->cols; /* cursor relative row. */
629 int rpos2; /* rpos after refresh. */
630 int col; /* colum position, zero-based. */
631 int old_rows = l->maxrows;
632 int fd = l->ofd, j;
633 struct abuf ab;
634
635 /* Update maxrows if needed. */
636 if (rows > (int)l->maxrows) l->maxrows = rows;
637
638 /* First step: clear all the lines used before. To do so start by
639 * going to the last row. */
640 abInit(&ab);
641 if (old_rows-rpos > 0) {
642 lndebug("go down %d", old_rows-rpos);
643 snprintf(seq,64,"\x1b[%dB", old_rows-rpos);
644 abAppend(&ab,seq,strlen(seq));
645 }
646
647 /* Now for every row clear it, go up. */
648 for (j = 0; j < old_rows-1; j++) {
649 lndebug("clear+up");
650 snprintf(seq,64,"\r\x1b[0K\x1b[1A");
651 abAppend(&ab,seq,strlen(seq));
652 }
653
654 /* Clean the top line. */
655 lndebug("clear");
656 snprintf(seq,64,"\r\x1b[0K");
657 abAppend(&ab,seq,strlen(seq));
658
659 /* Write the prompt and the current buffer content */
660 abAppend(&ab,l->prompt,strlen(l->prompt));
661 abAppend(&ab,l->buf,l->len);
662
663 /* If we are at the very end of the screen with our prompt, we need to
664 * emit a newline and move the prompt to the first column. */
665 if (l->pos &&
666 l->pos == l->len &&
667 (l->pos+plen) % l->cols == 0)
668 {
669 lndebug("<newline>");
670 abAppend(&ab,"\n",1);
671 snprintf(seq,64,"\r");
672 abAppend(&ab,seq,strlen(seq));
673 rows++;
674 if (rows > (int)l->maxrows) l->maxrows = rows;
675 }
676
677 /* Move cursor to right position. */
678 rpos2 = (plen+l->pos+l->cols)/l->cols; /* current cursor relative row. */
679 lndebug("rpos2 %d", rpos2);
680
681 /* Go up till we reach the expected positon. */
682 if (rows-rpos2 > 0) {
683 lndebug("go-up %d", rows-rpos2);
684 snprintf(seq,64,"\x1b[%dA", rows-rpos2);
685 abAppend(&ab,seq,strlen(seq));
686 }
687
688 /* Set column. */
689 col = (plen+(int)l->pos) % (int)l->cols;
690 lndebug("set col %d", 1+col);
691 if (col)
692 snprintf(seq,64,"\r\x1b[%dC", col);
693 else
694 snprintf(seq,64,"\r");
695 abAppend(&ab,seq,strlen(seq));
696
697 lndebug("\n");
698 l->oldpos = l->pos;
699
700 if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
701 abFree(&ab);
702}
703
704/* Calls the two low level functions refreshSingleLine() or
705 * refreshMultiLine() according to the selected mode. */
Michal Vasko62056bb2015-12-16 13:24:39 +0100706void linenoiseRefreshLine(void) {
Michal Vasko203b4e72015-06-30 15:25:15 +0200707 if (mlmode)
Michal Vasko62056bb2015-12-16 13:24:39 +0100708 refreshMultiLine(&ls);
Michal Vasko203b4e72015-06-30 15:25:15 +0200709 else
Michal Vasko62056bb2015-12-16 13:24:39 +0100710 refreshSingleLine(&ls);
Michal Vasko203b4e72015-06-30 15:25:15 +0200711}
712
713/* Insert the character 'c' at cursor current position.
714 *
715 * On error writing to the terminal -1 is returned, otherwise 0. */
716int linenoiseEditInsert(struct linenoiseState *l, char c) {
717 if (l->len < l->buflen) {
718 if (l->len == l->pos) {
719 l->buf[l->pos] = c;
720 l->pos++;
721 l->len++;
722 l->buf[l->len] = '\0';
723 if ((!mlmode && l->plen+l->len < l->cols) /* || mlmode */) {
724 /* Avoid a full update of the line in the
725 * trivial case. */
726 if (write(l->ofd,&c,1) == -1) return -1;
727 } else {
Michal Vasko62056bb2015-12-16 13:24:39 +0100728 linenoiseRefreshLine();
Michal Vasko203b4e72015-06-30 15:25:15 +0200729 }
730 } else {
731 memmove(l->buf+l->pos+1,l->buf+l->pos,l->len-l->pos);
732 l->buf[l->pos] = c;
733 l->len++;
734 l->pos++;
735 l->buf[l->len] = '\0';
Michal Vasko62056bb2015-12-16 13:24:39 +0100736 linenoiseRefreshLine();
Michal Vasko203b4e72015-06-30 15:25:15 +0200737 }
738 }
739 return 0;
740}
741
742/* Move cursor on the left. */
743void linenoiseEditMoveLeft(struct linenoiseState *l) {
744 if (l->pos > 0) {
745 l->pos--;
Michal Vasko62056bb2015-12-16 13:24:39 +0100746 linenoiseRefreshLine();
Michal Vasko203b4e72015-06-30 15:25:15 +0200747 }
748}
749
750/* Move cursor on the right. */
751void linenoiseEditMoveRight(struct linenoiseState *l) {
752 if (l->pos != l->len) {
753 l->pos++;
Michal Vasko62056bb2015-12-16 13:24:39 +0100754 linenoiseRefreshLine();
Michal Vasko203b4e72015-06-30 15:25:15 +0200755 }
756}
757
758/* Move cursor to the start of the line. */
759void linenoiseEditMoveHome(struct linenoiseState *l) {
760 if (l->pos != 0) {
761 l->pos = 0;
Michal Vasko62056bb2015-12-16 13:24:39 +0100762 linenoiseRefreshLine();
Michal Vasko203b4e72015-06-30 15:25:15 +0200763 }
764}
765
766/* Move cursor to the end of the line. */
767void linenoiseEditMoveEnd(struct linenoiseState *l) {
768 if (l->pos != l->len) {
769 l->pos = l->len;
Michal Vasko62056bb2015-12-16 13:24:39 +0100770 linenoiseRefreshLine();
Michal Vasko203b4e72015-06-30 15:25:15 +0200771 }
772}
773
774/* Substitute the currently edited line with the next or previous history
775 * entry as specified by 'dir'. */
776#define LINENOISE_HISTORY_NEXT 0
777#define LINENOISE_HISTORY_PREV 1
778void linenoiseEditHistoryNext(struct linenoiseState *l, int dir) {
779 if (history_len > 1) {
780 /* Update the current history entry before to
781 * overwrite it with the next one. */
782 free(history[history_len - 1 - l->history_index]);
783 history[history_len - 1 - l->history_index] = strdup(l->buf);
784 /* Show the new entry */
785 l->history_index += (dir == LINENOISE_HISTORY_PREV) ? 1 : -1;
786 if (l->history_index < 0) {
787 l->history_index = 0;
788 return;
789 } else if (l->history_index >= history_len) {
790 l->history_index = history_len-1;
791 return;
792 }
793 strncpy(l->buf,history[history_len - 1 - l->history_index],l->buflen);
794 l->buf[l->buflen-1] = '\0';
795 l->len = l->pos = strlen(l->buf);
Michal Vasko62056bb2015-12-16 13:24:39 +0100796 linenoiseRefreshLine();
Michal Vasko203b4e72015-06-30 15:25:15 +0200797 }
798}
799
800/* Delete the character at the right of the cursor without altering the cursor
801 * position. Basically this is what happens with the "Delete" keyboard key. */
802void linenoiseEditDelete(struct linenoiseState *l) {
803 if (l->len > 0 && l->pos < l->len) {
804 memmove(l->buf+l->pos,l->buf+l->pos+1,l->len-l->pos-1);
805 l->len--;
806 l->buf[l->len] = '\0';
Michal Vasko62056bb2015-12-16 13:24:39 +0100807 linenoiseRefreshLine();
Michal Vasko203b4e72015-06-30 15:25:15 +0200808 }
809}
810
811/* Backspace implementation. */
812void linenoiseEditBackspace(struct linenoiseState *l) {
813 if (l->pos > 0 && l->len > 0) {
814 memmove(l->buf+l->pos-1,l->buf+l->pos,l->len-l->pos);
815 l->pos--;
816 l->len--;
817 l->buf[l->len] = '\0';
Michal Vasko62056bb2015-12-16 13:24:39 +0100818 linenoiseRefreshLine();
Michal Vasko203b4e72015-06-30 15:25:15 +0200819 }
820}
821
822/* Delete the previosu word, maintaining the cursor at the start of the
823 * current word. */
824void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
825 size_t old_pos = l->pos;
826 size_t diff;
827
828 while (l->pos > 0 && l->buf[l->pos-1] == ' ')
829 l->pos--;
830 while (l->pos > 0 && l->buf[l->pos-1] != ' ')
831 l->pos--;
832 diff = old_pos - l->pos;
833 memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1);
834 l->len -= diff;
Michal Vasko62056bb2015-12-16 13:24:39 +0100835 linenoiseRefreshLine();
Michal Vasko203b4e72015-06-30 15:25:15 +0200836}
837
838/* This function is the core of the line editing capability of linenoise.
839 * It expects 'fd' to be already in "raw mode" so that every key pressed
840 * will be returned ASAP to read().
841 *
842 * The resulting string is put into 'buf' when the user type enter, or
843 * when ctrl+d is typed.
844 *
845 * The function returns the length of the current buffer. */
846static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt)
847{
Michal Vasko203b4e72015-06-30 15:25:15 +0200848 /* Populate the linenoise state that we pass to functions implementing
849 * specific editing functionalities. */
Michal Vasko62056bb2015-12-16 13:24:39 +0100850 ls.ifd = stdin_fd;
851 ls.ofd = stdout_fd;
852 ls.buf = buf;
853 ls.buflen = buflen;
854 ls.prompt = prompt;
855 ls.plen = strlen(prompt);
856 ls.oldpos = ls.pos = 0;
857 ls.len = 0;
858 ls.cols = getColumns(stdin_fd, stdout_fd);
859 ls.maxrows = 0;
860 ls.history_index = 0;
Michal Vasko203b4e72015-06-30 15:25:15 +0200861
862 /* Buffer starts empty. */
Michal Vasko62056bb2015-12-16 13:24:39 +0100863 ls.buf[0] = '\0';
864 ls.buflen--; /* Make sure there is always space for the nulterm */
Michal Vasko203b4e72015-06-30 15:25:15 +0200865
866 /* The latest history entry is always our current buffer, that
867 * initially is just an empty string. */
868 linenoiseHistoryAdd("");
869
Michal Vasko62056bb2015-12-16 13:24:39 +0100870 if (write(ls.ofd,prompt,ls.plen) == -1) return -1;
Michal Vasko203b4e72015-06-30 15:25:15 +0200871 while(1) {
872 char c;
873 int nread;
874 char seq[3];
875
Michal Vasko62056bb2015-12-16 13:24:39 +0100876 nread = read(ls.ifd,&c,1);
877 if (nread <= 0) return ls.len;
Michal Vasko203b4e72015-06-30 15:25:15 +0200878
879 /* Only autocomplete when the callback is set. It returns < 0 when
880 * there was an error reading from fd. Otherwise it will return the
881 * character that should be handled next. */
882 if (c == 9 && completionCallback != NULL) {
Michal Vasko62056bb2015-12-16 13:24:39 +0100883 c = completeLine(&ls);
Michal Vasko203b4e72015-06-30 15:25:15 +0200884 /* Return on errors */
Michal Vasko62056bb2015-12-16 13:24:39 +0100885 if (c < 0) return ls.len;
Michal Vasko203b4e72015-06-30 15:25:15 +0200886 /* Read next character when 0 */
887 if (c == 0) continue;
888 }
889
890 switch(c) {
891 case ENTER: /* enter */
892 history_len--;
893 free(history[history_len]);
Michal Vasko62056bb2015-12-16 13:24:39 +0100894 if (mlmode) linenoiseEditMoveEnd(&ls);
895 return (int)ls.len;
Michal Vasko203b4e72015-06-30 15:25:15 +0200896 case CTRL_C: /* ctrl-c */
897 errno = EAGAIN;
898 return -1;
899 case BACKSPACE: /* backspace */
900 case 8: /* ctrl-h */
Michal Vasko62056bb2015-12-16 13:24:39 +0100901 linenoiseEditBackspace(&ls);
Michal Vasko203b4e72015-06-30 15:25:15 +0200902 break;
903 case CTRL_D: /* ctrl-d, remove char at right of cursor, or if the
904 line is empty, act as end-of-file. */
Michal Vasko62056bb2015-12-16 13:24:39 +0100905 if (ls.len > 0) {
906 linenoiseEditDelete(&ls);
Michal Vasko203b4e72015-06-30 15:25:15 +0200907 } else {
908 history_len--;
909 free(history[history_len]);
910 return -1;
911 }
912 break;
913 case CTRL_T: /* ctrl-t, swaps current character with previous. */
Michal Vasko62056bb2015-12-16 13:24:39 +0100914 if (ls.pos > 0 && ls.pos < ls.len) {
915 int aux = buf[ls.pos-1];
916 buf[ls.pos-1] = buf[ls.pos];
917 buf[ls.pos] = aux;
918 if (ls.pos != ls.len-1) ls.pos++;
919 linenoiseRefreshLine();
Michal Vasko203b4e72015-06-30 15:25:15 +0200920 }
921 break;
922 case CTRL_B: /* ctrl-b */
Michal Vasko62056bb2015-12-16 13:24:39 +0100923 linenoiseEditMoveLeft(&ls);
Michal Vasko203b4e72015-06-30 15:25:15 +0200924 break;
925 case CTRL_F: /* ctrl-f */
Michal Vasko62056bb2015-12-16 13:24:39 +0100926 linenoiseEditMoveRight(&ls);
Michal Vasko203b4e72015-06-30 15:25:15 +0200927 break;
928 case CTRL_P: /* ctrl-p */
Michal Vasko62056bb2015-12-16 13:24:39 +0100929 linenoiseEditHistoryNext(&ls, LINENOISE_HISTORY_PREV);
Michal Vasko203b4e72015-06-30 15:25:15 +0200930 break;
931 case CTRL_N: /* ctrl-n */
Michal Vasko62056bb2015-12-16 13:24:39 +0100932 linenoiseEditHistoryNext(&ls, LINENOISE_HISTORY_NEXT);
Michal Vasko203b4e72015-06-30 15:25:15 +0200933 break;
934 case ESC: /* escape sequence */
935 /* Read the next two bytes representing the escape sequence.
936 * Use two calls to handle slow terminals returning the two
937 * chars at different times. */
Michal Vasko62056bb2015-12-16 13:24:39 +0100938 if (read(ls.ifd,seq,1) == -1) break;
939 if (read(ls.ifd,seq+1,1) == -1) break;
Michal Vasko203b4e72015-06-30 15:25:15 +0200940
941 /* ESC [ sequences. */
942 if (seq[0] == '[') {
943 if (seq[1] >= '0' && seq[1] <= '9') {
944 /* Extended escape, read additional byte. */
Michal Vasko62056bb2015-12-16 13:24:39 +0100945 if (read(ls.ifd,seq+2,1) == -1) break;
Michal Vasko203b4e72015-06-30 15:25:15 +0200946 if (seq[2] == '~') {
947 switch(seq[1]) {
948 case '3': /* Delete key. */
Michal Vasko62056bb2015-12-16 13:24:39 +0100949 linenoiseEditDelete(&ls);
Michal Vasko203b4e72015-06-30 15:25:15 +0200950 break;
951 }
952 }
953 } else {
954 switch(seq[1]) {
955 case 'A': /* Up */
Michal Vasko62056bb2015-12-16 13:24:39 +0100956 linenoiseEditHistoryNext(&ls, LINENOISE_HISTORY_PREV);
Michal Vasko203b4e72015-06-30 15:25:15 +0200957 break;
958 case 'B': /* Down */
Michal Vasko62056bb2015-12-16 13:24:39 +0100959 linenoiseEditHistoryNext(&ls, LINENOISE_HISTORY_NEXT);
Michal Vasko203b4e72015-06-30 15:25:15 +0200960 break;
961 case 'C': /* Right */
Michal Vasko62056bb2015-12-16 13:24:39 +0100962 linenoiseEditMoveRight(&ls);
Michal Vasko203b4e72015-06-30 15:25:15 +0200963 break;
964 case 'D': /* Left */
Michal Vasko62056bb2015-12-16 13:24:39 +0100965 linenoiseEditMoveLeft(&ls);
Michal Vasko203b4e72015-06-30 15:25:15 +0200966 break;
967 case 'H': /* Home */
Michal Vasko62056bb2015-12-16 13:24:39 +0100968 linenoiseEditMoveHome(&ls);
Michal Vasko203b4e72015-06-30 15:25:15 +0200969 break;
970 case 'F': /* End*/
Michal Vasko62056bb2015-12-16 13:24:39 +0100971 linenoiseEditMoveEnd(&ls);
Michal Vasko203b4e72015-06-30 15:25:15 +0200972 break;
973 }
974 }
975 }
976
977 /* ESC O sequences. */
978 else if (seq[0] == 'O') {
979 switch(seq[1]) {
980 case 'H': /* Home */
Michal Vasko62056bb2015-12-16 13:24:39 +0100981 linenoiseEditMoveHome(&ls);
Michal Vasko203b4e72015-06-30 15:25:15 +0200982 break;
983 case 'F': /* End*/
Michal Vasko62056bb2015-12-16 13:24:39 +0100984 linenoiseEditMoveEnd(&ls);
Michal Vasko203b4e72015-06-30 15:25:15 +0200985 break;
986 }
987 }
988 break;
989 default:
Michal Vasko62056bb2015-12-16 13:24:39 +0100990 if (linenoiseEditInsert(&ls,c)) return -1;
Michal Vasko203b4e72015-06-30 15:25:15 +0200991 break;
992 case CTRL_U: /* Ctrl+u, delete the whole line. */
993 buf[0] = '\0';
Michal Vasko62056bb2015-12-16 13:24:39 +0100994 ls.pos = ls.len = 0;
995 linenoiseRefreshLine();
Michal Vasko203b4e72015-06-30 15:25:15 +0200996 break;
997 case CTRL_K: /* Ctrl+k, delete from current to end of line. */
Michal Vasko62056bb2015-12-16 13:24:39 +0100998 buf[ls.pos] = '\0';
999 ls.len = ls.pos;
1000 linenoiseRefreshLine();
Michal Vasko203b4e72015-06-30 15:25:15 +02001001 break;
1002 case CTRL_A: /* Ctrl+a, go to the start of the line */
Michal Vasko62056bb2015-12-16 13:24:39 +01001003 linenoiseEditMoveHome(&ls);
Michal Vasko203b4e72015-06-30 15:25:15 +02001004 break;
1005 case CTRL_E: /* ctrl+e, go to the end of the line */
Michal Vasko62056bb2015-12-16 13:24:39 +01001006 linenoiseEditMoveEnd(&ls);
Michal Vasko203b4e72015-06-30 15:25:15 +02001007 break;
1008 case CTRL_L: /* ctrl+l, clear screen */
1009 linenoiseClearScreen();
Michal Vasko62056bb2015-12-16 13:24:39 +01001010 linenoiseRefreshLine();
Michal Vasko203b4e72015-06-30 15:25:15 +02001011 break;
1012 case CTRL_W: /* ctrl+w, delete previous word */
Michal Vasko62056bb2015-12-16 13:24:39 +01001013 linenoiseEditDeletePrevWord(&ls);
Michal Vasko203b4e72015-06-30 15:25:15 +02001014 break;
1015 }
1016 }
Michal Vasko62056bb2015-12-16 13:24:39 +01001017 return ls.len;
Michal Vasko203b4e72015-06-30 15:25:15 +02001018}
1019
1020/* This special mode is used by linenoise in order to print scan codes
1021 * on screen for debugging / development purposes. It is implemented
1022 * by the linenoise_example program using the --keycodes option. */
1023void linenoisePrintKeyCodes(void) {
1024 char quit[4];
1025
1026 printf("Linenoise key codes debugging mode.\n"
1027 "Press keys to see scan codes. Type 'quit' at any time to exit.\n");
Michal Vasko62056bb2015-12-16 13:24:39 +01001028 if (linenoiseEnableRawMode(STDIN_FILENO) == -1) return;
Michal Vasko203b4e72015-06-30 15:25:15 +02001029 memset(quit,' ',4);
1030 while(1) {
1031 char c;
1032 int nread;
1033
1034 nread = read(STDIN_FILENO,&c,1);
1035 if (nread <= 0) continue;
1036 memmove(quit,quit+1,sizeof(quit)-1); /* shift string to left. */
1037 quit[sizeof(quit)-1] = c; /* Insert current char on the right. */
1038 if (memcmp(quit,"quit",sizeof(quit)) == 0) break;
1039
1040 printf("'%c' %02x (%d) (type quit to exit)\n",
1041 isprint(c) ? c : '?', (int)c, (int)c);
1042 printf("\r"); /* Go left edge manually, we are in raw mode. */
1043 fflush(stdout);
1044 }
Michal Vasko62056bb2015-12-16 13:24:39 +01001045 linenoiseDisableRawMode(STDIN_FILENO);
Michal Vasko203b4e72015-06-30 15:25:15 +02001046}
1047
1048/* This function calls the line editing function linenoiseEdit() using
1049 * the STDIN file descriptor set in raw mode. */
1050static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
1051 int count;
1052
1053 if (buflen == 0) {
1054 errno = EINVAL;
1055 return -1;
1056 }
1057 if (!isatty(STDIN_FILENO)) {
1058 /* Not a tty: read from file / pipe. */
1059 if (fgets(buf, buflen, stdin) == NULL) return -1;
1060 count = strlen(buf);
1061 if (count && buf[count-1] == '\n') {
1062 count--;
1063 buf[count] = '\0';
1064 }
1065 } else {
1066 /* Interactive editing. */
Michal Vasko62056bb2015-12-16 13:24:39 +01001067 if (linenoiseEnableRawMode(STDIN_FILENO) == -1) return -1;
Michal Vasko203b4e72015-06-30 15:25:15 +02001068 count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt);
Michal Vasko62056bb2015-12-16 13:24:39 +01001069 linenoiseDisableRawMode(STDIN_FILENO);
Michal Vasko203b4e72015-06-30 15:25:15 +02001070 printf("\n");
1071 }
1072 return count;
1073}
1074
1075/* The high level function that is the main API of the linenoise library.
1076 * This function checks if the terminal has basic capabilities, just checking
1077 * for a blacklist of stupid terminals, and later either calls the line
1078 * editing function or uses dummy fgets() so that you will be able to type
1079 * something even in the most desperate of the conditions. */
1080char *linenoise(const char *prompt) {
1081 char buf[LINENOISE_MAX_LINE];
1082 int count;
1083
1084 if (isUnsupportedTerm()) {
1085 size_t len;
1086
1087 printf("%s",prompt);
1088 fflush(stdout);
1089 if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL;
1090 len = strlen(buf);
1091 while(len && (buf[len-1] == '\n' || buf[len-1] == '\r')) {
1092 len--;
1093 buf[len] = '\0';
1094 }
1095 return strdup(buf);
1096 } else {
1097 count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt);
1098 if (count == -1) return NULL;
1099 return strdup(buf);
1100 }
1101}
1102
1103/* ================================ History ================================= */
1104
1105/* Free the history, but does not reset it. Only used when we have to
1106 * exit() to avoid memory leaks are reported by valgrind & co. */
1107static void freeHistory(void) {
1108 if (history) {
1109 int j;
1110
1111 for (j = 0; j < history_len; j++)
1112 free(history[j]);
1113 free(history);
1114 }
1115}
1116
1117/* At exit we'll try to fix the terminal to the initial conditions. */
1118static void linenoiseAtExit(void) {
Michal Vasko62056bb2015-12-16 13:24:39 +01001119 linenoiseDisableRawMode(STDIN_FILENO);
Michal Vasko203b4e72015-06-30 15:25:15 +02001120 freeHistory();
1121}
1122
1123/* This is the API call to add a new entry in the linenoise history.
1124 * It uses a fixed array of char pointers that are shifted (memmoved)
1125 * when the history max length is reached in order to remove the older
1126 * entry and make room for the new one, so it is not exactly suitable for huge
1127 * histories, but will work well for a few hundred of entries.
1128 *
1129 * Using a circular buffer is smarter, but a bit more complex to handle. */
1130int linenoiseHistoryAdd(const char *line) {
1131 char *linecopy;
1132
1133 if (history_max_len == 0) return 0;
1134
1135 /* Initialization on first call. */
1136 if (history == NULL) {
1137 history = malloc(sizeof(char*)*history_max_len);
1138 if (history == NULL) return 0;
1139 memset(history,0,(sizeof(char*)*history_max_len));
1140 }
1141
1142 /* Don't add duplicated lines. */
1143 if (history_len && !strcmp(history[history_len-1], line)) return 0;
1144
1145 /* Add an heap allocated copy of the line in the history.
1146 * If we reached the max length, remove the older line. */
1147 linecopy = strdup(line);
1148 if (!linecopy) return 0;
1149 if (history_len == history_max_len) {
1150 free(history[0]);
1151 memmove(history,history+1,sizeof(char*)*(history_max_len-1));
1152 history_len--;
1153 }
1154 history[history_len] = linecopy;
1155 history_len++;
1156 return 1;
1157}
1158
1159/* Set the maximum length for the history. This function can be called even
1160 * if there is already some history, the function will make sure to retain
1161 * just the latest 'len' elements if the new history length value is smaller
1162 * than the amount of items already inside the history. */
1163int linenoiseHistorySetMaxLen(int len) {
1164 char **new;
1165
1166 if (len < 1) return 0;
1167 if (history) {
1168 int tocopy = history_len;
1169
1170 new = malloc(sizeof(char*)*len);
1171 if (new == NULL) return 0;
1172
1173 /* If we can't copy everything, free the elements we'll not use. */
1174 if (len < tocopy) {
1175 int j;
1176
1177 for (j = 0; j < tocopy-len; j++) free(history[j]);
1178 tocopy = len;
1179 }
1180 memset(new,0,sizeof(char*)*len);
1181 memcpy(new,history+(history_len-tocopy), sizeof(char*)*tocopy);
1182 free(history);
1183 history = new;
1184 }
1185 history_max_len = len;
1186 if (history_len > history_max_len)
1187 history_len = history_max_len;
1188 return 1;
1189}
1190
1191/* Save the history in the specified file. On success 0 is returned
1192 * otherwise -1 is returned. */
1193int linenoiseHistorySave(const char *filename) {
1194 FILE *fp = fopen(filename,"w");
1195 int j;
1196
1197 if (fp == NULL) return -1;
1198 for (j = 0; j < history_len; j++)
1199 fprintf(fp,"%s\n",history[j]);
1200 fclose(fp);
1201 return 0;
1202}
1203
1204/* Load the history from the specified file. If the file does not exist
1205 * zero is returned and no operation is performed.
1206 *
1207 * If the file exists and the operation succeeded 0 is returned, otherwise
1208 * on error -1 is returned. */
1209int linenoiseHistoryLoad(const char *filename) {
1210 FILE *fp = fopen(filename,"r");
1211 char buf[LINENOISE_MAX_LINE];
1212
1213 if (fp == NULL) return -1;
1214
1215 while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) {
1216 char *p;
1217
1218 p = strchr(buf,'\r');
1219 if (!p) p = strchr(buf,'\n');
1220 if (p) *p = '\0';
1221 linenoiseHistoryAdd(buf);
1222 }
1223 fclose(fp);
1224 return 0;
1225}