1 /*
2 * linehistory.c
3 *
4 * linehistory is forked from linenoise; the original version
5 * is available from https://github.com/antirez/linenoise
6 *
7 * ------------------------------------------------------------------------
8 *
9 * Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com>
10 * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
11 * Copyright (c) 2021 The DPS8M Development Team
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 _POSIX_C_SOURCE
40 # define _POSIX_C_SOURCE 200809L
41 #endif /* ifndef _POSIX_C_SOURCE */
42
43 #if !defined( __MINGW32__ ) \
44 && !defined( CROSS_MINGW32 ) \
45 && !defined( CROSS_MINGW64 ) \
46 && !defined( __MINGW64__ ) \
47 && !defined( _MSC_VER ) \
48 && !defined( _MSC_BUILD )
49
50 # if defined( __sun ) && defined( __SVR4 )
51 # ifndef __EXTENSIONS__
52 # define __EXTENSIONS__ 1
53 # endif /* ifndef __EXTENSIONS__ */
54 # endif /* if defined( __sun ) && defined( __SVR4 ) */
55 # include <termios.h>
56 # if defined( __sun ) && defined( __SVR4 )
57 # include <sys/termiox.h>
58 # endif /* if defined( __sun ) && defined( __SVR4 ) */
59 # include "linehistory.h"
60 # include <ctype.h>
61 # include <errno.h>
62 # include <stdio.h>
63 # include <stdlib.h>
64 # include <string.h>
65 # include <strings.h>
66 # include <sys/ioctl.h>
67 # include <sys/stat.h>
68 # include <sys/types.h>
69 # include <unistd.h>
70
71 # define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
72 # define LINENOISE_MAX_LINE 4096
73
74 static char *unsupported_term[] = {
75 "dumb", "cons25", "emacs", NULL
76 };
77
78 # ifdef LH_COMPLETION
79 static linenoiseCompletionCallback *completionCallback = NULL;
80 # endif /* ifdef LH_COMPLETION */
81
82 # ifdef LH_HINTS
83 static linenoiseHintsCallback *hintsCallback = NULL;
84 static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
85 # endif /* ifdef LH_HINTS */
86
87 static struct termios orig_termios; /* In order to restore at exit.*/
88
89 # ifdef LH_MASKMODE
90 static int maskmode = 0; /* Show "***" instead of input. For passwords. */
91 # endif /* ifdef LH_MASKMODE */
92
93 static int rawmode = 0;
94 static int mlmode = 0; /* Multi line mode. Default is single line. */
95 static int atexit_registered = 0; /* Register atexit just 1 time. */
96 static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
97 static int history_len = 0;
98 static char **history = NULL;
99
100 /*
101 * The linenoiseState structure represents the state during line editing.
102 * We pass this state to functions implementing specific editing
103 * functionalities.
104 */
105
106 struct linenoiseState
107 {
108 int ifd; /* Terminal stdin file descriptor. */
109 int ofd; /* Terminal stdout file descriptor. */
110 char *buf; /* Edited line buffer. */
111 size_t buflen; /* Edited line buffer size. */
112 const char *prompt; /* Prompt to display. */
113 size_t plen; /* Prompt length. */
114 size_t pos; /* Current cursor position. */
115 size_t oldpos; /* Previous refresh cursor position. */
116 size_t len; /* Current edited line length. */
117 size_t cols; /* Number of columns in terminal. */
118 size_t maxrows; /* Maximum num of rows used so far (multiline mode) */
119 int history_index; /* The history index we are currently editing. */
120 };
121
122 enum KEY_ACTION
123 {
124 KEY_NULL = 0, /* NULL */
125 CTRL_A = 1, /* Ctrl-A */
126 CTRL_B = 2, /* Ctrl-B */
127 CTRL_C = 3, /* Ctrl-C */
128 CTRL_D = 4, /* Ctrl-D */
129 CTRL_E = 5, /* Ctrl-E */
130 CTRL_F = 6, /* Ctrl-F */
131 CTRL_H = 8, /* Ctrl-H */
132 TAB = 9, /* Tab */
133 CTRL_K = 11, /* Ctrl-K */
134 CTRL_L = 12, /* Ctrl-L */
135 ENTER = 13, /* Enter */
136 CTRL_N = 14, /* Ctrl-N */
137 CTRL_P = 16, /* Ctrl-P */
138 CTRL_T = 20, /* Ctrl-T */
139 CTRL_U = 21, /* Ctrl-U */
140 CTRL_W = 23, /* Ctrl-W */
141 ESC = 27, /* Escape */
142 BACKSPACE = 127 /* Backspace */
143 };
144
145 static void linenoiseAtExit(void);
146 static void refreshLine(struct linenoiseState *l);
147 size_t pstrlen(const char *s);
148
149 # ifdef LH_MASKMODE
150
151 /*
152 * Enable "mask mode". When it is enabled, instead of the input that
153 * the user is typing, the terminal will just display a corresponding
154 * number of asterisks, like "****". This is useful for passwords and other
155 * secrets that should not be displayed.
156 */
157
158 void
linenoiseMaskModeEnable(void)159 linenoiseMaskModeEnable(void)
160 {
161 maskmode = 1;
162 }
163
164 /* Disable mask mode. */
165 void
linenoiseMaskModeDisable(void)166 linenoiseMaskModeDisable(void)
167 {
168 maskmode = 0;
169 }
170 # endif /* ifdef LH_MASKMODE */
171
172 /* Set if to use or not the multi line mode. */
173 void
linenoiseSetMultiLine(int ml)174 linenoiseSetMultiLine(int ml)
175 {
176 mlmode = ml;
177 }
178
179 /*
180 * Return true if the terminal name is in the list of terminals we know are
181 * not able to understand basic escape sequences.
182 */
183
184 static int
isUnsupportedTerm(void)185 isUnsupportedTerm(void)
186 {
187 char *term = getenv("TERM");
188 int j;
189
190 if (term == NULL)
191 {
192 return ( 0 );
193 }
194
195 for (j = 0; unsupported_term[j]; j++)
196 {
197 if (!strcasecmp(term, unsupported_term[j]))
198 {
199 return ( 1 );
200 }
201 }
202
203 return ( 0 );
204 }
205
206 /* Raw mode */
207 static int
enableRawMode(int fd)208 enableRawMode(int fd)
209 {
210 struct termios raw;
211
212 if (!isatty(STDIN_FILENO))
213 {
214 goto fatal;
215 }
216
217 if (!atexit_registered)
218 {
219 atexit(linenoiseAtExit);
220 atexit_registered = 1;
221 }
222
223 if (tcgetattr(fd, &orig_termios) == -1)
224 {
225 goto fatal;
226 }
227
228 raw = orig_termios; /* modify the original mode */
229 /* input modes: no break, no CR to NL, no parity check, no strip char,
230 * no start/stop output control. */
231 raw.c_iflag &= ~( BRKINT | ICRNL | INPCK | ISTRIP | IXON );
232 /* control modes - set 8 bit chars */
233 raw.c_cflag |= ( CS8 );
234 /* local modes - choing off, canonical off, no extended functions,
235 * no signal chars (^Z,^C) */
236 raw.c_lflag &= ~( ECHO | ICANON | IEXTEN | ISIG );
237 /* control chars - set return condition: min number of bytes and timer.
238 * We want read to return every single byte, without timeout. */
239 raw.c_cc[VMIN] = 1;
240 raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
241
242 /* put terminal in raw mode after flushing */
243 if (tcsetattr(fd, TCSAFLUSH, &raw) < 0)
244 {
245 goto fatal;
246 }
247
248 rawmode = 1;
249 return ( 0 );
250
251 fatal:
252 errno = ENOTTY;
253 return ( -1 );
254 }
255
256 static void
disableRawMode(int fd)257 disableRawMode(int fd)
258 {
259 /* Don't even check the return value as it's too late. */
260 if (rawmode && tcsetattr(fd, TCSAFLUSH, &orig_termios) != -1)
261 {
262 rawmode = 0;
263 }
264 }
265
266 /*
267 * Use the ESC [6n escape sequence to query the horizontal cursor position
268 * and return it. On error -1 is returned, on success the position of the
269 * cursor.
270 */
271
272 static int
getCursorPosition(int ifd,int ofd)273 getCursorPosition(int ifd, int ofd)
274 {
275 char buf[32];
276 int cols, rows;
277 unsigned int i = 0;
278
279 /* Report cursor location */
280 if (write(ofd, "\x1b[6n", 4) != 4)
281 {
282 return ( -1 );
283 }
284
285 /* Read the response: ESC [ rows ; cols R */
286 while (i < sizeof ( buf ) - 1)
287 {
288 if (read(ifd, buf + i, 1) != 1)
289 {
290 break;
291 }
292
293 if (buf[i] == 'R')
294 {
295 break;
296 }
297
298 i++;
299 }
300 buf[i] = '\0';
301
302 /* Parse it. */
303 if (buf[0] != ESC || buf[1] != '[')
304 {
305 return ( -1 );
306 }
307
308 if (sscanf(buf + 2, "%d;%d", &rows, &cols) != 2)
309 {
310 return ( -1 );
311 }
312
313 return ( cols );
314 }
315
316 /* Try to get the number of columns in terminal, or assume 80 */
317 static int
getColumns(int ifd,int ofd)318 getColumns(int ifd, int ofd)
319 {
320 struct winsize ws;
321
322 if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0)
323 {
324 /* ioctl() failed. Try to query the terminal itself. */
325 int start, cols;
326
327 /* Get the initial position so we can restore it later. */
328 start = getCursorPosition(ifd, ofd);
329 if (start == -1)
330 {
331 goto failed;
332 }
333
334 /* Go to right margin and get position. */
335 if (write(ofd, "\x1b[999C", 6) != 6)
336 {
337 goto failed;
338 }
339
340 cols = getCursorPosition(ifd, ofd);
341 if (cols == -1)
342 {
343 goto failed;
344 }
345
346 /* Restore position. */
347 if (cols > start)
348 {
349 char seq[32];
350 snprintf(seq, sizeof ( seq ), "\x1b[%dD", cols - start);
351 if (write(ofd, seq, strlen(seq)) == -1)
352 { /* Can't recover... */
353 }
354 }
355
356 return ( cols );
357 }
358 else
359 {
360 return ( ws.ws_col );
361 }
362
363 failed:
364 return ( 80 );
365 }
366
367 /* Clear the screen. Used to handle ctrl+l */
368 void
linenoiseClearScreen(void)369 linenoiseClearScreen(void)
370 {
371 if (write(STDOUT_FILENO, "\x1b[H\x1b[2J", 7) <= 0)
372 { /* nothing to do, just to avoid warning. */
373 }
374 }
375
376 # ifdef LH_COMPLETION
377
378 /*
379 * Beep, used for completion when there is nothing to complete or when all
380 * the choices were already shown.
381 */
382
383 static void
linenoiseBeep(void)384 linenoiseBeep(void)
385 {
386 fprintf(stderr, "\x7");
387 fflush(stderr);
388 }
389
390 /* Free a list of completion option populated by linenoiseAddCompletion(). */
391 static void
freeCompletions(const linenoiseCompletions * lc)392 freeCompletions(const linenoiseCompletions *lc)
393 {
394 size_t i;
395
396 for (i = 0; i < lc->len; i++)
397 {
398 free(lc->cvec[i]);
399 }
400
401 if (lc->cvec != NULL)
402 {
403 free(lc->cvec);
404 }
405 }
406
407 /*
408 * This is an helper function for linenoiseEdit() and is called when the
409 * user types the <tab> key in order to complete the string currently in the
410 * input.
411 *
412 * The state of the editing is encapsulated into the pointed linenoiseState
413 * structure as described in the structure definition.
414 */
415
416 static int
completeLine(struct linenoiseState * ls)417 completeLine(struct linenoiseState *ls)
418 {
419 linenoiseCompletions lc = {
420 0, NULL
421 };
422 int nread, nwritten;
423 char c = 0;
424
425 completionCallback(ls->buf, &lc);
426 if (lc.len == 0)
427 {
428 linenoiseBeep();
429 }
430 else
431 {
432 size_t stop = 0, i = 0;
433
434 while (!stop)
435 {
436 /* Show completion or original buffer */
437 if (i < lc.len)
438 {
439 struct linenoiseState saved = *ls;
440
441 ls->len = ls->pos = strlen(lc.cvec[i]);
442 ls->buf = lc.cvec[i];
443 refreshLine(ls);
444 ls->len = saved.len;
445 ls->pos = saved.pos;
446 ls->buf = saved.buf;
447 }
448 else
449 {
450 refreshLine(ls);
451 }
452
453 nread = read(ls->ifd, &c, 1);
454 if (nread <= 0)
455 {
456 freeCompletions(&lc);
457 return ( -1 );
458 }
459
460 switch (c)
461 {
462 case 9: /* Tab */
463 i = ( i + 1 ) % ( lc.len + 1 );
464 if (i == lc.len)
465 {
466 linenoiseBeep();
467 }
468
469 stop = 1;
470 break;
471
472 default:
473 /* Update buffer and return */
474 if (i < lc.len)
475 {
476 nwritten = snprintf(ls->buf, ls->buflen, "%s", lc.cvec[i]);
477 ls->len = ls->pos = nwritten;
478 }
479
480 stop = 1;
481 break;
482 }
483 }
484 }
485
486 freeCompletions(&lc);
487 return ( c ); /* Return last read character */
488 }
489
490 /* Register a callback function to be called for tab-completion. */
491 void
linenoiseSetCompletionCallback(linenoiseCompletionCallback * fn)492 linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn)
493 {
494 completionCallback = fn;
495 }
496
497 # endif /* ifdef LH_COMPLETION */
498
499 # ifdef LH_HINTS
500
501 /*
502 * Register a hits function to be called to show hits to the user at the
503 * right of the prompt.
504 */
505
506 void
linenoiseSetHintsCallback(linenoiseHintsCallback * fn)507 linenoiseSetHintsCallback(linenoiseHintsCallback *fn)
508 {
509 hintsCallback = fn;
510 }
511
512 /*
513 * Register a function to free the hints returned by the hints callback
514 * registered with linenoiseSetHintsCallback().
515 */
516
517 void
linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback * fn)518 linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn)
519 {
520 freeHintsCallback = fn;
521 }
522
523 # endif /* ifdef LH_HINTS */
524
525 # ifdef LH_COMPLETION
526
527 /*
528 * This function is used by the callback function registered by the user
529 * in order to add completion options given the input string when the
530 * user typed <tab>.
531 */
532
533 void
linenoiseAddCompletion(linenoiseCompletions * lc,const char * str)534 linenoiseAddCompletion(linenoiseCompletions *lc, const char *str)
535 {
536 size_t len = strlen(str);
537 char *copy, **cvec;
538
539 copy = malloc(len + 1);
540 if (copy == NULL)
541 {
542 return;
543 }
544
545 memcpy(copy, str, len + 1);
546 cvec = realloc(lc->cvec, sizeof ( char * ) * ( lc->len + 1 ));
547 if (cvec == NULL)
548 {
549 free(copy);
550 return;
551 }
552
553 lc->cvec = cvec;
554 lc->cvec[lc->len++] = copy;
555 }
556
557 # endif /* ifdef LH_COMPLETION */
558
559 /*
560 * We define a very simple "append buffer" structure, that is an heap
561 * allocated string where we can append to. This is useful in order to
562 * write all the escape sequences in a buffer and flush them to the standard
563 * output in a single call, to avoid flickering effects.
564 */
565
566 struct abuf
567 {
568 char *b;
569 int len;
570 };
571
572 static void
abInit(struct abuf * ab)573 abInit(struct abuf *ab)
574 {
575 ab->b = NULL;
576 ab->len = 0;
577 }
578
579 static void
abAppend(struct abuf * ab,const char * s,int len)580 abAppend(struct abuf *ab, const char *s, int len)
581 {
582 if (len <= 0)
583 {
584 return;
585 }
586
587 char *new = realloc(ab->b, ab->len + len);
588
589 if (new == NULL)
590 {
591 return;
592 }
593
594 memcpy(new + ab->len, s, len);
595 ab->b = new;
596 ab->len += len;
597 }
598
599 static void
abFree(const struct abuf * ab)600 abFree(const struct abuf *ab)
601 {
602 free(ab->b);
603 }
604
605 # ifdef LH_HINTS
606
607 /*
608 * Helper of refreshSingleLine() and refreshMultiLine() to show hints
609 * to the right of the prompt.
610 */
611
612 static void
refreshShowHints(struct abuf * ab,const struct linenoiseState * l,int plen)613 refreshShowHints(struct abuf *ab, const struct linenoiseState *l, int plen)
614 {
615 char seq[64];
616
617 seq[0] = '\0';
618 if (hintsCallback && plen + l->len < l->cols)
619 {
620 int color = -1, bold = 0;
621 char *hint = hintsCallback(l->buf, &color, &bold);
622 if (hint)
623 {
624 int hintlen = strlen(hint);
625 int hintmaxlen = l->cols - ( plen + l->len );
626 if (hintlen > hintmaxlen)
627 {
628 hintlen = hintmaxlen;
629 }
630
631 if (bold == 1 && color == -1)
632 {
633 color = 37;
634 }
635
636 if (color != -1 || bold != 0)
637 {
638 snprintf(seq, sizeof ( seq ), "\033[%d;%d;49m", bold, color);
639 }
640 else
641 {
642 seq[0] = '\0';
643 }
644
645 abAppend(ab, seq, strlen(seq));
646 abAppend(ab, hint, hintlen);
647 if (color != -1 || bold != 0)
648 {
649 abAppend(ab, "\033[0m", 4);
650 }
651
652 /* Call the function to free the hint returned. */
653 if (freeHintsCallback)
654 {
655 freeHintsCallback(hint);
656 }
657 }
658 }
659 }
660
661 # endif /* ifdef LH_HINTS */
662
663 /*
664 * Single line low level line refresh.
665 *
666 * Rewrite the currently edited line accordingly to the buffer content,
667 * cursor position, and number of columns of the terminal.
668 */
669
670 static void
refreshSingleLine(const struct linenoiseState * l)671 refreshSingleLine(const struct linenoiseState *l)
672 {
673 char seq[64];
674 size_t plen = pstrlen(l->prompt);
675 int fd = l->ofd;
676 char *buf = l->buf;
677 size_t len = l->len;
678 size_t pos = l->pos;
679 struct abuf ab;
680
681 while (( plen + pos ) >= l->cols)
682 {
683 buf++;
684 len--;
685 pos--;
686 }
687 while (plen + len > l->cols)
688 {
689 len--;
690 }
691
692 abInit(&ab);
693 /* Cursor to left edge */
694 snprintf(seq, sizeof ( seq ), "\r");
695 abAppend(&ab, seq, strlen(seq));
696 /* Write the prompt and the current buffer content */
697 abAppend(&ab, l->prompt, strlen(l->prompt));
698 # ifdef LH_MASKMODE
699 if (maskmode == 1)
700 {
701 while (len--)
702 {
703 abAppend(&ab, "*", 1);
704 }
705 }
706 else
707 {
708 # endif /* ifdef LH_MASKMODE */
709 abAppend(&ab, buf, len);
710 # ifdef LH_MASKMODE
711 }
712 # endif /* ifdef LH_MASKMODE */
713 # ifdef LH_HINTS
714 /* Show hits if any. */
715 refreshShowHints(&ab, l, plen);
716 # endif /* ifdef LH_HINTS */
717 /* Erase to right */
718 snprintf(seq, sizeof ( seq ), "\x1b[0K");
719 abAppend(&ab, seq, strlen(seq));
720 /* Move cursor to original position. */
721 snprintf(seq, sizeof ( seq ), "\r\x1b[%dC", (int)( pos + plen ));
722 abAppend(&ab, seq, strlen(seq));
723 if (write(fd, ab.b, ab.len) == -1)
724 { /* Can't recover from write error. */
725 }
726
727 abFree(&ab);
728 }
729
730 /*
731 * Multi line low level line refresh.
732 *
733 * Rewrite the currently edited line accordingly to the buffer content,
734 * cursor position, and number of columns of the terminal.
735 */
736
737 static void
refreshMultiLine(struct linenoiseState * l)738 refreshMultiLine(struct linenoiseState *l)
739 {
740 char seq[64];
741 int plen = strlen(l->prompt);
742 int rows = ( plen + l->len + l->cols - 1 )
743 / l->cols; /* rows used by current buf. */
744 int rpos = ( plen + l->oldpos + l->cols ) / l->cols; /* cursor relative row. */
745 int rpos2; /* rpos after refresh. */
746 int col; /* colum position, zero-based. */
747 int old_rows = l->maxrows;
748 int fd = l->ofd, j;
749 struct abuf ab;
750
751 /* Update maxrows if needed. */
752 if (rows > (int)l->maxrows)
753 {
754 l->maxrows = rows;
755 }
756
757 /*
758 * First step: clear all the lines used before. To do so start by
759 * going to the last row.
760 */
761
762 abInit(&ab);
763 if (old_rows - rpos > 0)
764 {
765 snprintf(seq, sizeof ( seq ), "\x1b[%dB", old_rows - rpos);
766 abAppend(&ab, seq, strlen(seq));
767 }
768
769 /* Now for every row clear it, go up. */
770 for (j = 0; j < old_rows - 1; j++)
771 {
772 snprintf(seq, sizeof ( seq ), "\r\x1b[0K\x1b[1A");
773 abAppend(&ab, seq, strlen(seq));
774 }
775
776 /* Clean the top line. */
777 snprintf(seq, sizeof ( seq ), "\r\x1b[0K");
778 abAppend(&ab, seq, strlen(seq));
779
780 /* Write the prompt and the current buffer content */
781 abAppend(&ab, l->prompt, strlen(l->prompt));
782 # ifdef LH_MASKMODE
783 if (maskmode == 1)
784 {
785 unsigned int i;
786 for (i = 0; i < l->len; i++)
787 {
788 abAppend(&ab, "*", 1);
789 }
790 }
791 else
792 {
793 # endif /* ifdef LH_MASKMODE */
794 abAppend(&ab, l->buf, l->len);
795 # ifdef LH_MASKMODE
796 }
797 # endif /* ifdef LH_MASKMODE */
798
799 # ifdef LH_HINTS
800 /* Show hits if any. */
801 refreshShowHints(&ab, l, plen);
802 # endif /* ifdef LH_HINTS */
803
804 /*
805 * If we are at the very end of the screen with our prompt, we need to
806 * emit a newline and move the prompt to the first column.
807 */
808
809 if (l->pos && l->pos == l->len && ( l->pos + plen ) % l->cols == 0)
810 {
811 abAppend(&ab, "\n", 1);
812 snprintf(seq, sizeof ( seq ), "\r");
813 abAppend(&ab, seq, strlen(seq));
814 rows++;
815 if (rows > (int)l->maxrows)
816 {
817 l->maxrows = rows;
818 }
819 }
820
821 /* Move cursor to right position. */
822 rpos2 = ( plen + l->pos + l->cols ) / l->cols;
823
824 /* Go up till we reach the expected positon. */
825 if (rows - rpos2 > 0)
826 {
827 snprintf(seq, sizeof ( seq ), "\x1b[%dA", rows - rpos2);
828 abAppend(&ab, seq, strlen(seq));
829 }
830
831 /* Set column. */
832 col = ( plen + (int)l->pos ) % (int)l->cols;
833 if (col)
834 {
835 snprintf(seq, sizeof ( seq ), "\r\x1b[%dC", col);
836 }
837 else
838 {
839 snprintf(seq, sizeof ( seq ), "\r");
840 }
841
842 abAppend(&ab, seq, strlen(seq));
843
844 l->oldpos = l->pos;
845
846 if (write(fd, ab.b, ab.len) == -1)
847 { /* Can't recover from write error. */
848 }
849
850 abFree(&ab);
851 }
852
853 /*
854 * Calls the two low level functions refreshSingleLine() or
855 * refreshMultiLine() according to the selected mode.
856 */
857
858 static void
refreshLine(struct linenoiseState * l)859 refreshLine(struct linenoiseState *l)
860 {
861 l->cols = getColumns(STDIN_FILENO, STDOUT_FILENO);
862 if (mlmode)
863 {
864 refreshMultiLine(l);
865 }
866 else
867 {
868 refreshSingleLine(l);
869 }
870 }
871
872 /*
873 * Insert the character 'c' at cursor current position.
874 * On error writing to the terminal -1 is returned, otherwise 0.
875 */
876
877 int
linenoiseEditInsert(struct linenoiseState * l,char c)878 linenoiseEditInsert(struct linenoiseState *l, char c)
879 {
880 if (l->len < l->buflen)
881 {
882 if (l->len == l->pos)
883 {
884 l->buf[l->pos] = c;
885 l->pos++;
886 l->len++;
887 l->buf[l->len] = '\0';
888 # if defined( LH_MASKMODE ) && defined( LH_HINTS )
889 if (( !mlmode && l->plen + l->len < l->cols && !hintsCallback ))
890 {
891 /* Avoid a full update of the line in the trivial case. */
892 char d = ( maskmode == 1 ) ? '*' : (char)c;
893 if (write(l->ofd, &d, 1) == -1)
894 {
895 return ( -1 );
896 }
897 }
898 else
899 {
900 # endif /* if defined( LH_MASKMODE ) && defined( LH_HINTS ) */
901 refreshLine(l);
902 # if defined( LH_MASKMODE ) && defined( LH_HINTS )
903 }
904 # endif /* if defined( LH_MASKMODE ) && defined( LH_HINTS ) */
905 }
906 else
907 {
908 memmove(l->buf + l->pos + 1, l->buf + l->pos, l->len - l->pos);
909 l->buf[l->pos] = c;
910 l->len++;
911 l->pos++;
912 l->buf[l->len] = '\0';
913 refreshLine(l);
914 }
915 }
916
917 return ( 0 );
918 }
919
920 /* Move cursor on the left. */
921 void
linenoiseEditMoveLeft(struct linenoiseState * l)922 linenoiseEditMoveLeft(struct linenoiseState *l)
923 {
924 if (l->pos > 0)
925 {
926 l->pos--;
927 refreshLine(l);
928 }
929 }
930
931 /* Move cursor on the right. */
932 void
linenoiseEditMoveRight(struct linenoiseState * l)933 linenoiseEditMoveRight(struct linenoiseState *l)
934 {
935 if (l->pos != l->len)
936 {
937 l->pos++;
938 refreshLine(l);
939 }
940 }
941
942 /* Move cursor to the end of the current word. */
943 void
linenoiseEditMoveWordEnd(struct linenoiseState * l)944 linenoiseEditMoveWordEnd(struct linenoiseState *l)
945 {
946 if (l->len == 0 || l->pos >= l->len)
947 {
948 return;
949 }
950
951 if (l->buf[l->pos] == ' ')
952 {
953 while (l->pos < l->len && l->buf[l->pos] == ' ')
954 {
955 ++l->pos;
956 }
957 }
958
959 while (l->pos < l->len && l->buf[l->pos] != ' ')
960 {
961 ++l->pos;
962 }
963 refreshLine(l);
964 }
965
966 /* Move cursor to the start of the current word. */
967 void
linenoiseEditMoveWordStart(struct linenoiseState * l)968 linenoiseEditMoveWordStart(struct linenoiseState *l)
969 {
970 if (l->len == 0)
971 {
972 return;
973 }
974
975 if (l->buf[l->pos - 1] == ' ')
976 {
977 --l->pos;
978 }
979
980 if (l->buf[l->pos] == ' ')
981 {
982 while (l->pos > 0 && l->buf[l->pos] == ' ')
983 {
984 --l->pos;
985 }
986 }
987
988 while (l->pos > 0 && l->buf[l->pos - 1] != ' ')
989 {
990 --l->pos;
991 }
992 refreshLine(l);
993 }
994
995 /* Move cursor to the start of the line. */
996 void
linenoiseEditMoveHome(struct linenoiseState * l)997 linenoiseEditMoveHome(struct linenoiseState *l)
998 {
999 if (l->pos != 0)
1000 {
1001 l->pos = 0;
1002 refreshLine(l);
1003 }
1004 }
1005
1006 /* Move cursor to the end of the line. */
1007 void
linenoiseEditMoveEnd(struct linenoiseState * l)1008 linenoiseEditMoveEnd(struct linenoiseState *l)
1009 {
1010 if (l->pos != l->len)
1011 {
1012 l->pos = l->len;
1013 refreshLine(l);
1014 }
1015 }
1016
1017 /*
1018 * Substitute the currently edited line with the next
1019 * or previous history entry as specified by 'dir'.
1020 */
1021
1022 # define LINENOISE_HISTORY_NEXT 0
1023 # define LINENOISE_HISTORY_PREV 1
1024 void
linenoiseEditHistoryNext(struct linenoiseState * l,int dir)1025 linenoiseEditHistoryNext(struct linenoiseState *l, int dir)
1026 {
1027 if (history_len > 1)
1028 {
1029
1030 /*
1031 * Update the current history entry before to
1032 * overwrite it with the next one.
1033 */
1034
1035 free(history[history_len - 1 - l->history_index]);
1036 history[history_len - 1 - l->history_index] = strdup(l->buf);
1037 /* Show the new entry */
1038 l->history_index += ( dir == LINENOISE_HISTORY_PREV ) ? 1 : -1;
1039 if (l->history_index < 0)
1040 {
1041 l->history_index = 0;
1042 return;
1043 }
1044 else if (l->history_index >= history_len)
1045 {
1046 l->history_index = history_len - 1;
1047 return;
1048 }
1049
1050 strncpy(l->buf, history[history_len - 1 - l->history_index], l->buflen);
1051 l->buf[l->buflen - 1] = '\0';
1052 l->len = l->pos = strlen(l->buf);
1053 refreshLine(l);
1054 }
1055 }
1056
1057 /*
1058 * Search a line in history that start with the same characters as the
1059 * currently edited line. Substitue the current line with this history
1060 */
1061
1062 # define LINENOISE_SEARCH_HISTORY_FORWARD 0
1063 # define LINENOISE_SEARCH_HISTROY_REVERSE 1
1064 void
linenoiseSearchInHistory(struct linenoiseState * l,int direction)1065 linenoiseSearchInHistory(struct linenoiseState *l, int direction)
1066 {
1067 if (history_len > 1)
1068 {
1069
1070 /*
1071 * Update the current history entry before to
1072 * overwrite it with the next one.
1073 */
1074
1075 free(history[history_len - 1 - l->history_index]);
1076 history[history_len - 1 - l->history_index] = strdup(l->buf);
1077
1078 /* Search new entry */
1079 int cnt;
1080 if (direction == LINENOISE_SEARCH_HISTORY_FORWARD)
1081 {
1082 cnt = history_len - 2 - l->history_index;
1083 for (; cnt >= 0; cnt--)
1084 {
1085
1086 /*
1087 * Search a history entry that start with same
1088 * as the current line until the curser position
1089 */
1090
1091 if (strncmp(l->buf, history[cnt], l->pos) == 0)
1092 {
1093 strncpy(l->buf, history[cnt], l->buflen);
1094 l->buf[l->buflen - 1] = '\0';
1095 /* Don't change old curser postion */
1096 l->len = strlen(l->buf);
1097
1098 /*
1099 * Set history index so that we can contiune
1100 * the search on this postiion
1101 */
1102
1103 l->history_index = history_len - 1 - cnt;
1104 refreshLine(l);
1105 return;
1106 }
1107 }
1108 }
1109 else if (direction == LINENOISE_SEARCH_HISTROY_REVERSE)
1110 {
1111 cnt = history_len - l->history_index;
1112 for (; cnt < history_len; cnt++)
1113 {
1114
1115 /*
1116 * Search a history entry that start with same
1117 * as the current line until the curser position
1118 */
1119
1120 if (strncmp(l->buf, history[cnt], l->pos) == 0)
1121 {
1122 strncpy(l->buf, history[cnt], l->buflen);
1123 l->buf[l->buflen - 1] = '\0';
1124 /* Don't change old curser position */
1125 l->len = strlen(l->buf);
1126
1127 /*
1128 * Set history index so that we can contiune
1129 * the search on this postiion
1130 */
1131
1132 l->history_index = history_len - 1 - cnt;
1133 refreshLine(l);
1134 return;
1135 }
1136 }
1137 }
1138 }
1139 }
1140
1141 /*
1142 * Delete the character at the right of the cursor without altering the cursor
1143 * position. Basically this is what happens with the "Delete" keyboard key.
1144 */
1145
1146 void
linenoiseEditDelete(struct linenoiseState * l)1147 linenoiseEditDelete(struct linenoiseState *l)
1148 {
1149 if (l->len > 0 && l->pos < l->len)
1150 {
1151 memmove(l->buf + l->pos, l->buf + l->pos + 1, l->len - l->pos - 1);
1152 l->len--;
1153 l->buf[l->len] = '\0';
1154 refreshLine(l);
1155 }
1156 }
1157
1158 /* Backspace implementation. */
1159 void
linenoiseEditBackspace(struct linenoiseState * l)1160 linenoiseEditBackspace(struct linenoiseState *l)
1161 {
1162 if (l->pos > 0 && l->len > 0)
1163 {
1164 memmove(l->buf + l->pos - 1, l->buf + l->pos, l->len - l->pos);
1165 l->pos--;
1166 l->len--;
1167 l->buf[l->len] = '\0';
1168 refreshLine(l);
1169 }
1170 }
1171
1172 /*
1173 * Delete the previosu word, maintaining the
1174 * cursor at the start of the current word.
1175 */
1176
1177 void
linenoiseEditDeletePrevWord(struct linenoiseState * l)1178 linenoiseEditDeletePrevWord(struct linenoiseState *l)
1179 {
1180 size_t old_pos = l->pos;
1181 size_t diff;
1182
1183 while (l->pos > 0 && l->buf[l->pos - 1] == ' ')
1184 {
1185 l->pos--;
1186 }
1187 while (l->pos > 0 && l->buf[l->pos - 1] != ' ')
1188 {
1189 l->pos--;
1190 }
1191 diff = old_pos - l->pos;
1192 memmove(l->buf + l->pos, l->buf + old_pos, l->len - old_pos + 1);
1193 l->len -= diff;
1194 refreshLine(l);
1195 }
1196
1197 /* Delete the next word, maintaining the cursor at the same position */
1198 void
linenoiseEditDeleteNextWord(struct linenoiseState * l)1199 linenoiseEditDeleteNextWord(struct linenoiseState *l)
1200 {
1201 size_t next_word_end = l->pos;
1202
1203 while (next_word_end < l->len && l->buf[next_word_end] == ' ')
1204 {
1205 ++next_word_end;
1206 }
1207 while (next_word_end < l->len && l->buf[next_word_end] != ' ')
1208 {
1209 ++next_word_end;
1210 }
1211 memmove(l->buf + l->pos, l->buf + next_word_end, l->len - next_word_end);
1212 l->len -= next_word_end - l->pos;
1213 refreshLine(l);
1214 }
1215
1216 /*
1217 * This function is the core of the line editing capability of linenoise.
1218 * It expects 'fd' to be already in "raw mode" so that every key pressed
1219 * will be returned ASAP to read().
1220 *
1221 * The resulting string is put into 'buf' when the user type enter, or
1222 * when ctrl+d is typed.
1223 *
1224 * The function returns the length of the current buffer.
1225 */
1226
1227 static int
linenoiseEdit(int stdin_fd,int stdout_fd,char * buf,size_t buflen,const char * prompt)1228 linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen,
1229 const char *prompt)
1230 {
1231 struct linenoiseState l;
1232
1233 /*
1234 * Populate the linenoise state that we pass to functions implementing
1235 * specific editing functionalities.
1236 */
1237
1238 l.ifd = stdin_fd;
1239 l.ofd = stdout_fd;
1240 l.buf = buf;
1241 l.buflen = buflen;
1242 l.prompt = prompt;
1243 l.plen = pstrlen(prompt);
1244 l.oldpos = l.pos = 0;
1245 l.len = 0;
1246 l.cols = getColumns(stdin_fd, stdout_fd);
1247 l.maxrows = 0;
1248 l.history_index = 0;
1249
1250 /* Buffer starts empty. */
1251 l.buf[0] = '\0';
1252 l.buflen--; /* Make sure there is always space for the nulterm */
1253
1254 /*
1255 * The latest history entry is always our current
1256 * buffer, that initially is just an empty string.
1257 */
1258
1259 (void)linenoiseHistoryAdd("");
1260
1261 if (write(l.ofd, prompt, strlen(prompt)) == -1)
1262 {
1263 return ( -1 );
1264 }
1265
1266 while (1)
1267 {
1268 signed char c;
1269 int nread;
1270 char seq[3];
1271
1272 nread = read(l.ifd, &c, 1);
1273 if (nread <= 0)
1274 {
1275 return ( l.len );
1276 }
1277
1278 # ifdef LH_COMPLETION
1279
1280 /*
1281 * Only autocomplete when the callback is set. It returns < 0 when
1282 * there was an error reading from fd. Otherwise it will return the
1283 * character that should be handled next.
1284 */
1285
1286 if (c == 9 && completionCallback != NULL)
1287 {
1288 int cint = completeLine(&l);
1289 /* Return on errors */
1290 if (cint < 0)
1291 {
1292 return ( l.len );
1293 }
1294
1295 /* Read next character when 0 */
1296 if (cint == 0)
1297 {
1298 continue;
1299 }
1300
1301 c = (char)cint;
1302 }
1303
1304 # endif /* ifdef LH_COMPLETION */
1305
1306 switch (c)
1307 {
1308 case 9:
1309 break; /* johnsonjh - disable processing of tabs */
1310
1311 case ENTER: /* Enter */
1312 history_len--;
1313 free(history[history_len]);
1314 if (mlmode)
1315 {
1316 linenoiseEditMoveEnd(&l);
1317 }
1318
1319 # ifdef LH_HINTS
1320 if (hintsCallback)
1321 {
1322
1323 /*
1324 * Force a refresh without hints to leave the previous
1325 * line as the user typed it after a newline.
1326 */
1327
1328 linenoiseHintsCallback *hc = hintsCallback;
1329 hintsCallback = NULL;
1330 refreshLine(&l);
1331 hintsCallback = hc;
1332 }
1333
1334 # endif /* ifdef LH_HINTS */
1335 return ((int)l.len );
1336
1337 case CTRL_C: /* Ctrl-C */
1338 errno = EAGAIN;
1339 return ( -1 );
1340
1341 case BACKSPACE: /* Backspace */
1342 case 8: /* Ctrl-H */
1343 linenoiseEditBackspace(&l);
1344 break;
1345
1346 case CTRL_D: /* Ctrl-D, remove char at right of cursor, or */
1347 if (l.len > 0) /* if the line is empty, act as end-of-file. */
1348 {
1349 linenoiseEditDelete(&l);
1350 }
1351 else
1352 {
1353 history_len--;
1354 free(history[history_len]);
1355 return ( -1 );
1356 }
1357
1358 break;
1359
1360 case CTRL_T: /* Ctrl-T */
1361 break;
1362
1363 case CTRL_B: /* Ctrl-B */
1364 linenoiseEditMoveLeft(&l);
1365 break;
1366
1367 case CTRL_F: /* Ctrl-F */
1368 linenoiseEditMoveRight(&l);
1369 break;
1370
1371 case CTRL_P: /* Ctrl-P */
1372 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
1373 break;
1374
1375 case CTRL_N: /* Ctrl-N */
1376 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
1377 break;
1378
1379 case ESC: /* Escape Sequence */
1380
1381 /*
1382 * Read the next two bytes representing the escape sequence.
1383 * Use two calls to handle slow terminals returning the two
1384 * chars at different times.
1385 */
1386
1387 if (read(l.ifd, seq, 1) == -1)
1388 {
1389 break;
1390 }
1391
1392 if (read(l.ifd, seq + 1, 1) == -1)
1393 {
1394 break;
1395 }
1396
1397 /* ESC [ sequences. */
1398 if (seq[0] == '[')
1399 {
1400 if (seq[1] >= '0' && seq[1] <= '9')
1401 {
1402 /* Extended escape, read additional byte. */
1403 if (read(l.ifd, seq + 2, 1) == -1)
1404 {
1405 break;
1406 }
1407
1408 if (seq[2] == '~')
1409 {
1410 switch (seq[1])
1411 {
1412 case '3': /* Delete */
1413 linenoiseEditDelete(&l);
1414 break;
1415
1416 case '6': /* Page Down */
1417 linenoiseSearchInHistory(
1418 &l,
1419 LINENOISE_SEARCH_HISTROY_REVERSE);
1420 break;
1421
1422 case '5': /* Page Up */
1423 linenoiseSearchInHistory(
1424 &l,
1425 LINENOISE_SEARCH_HISTORY_FORWARD);
1426 break;
1427 }
1428 }
1429 }
1430 else
1431 {
1432 switch (seq[1])
1433 {
1434 case 'A': /* Up */
1435 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
1436 break;
1437
1438 case 'B': /* Down */
1439 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
1440 break;
1441
1442 case 'C': /* Right */
1443 linenoiseEditMoveRight(&l);
1444 break;
1445
1446 case 'D': /* Left */
1447 linenoiseEditMoveLeft(&l);
1448 break;
1449
1450 case 'H': /* Home */
1451 linenoiseEditMoveHome(&l);
1452 break;
1453
1454 case 'F': /* End */
1455 linenoiseEditMoveEnd(&l);
1456 break;
1457 }
1458 }
1459 }
1460
1461 break;
1462
1463 default:
1464 if (linenoiseEditInsert(&l, c))
1465 {
1466 return ( -1 );
1467 }
1468
1469 break;
1470
1471 case CTRL_U: /* Ctrl+U, delete the whole line. */
1472 buf[0] = '\0';
1473 l.pos = l.len = 0;
1474 refreshLine(&l);
1475 break;
1476
1477 case CTRL_K: /* Ctrl+K, delete from current to end of line. */
1478 buf[l.pos] = '\0';
1479 l.len = l.pos;
1480 refreshLine(&l);
1481 break;
1482
1483 case CTRL_A: /* Ctrl+A, go to the start of the line */
1484 linenoiseEditMoveHome(&l);
1485 break;
1486
1487 case CTRL_E: /* Ctrl+E, go to the end of the line */
1488 linenoiseEditMoveEnd(&l);
1489 break;
1490
1491 case CTRL_L: /* Ctrl+L, clear screen */
1492 linenoiseClearScreen();
1493 refreshLine(&l);
1494 break;
1495
1496 case CTRL_W: /* Ctrl+W, delete previous word */
1497 linenoiseEditDeletePrevWord(&l);
1498 break;
1499 }
1500 }
1501 }
1502
1503 /*
1504 * This function calls the line editing function linenoiseEdit() using
1505 * the STDIN file descriptor set in raw mode.
1506 */
1507
1508 static int
linenoiseRaw(char * buf,size_t buflen,const char * prompt)1509 linenoiseRaw(char *buf, size_t buflen, const char *prompt)
1510 {
1511 int count;
1512
1513 if (buflen == 0)
1514 {
1515 errno = EINVAL;
1516 return ( -1 );
1517 }
1518
1519 if (enableRawMode(STDIN_FILENO) == -1)
1520 {
1521 return ( -1 );
1522 }
1523
1524 count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt);
1525 disableRawMode(STDIN_FILENO);
1526 printf("\n");
1527 return ( count );
1528 }
1529
1530 /*
1531 * This function is called when linenoise() is called with the standard
1532 * input file descriptor not attached to a TTY. So for example when the
1533 * program using linenoise is called in pipe or with a file redirected
1534 * to its standard input. In this case, we want to be able to return the
1535 * line regardless of its length (by default we are limited to 4k).
1536 */
1537
1538 static char *
linenoiseNoTTY(void)1539 linenoiseNoTTY(void)
1540 {
1541 char *line = NULL;
1542 size_t len = 0, maxlen = 0;
1543
1544 while (1)
1545 {
1546 if (len == maxlen)
1547 {
1548 if (maxlen == 0)
1549 {
1550 maxlen = 16;
1551 }
1552
1553 maxlen *= 2;
1554 char *oldval = line;
1555 line = realloc(line, maxlen);
1556 if (line == NULL)
1557 {
1558 if (oldval)
1559 {
1560 free(oldval);
1561 }
1562
1563 return ( NULL );
1564 }
1565 }
1566
1567 int c = fgetc(stdin);
1568 if (c == EOF || c == '\n')
1569 {
1570 if (c == EOF && len == 0)
1571 {
1572 free(line);
1573 return ( NULL );
1574 }
1575 else
1576 {
1577 line[len] = '\0';
1578 return ( line );
1579 }
1580 }
1581 else
1582 {
1583 line[len] = c;
1584 len++;
1585 }
1586 }
1587 }
1588
1589 /*
1590 * The high level function that is the main API of the linenoise library.
1591 * This function checks if the terminal has basic capabilities, just checking
1592 * for a blacklist of stupid terminals, and later either calls the line
1593 * editing function or uses dummy fgets() so that you will be able to type
1594 * something even in the most desperate of the conditions.
1595 */
1596
1597 char *
linenoise(const char * prompt)1598 linenoise(const char *prompt)
1599 {
1600 char buf[LINENOISE_MAX_LINE];
1601 int count;
1602
1603 if (!isatty(STDIN_FILENO))
1604 {
1605
1606 /*
1607 * Not a tty: read from file / pipe. In this mode we don't want any
1608 * limit to the line size, so we call a function to handle that.
1609 */
1610
1611 return ( linenoiseNoTTY());
1612 }
1613 else if (isUnsupportedTerm())
1614 {
1615 size_t len;
1616
1617 printf("%s", prompt);
1618 fflush(stdout);
1619 if (fgets(buf, LINENOISE_MAX_LINE, stdin) == NULL)
1620 {
1621 return ( NULL );
1622 }
1623
1624 len = strlen(buf);
1625 while (len && ( buf[len - 1] == '\n' || buf[len - 1] == '\r' ))
1626 {
1627 len--;
1628 buf[len] = '\0';
1629 }
1630 return ( strdup(buf));
1631 }
1632 else
1633 {
1634 count = linenoiseRaw(buf, LINENOISE_MAX_LINE, prompt);
1635 if (count == -1)
1636 {
1637 return ( NULL );
1638 }
1639
1640 return ( strdup(buf));
1641 }
1642 }
1643
1644 /*
1645 * This is just a wrapper the user may want to call in order to make sure
1646 * the linenoise returned buffer is freed with the same allocator it was
1647 * created with. Useful when the main program is using an alternative
1648 * allocator.
1649 */
1650
1651 void
linenoiseFree(void * ptr)1652 linenoiseFree(void *ptr)
1653 {
1654 free(ptr);
1655 }
1656
1657 /*
1658 * Free the history, but does not reset it. Only used when we have to
1659 * exit() to avoid memory leaks are reported by valgrind & co.
1660 */
1661
1662 static void
freeHistory(void)1663 freeHistory(void)
1664 {
1665 if (history)
1666 {
1667 int j;
1668
1669 for (j = 0; j < history_len; j++)
1670 {
1671 free(history[j]);
1672 }
1673
1674 free(history);
1675 }
1676 }
1677
1678 /* At exit we'll try to fix the terminal to the initial conditions. */
1679 static void
linenoiseAtExit(void)1680 linenoiseAtExit(void)
1681 {
1682 disableRawMode(STDIN_FILENO);
1683 freeHistory();
1684 }
1685
1686 /*
1687 * This is the API call to add a new entry in the linenoise history.
1688 * It uses a fixed array of char pointers that are shifted (memmoved)
1689 * when the history max length is reached in order to remove the older
1690 * entry and make room for the new one, so it is not exactly suitable for huge
1691 * histories, but will work well for a few hundred of entries.
1692 */
1693
1694 int
linenoiseHistoryAdd(const char * line)1695 linenoiseHistoryAdd(const char *line)
1696 {
1697 char *linecopy;
1698
1699 if (history_max_len == 0)
1700 {
1701 return ( 0 );
1702 }
1703
1704 /* Initialization on first call. */
1705 if (history == NULL)
1706 {
1707 history = malloc(sizeof ( char * ) * history_max_len);
1708 if (history == NULL)
1709 {
1710 return ( 0 );
1711 }
1712
1713 memset(history, 0, ( sizeof ( char * ) * history_max_len ));
1714 }
1715
1716 /* Don't add duplicated lines. */
1717 if (( history_len > 0 ) && ( !strcmp(history[history_len - 1], line)))
1718 {
1719 return ( 0 );
1720 }
1721
1722 /*
1723 * Add an heap allocated copy of the line in the history.
1724 * If we reached the max length, remove the older line.
1725 */
1726
1727 linecopy = strdup(line);
1728 if (!linecopy)
1729 {
1730 return ( 0 );
1731 }
1732
1733 if (history_len == history_max_len)
1734 {
1735 free(history[0]);
1736 memmove(
1737 history,
1738 history + 1,
1739 sizeof ( char * ) * ( history_max_len - 1 ));
1740 history_len--;
1741 }
1742
1743 history[history_len] = linecopy;
1744 history_len++;
1745 return ( 1 );
1746 }
1747
1748 /*
1749 * Set the maximum length for the history. This function can be called even
1750 * if there is already some history, the function will make sure to retain
1751 * just the latest 'len' elements if the new history length value is smaller
1752 * than the amount of items already inside the history.
1753 */
1754
1755 int
linenoiseHistorySetMaxLen(int len)1756 linenoiseHistorySetMaxLen(int len)
1757 {
1758 char **new;
1759
1760 if (len < 1)
1761 {
1762 return ( 0 );
1763 }
1764
1765 if (history)
1766 {
1767 int tocopy = history_len;
1768
1769 new = malloc(sizeof ( char * ) * len);
1770 if (new == NULL)
1771 {
1772 return ( 0 );
1773 }
1774
1775 /* If we can't copy everything, free the elements we'll not use. */
1776 if (len < tocopy)
1777 {
1778 int j;
1779
1780 for (j = 0; j < tocopy - len; j++)
1781 {
1782 free(history[j]);
1783 }
1784
1785 tocopy = len;
1786 }
1787
1788 memset(new, 0, sizeof ( char * ) * len);
1789 memcpy(
1790 new,
1791 history + ( history_len - tocopy ),
1792 sizeof ( char * ) * tocopy);
1793 free(history);
1794 history = new;
1795 }
1796
1797 history_max_len = len;
1798 if (history_len > history_max_len)
1799 {
1800 history_len = history_max_len;
1801 }
1802
1803 return ( 1 );
1804 }
1805
1806 /* Calculate length of the prompt string as seen from a terminal. */
1807 size_t
pstrlen(const char * s)1808 pstrlen(const char *s)
1809 {
1810 size_t len = 0, i = 0;
1811
1812 while (s[i] != '\0')
1813 {
1814 if (s[i] == '\033')
1815 {
1816 i = strpbrk(s + i, "m") - s + 1;
1817 continue;
1818 }
1819
1820 len++;
1821 i++;
1822 }
1823 return ( len );
1824 }
1825
1826 #endif /* if !defined( __MINGW32__ )
1827 && !defined( CROSS_MINGW32 )
1828 && !defined( CROSS_MINGW64 )
1829 && !defined( __MINGW64__ )
1830 && !defined( _MSC_VER )
1831 && !defined( _MSC_BUILD ) */
1832