configure: allow "--full" options to be explicitly disabled
[jimtcl.git] / linenoise.c
blobae1f166fc0024ee4a9a945745cad7a5487ab8508
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.
4 * You can find the latest source code at:
6 * http://github.com/msteveb/linenoise
7 * (forked from http://github.com/antirez/linenoise)
9 * Does a number of crazy assumptions that happen to be true in 99.9999% of
10 * the 2010 UNIX computers around.
12 * ------------------------------------------------------------------------
14 * Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
15 * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
16 * Copyright (c) 2011, Steve Bennett <steveb at workware dot net dot au>
18 * All rights reserved.
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions are
22 * met:
24 * * Redistributions of source code must retain the above copyright
25 * notice, this list of conditions and the following disclaimer.
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.
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.
43 * ------------------------------------------------------------------------
45 * References:
46 * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
47 * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html
49 * Bloat:
50 * - Completion?
52 * Unix/termios
53 * ------------
54 * List of escape sequences used by this program, we do everything just
55 * a few 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.
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
65 * CUF (CUrsor Forward)
66 * Sequence: ESC [ n C
67 * Effect: moves cursor forward of n chars
69 * CR (Carriage Return)
70 * Sequence: \r
71 * Effect: moves cursor to column 1
73 * The following are used to clear the screen: ESC [ H ESC [ 2 J
74 * This is actually composed of two sequences:
76 * cursorhome
77 * Sequence: ESC [ H
78 * Effect: moves the cursor to upper left corner
80 * ED2 (Clear entire screen)
81 * Sequence: ESC [ 2 J
82 * Effect: clear the whole screen
84 * == For highlighting control characters, we also use the following two ==
85 * SO (enter StandOut)
86 * Sequence: ESC [ 7 m
87 * Effect: Uses some standout mode such as reverse video
89 * SE (Standout End)
90 * Sequence: ESC [ 0 m
91 * Effect: Exit standout mode
93 * == Only used if TIOCGWINSZ fails ==
94 * DSR/CPR (Report cursor position)
95 * Sequence: ESC [ 6 n
96 * Effect: reports current cursor position as ESC [ NNN ; MMM R
98 * win32/console
99 * -------------
100 * If __MINGW32__ is defined, the win32 console API is used.
101 * This could probably be made to work for the msvc compiler too.
102 * This support based in part on work by Jon Griffiths.
105 #ifdef _WIN32 /* Windows platform, either MinGW or Visual Studio (MSVC) */
106 #include <windows.h>
107 #include <fcntl.h>
108 #define USE_WINCONSOLE
109 #ifdef __MINGW32__
110 #define HAVE_UNISTD_H
111 #else
112 /* Microsoft headers don't like old POSIX names */
113 #define strdup _strdup
114 #define snprintf _snprintf
115 #endif
116 #else
117 #include <termios.h>
118 #include <sys/ioctl.h>
119 #include <sys/poll.h>
120 #define USE_TERMIOS
121 #define HAVE_UNISTD_H
122 #endif
124 #ifdef HAVE_UNISTD_H
125 #include <unistd.h>
126 #endif
127 #include <stdlib.h>
128 #include <stdarg.h>
129 #include <stdio.h>
130 #include <errno.h>
131 #include <string.h>
132 #include <stdlib.h>
133 #include <sys/types.h>
135 #include "linenoise.h"
136 #include "utf8.h"
138 #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
139 #define LINENOISE_MAX_LINE 4096
141 #define ctrl(C) ((C) - '@')
143 /* Use -ve numbers here to co-exist with normal unicode chars */
144 enum {
145 SPECIAL_NONE,
146 SPECIAL_UP = -20,
147 SPECIAL_DOWN = -21,
148 SPECIAL_LEFT = -22,
149 SPECIAL_RIGHT = -23,
150 SPECIAL_DELETE = -24,
151 SPECIAL_HOME = -25,
152 SPECIAL_END = -26,
153 SPECIAL_INSERT = -27,
154 SPECIAL_PAGE_UP = -28,
155 SPECIAL_PAGE_DOWN = -29
158 static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
159 static int history_len = 0;
160 static char **history = NULL;
162 /* Structure to contain the status of the current (being edited) line */
163 struct current {
164 char *buf; /* Current buffer. Always null terminated */
165 int bufmax; /* Size of the buffer, including space for the null termination */
166 int len; /* Number of bytes in 'buf' */
167 int chars; /* Number of chars in 'buf' (utf-8 chars) */
168 int pos; /* Cursor position, measured in chars */
169 int cols; /* Size of the window, in chars */
170 const char *prompt;
171 char *capture; /* Allocated capture buffer, or NULL for none. Always null terminated */
172 #if defined(USE_TERMIOS)
173 int fd; /* Terminal fd */
174 #elif defined(USE_WINCONSOLE)
175 HANDLE outh; /* Console output handle */
176 HANDLE inh; /* Console input handle */
177 int rows; /* Screen rows */
178 int x; /* Current column during output */
179 int y; /* Current row */
180 #endif
183 static int fd_read(struct current *current);
184 static int getWindowSize(struct current *current);
186 void linenoiseHistoryFree(void) {
187 if (history) {
188 int j;
190 for (j = 0; j < history_len; j++)
191 free(history[j]);
192 free(history);
193 history = NULL;
194 history_len = 0;
198 #if defined(USE_TERMIOS)
199 static void linenoiseAtExit(void);
200 static struct termios orig_termios; /* in order to restore at exit */
201 static int rawmode = 0; /* for atexit() function to check if restore is needed*/
202 static int atexit_registered = 0; /* register atexit just 1 time */
204 static const char *unsupported_term[] = {"dumb","cons25",NULL};
206 static int isUnsupportedTerm(void) {
207 char *term = getenv("TERM");
209 if (term) {
210 int j;
211 for (j = 0; unsupported_term[j]; j++) {
212 if (strcmp(term, unsupported_term[j]) == 0) {
213 return 1;
217 return 0;
220 static int enableRawMode(struct current *current) {
221 struct termios raw;
223 current->fd = STDIN_FILENO;
224 current->cols = 0;
226 if (!isatty(current->fd) || isUnsupportedTerm() ||
227 tcgetattr(current->fd, &orig_termios) == -1) {
228 fatal:
229 errno = ENOTTY;
230 return -1;
233 if (!atexit_registered) {
234 atexit(linenoiseAtExit);
235 atexit_registered = 1;
238 raw = orig_termios; /* modify the original mode */
239 /* input modes: no break, no CR to NL, no parity check, no strip char,
240 * no start/stop output control. */
241 raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
242 /* output modes - actually, no need to disable post processing */
243 /*raw.c_oflag &= ~(OPOST);*/
244 /* control modes - set 8 bit chars */
245 raw.c_cflag |= (CS8);
246 /* local modes - choing off, canonical off, no extended functions,
247 * no signal chars (^Z,^C) */
248 raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
249 /* control chars - set return condition: min number of bytes and timer.
250 * We want read to return every single byte, without timeout. */
251 raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
253 /* put terminal in raw mode after flushing */
254 if (tcsetattr(current->fd,TCSADRAIN,&raw) < 0) {
255 goto fatal;
257 rawmode = 1;
258 return 0;
261 static void disableRawMode(struct current *current) {
262 /* Don't even check the return value as it's too late. */
263 if (rawmode && tcsetattr(current->fd,TCSADRAIN,&orig_termios) != -1)
264 rawmode = 0;
267 /* At exit we'll try to fix the terminal to the initial conditions. */
268 static void linenoiseAtExit(void) {
269 if (rawmode) {
270 tcsetattr(STDIN_FILENO, TCSADRAIN, &orig_termios);
272 linenoiseHistoryFree();
275 /* gcc/glibc insists that we care about the return code of write!
276 * Clarification: This means that a void-cast like "(void) (EXPR)"
277 * does not work.
279 #define IGNORE_RC(EXPR) if (EXPR) {}
281 /* This is fdprintf() on some systems, but use a different
282 * name to avoid conflicts
284 static void fd_printf(int fd, const char *format, ...)
286 va_list args;
287 char buf[64];
288 int n;
290 va_start(args, format);
291 n = vsnprintf(buf, sizeof(buf), format, args);
292 va_end(args);
293 IGNORE_RC(write(fd, buf, n));
296 void linenoiseClearScreen(void)
298 fd_printf(STDOUT_FILENO, "\x1b[H\x1b[2J");
301 static void cursorToLeft(struct current *current)
303 fd_printf(current->fd, "\r");
306 static int outputChars(struct current *current, const char *buf, int len)
308 return write(current->fd, buf, len);
311 static void outputControlChar(struct current *current, char ch)
313 fd_printf(current->fd, "\x1b[7m^%c\x1b[0m", ch);
316 static void eraseEol(struct current *current)
318 fd_printf(current->fd, "\x1b[0K");
321 static void setCursorPos(struct current *current, int x)
323 if (x == 0) {
324 cursorToLeft(current);
326 else {
327 fd_printf(current->fd, "\r\x1b[%dC", x);
332 * Reads a char from 'fd', waiting at most 'timeout' milliseconds.
334 * A timeout of -1 means to wait forever.
336 * Returns -1 if no char is received within the time or an error occurs.
338 static int fd_read_char(int fd, int timeout)
340 struct pollfd p;
341 unsigned char c;
343 p.fd = fd;
344 p.events = POLLIN;
346 if (poll(&p, 1, timeout) == 0) {
347 /* timeout */
348 return -1;
350 if (read(fd, &c, 1) != 1) {
351 return -1;
353 return c;
357 * Reads a complete utf-8 character
358 * and returns the unicode value, or -1 on error.
360 static int fd_read(struct current *current)
362 #ifdef USE_UTF8
363 char buf[4];
364 int n;
365 int i;
366 int c;
368 if (read(current->fd, &buf[0], 1) != 1) {
369 return -1;
371 n = utf8_charlen(buf[0]);
372 if (n < 1 || n > 3) {
373 return -1;
375 for (i = 1; i < n; i++) {
376 if (read(current->fd, &buf[i], 1) != 1) {
377 return -1;
380 buf[n] = 0;
381 /* decode and return the character */
382 utf8_tounicode(buf, &c);
383 return c;
384 #else
385 return fd_read_char(current->fd, -1);
386 #endif
389 static int countColorControlChars(const char* prompt)
391 /* ANSI color control sequences have the form:
392 * "\x1b" "[" [0-9;]* "m"
393 * We parse them with a simple state machine.
396 enum {
397 search_esc,
398 expect_bracket,
399 expect_trail
400 } state = search_esc;
401 int len = 0, found = 0;
402 char ch;
404 /* XXX: Strictly we should be checking utf8 chars rather than
405 * bytes in case of the extremely unlikely scenario where
406 * an ANSI sequence is part of a utf8 sequence.
408 while ((ch = *prompt++) != 0) {
409 switch (state) {
410 case search_esc:
411 if (ch == '\x1b') {
412 state = expect_bracket;
414 break;
415 case expect_bracket:
416 if (ch == '[') {
417 state = expect_trail;
418 /* 3 for "\e[ ... m" */
419 len = 3;
420 break;
422 state = search_esc;
423 break;
424 case expect_trail:
425 if ((ch == ';') || ((ch >= '0' && ch <= '9'))) {
426 /* 0-9, or semicolon */
427 len++;
428 break;
430 if (ch == 'm') {
431 found += len;
433 state = search_esc;
434 break;
438 return found;
442 * Stores the current cursor column in '*cols'.
443 * Returns 1 if OK, or 0 if failed to determine cursor pos.
445 static int queryCursor(int fd, int* cols)
447 /* control sequence - report cursor location */
448 fd_printf(fd, "\x1b[6n");
450 /* Parse the response: ESC [ rows ; cols R */
451 if (fd_read_char(fd, 100) == 0x1b &&
452 fd_read_char(fd, 100) == '[') {
454 int n = 0;
455 while (1) {
456 int ch = fd_read_char(fd, 100);
457 if (ch == ';') {
458 /* Ignore rows */
459 n = 0;
461 else if (ch == 'R') {
462 /* Got cols */
463 if (n != 0 && n < 1000) {
464 *cols = n;
466 break;
468 else if (ch >= 0 && ch <= '9') {
469 n = n * 10 + ch - '0';
471 else {
472 break;
475 return 1;
478 return 0;
482 * Updates current->cols with the current window size (width)
484 static int getWindowSize(struct current *current)
486 struct winsize ws;
488 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 && ws.ws_col != 0) {
489 current->cols = ws.ws_col;
490 return 0;
493 /* Failed to query the window size. Perhaps we are on a serial terminal.
494 * Try to query the width by sending the cursor as far to the right
495 * and reading back the cursor position.
496 * Note that this is only done once per call to linenoise rather than
497 * every time the line is refreshed for efficiency reasons.
499 * In more detail, we:
500 * (a) request current cursor position,
501 * (b) move cursor far right,
502 * (c) request cursor position again,
503 * (d) at last move back to the old position.
504 * This gives us the width without messing with the externally
505 * visible cursor position.
508 if (current->cols == 0) {
509 int here;
511 current->cols = 80;
513 /* (a) */
514 if (queryCursor (current->fd, &here)) {
515 /* (b) */
516 fd_printf(current->fd, "\x1b[999C");
518 /* (c). Note: If (a) succeeded, then (c) should as well.
519 * For paranoia we still check and have a fallback action
520 * for (d) in case of failure..
522 if (!queryCursor (current->fd, &current->cols)) {
523 /* (d') Unable to get accurate position data, reset
524 * the cursor to the far left. While this may not
525 * restore the exact original position it should not
526 * be too bad.
528 fd_printf(current->fd, "\r");
529 } else {
530 /* (d) Reset the cursor back to the original location. */
531 if (current->cols > here) {
532 fd_printf(current->fd, "\x1b[%dD", current->cols - here);
535 } /* 1st query failed, doing nothing => default 80 */
538 return 0;
542 * If escape (27) was received, reads subsequent
543 * chars to determine if this is a known special key.
545 * Returns SPECIAL_NONE if unrecognised, or -1 if EOF.
547 * If no additional char is received within a short time,
548 * 27 is returned.
550 static int check_special(int fd)
552 int c = fd_read_char(fd, 50);
553 int c2;
555 if (c < 0) {
556 return 27;
559 c2 = fd_read_char(fd, 50);
560 if (c2 < 0) {
561 return c2;
563 if (c == '[' || c == 'O') {
564 /* Potential arrow key */
565 switch (c2) {
566 case 'A':
567 return SPECIAL_UP;
568 case 'B':
569 return SPECIAL_DOWN;
570 case 'C':
571 return SPECIAL_RIGHT;
572 case 'D':
573 return SPECIAL_LEFT;
574 case 'F':
575 return SPECIAL_END;
576 case 'H':
577 return SPECIAL_HOME;
580 if (c == '[' && c2 >= '1' && c2 <= '8') {
581 /* extended escape */
582 c = fd_read_char(fd, 50);
583 if (c == '~') {
584 switch (c2) {
585 case '2':
586 return SPECIAL_INSERT;
587 case '3':
588 return SPECIAL_DELETE;
589 case '5':
590 return SPECIAL_PAGE_UP;
591 case '6':
592 return SPECIAL_PAGE_DOWN;
593 case '7':
594 return SPECIAL_HOME;
595 case '8':
596 return SPECIAL_END;
599 while (c != -1 && c != '~') {
600 /* .e.g \e[12~ or '\e[11;2~ discard the complete sequence */
601 c = fd_read_char(fd, 50);
605 return SPECIAL_NONE;
607 #elif defined(USE_WINCONSOLE)
609 static DWORD orig_consolemode = 0;
611 static int enableRawMode(struct current *current) {
612 DWORD n;
613 INPUT_RECORD irec;
615 current->outh = GetStdHandle(STD_OUTPUT_HANDLE);
616 current->inh = GetStdHandle(STD_INPUT_HANDLE);
618 if (!PeekConsoleInput(current->inh, &irec, 1, &n)) {
619 return -1;
621 if (getWindowSize(current) != 0) {
622 return -1;
624 if (GetConsoleMode(current->inh, &orig_consolemode)) {
625 SetConsoleMode(current->inh, ENABLE_PROCESSED_INPUT);
627 return 0;
630 static void disableRawMode(struct current *current)
632 SetConsoleMode(current->inh, orig_consolemode);
635 void linenoiseClearScreen(void)
637 /* XXX: This is ugly. Should just have the caller pass a handle */
638 struct current current;
640 current.outh = GetStdHandle(STD_OUTPUT_HANDLE);
642 if (getWindowSize(&current) == 0) {
643 COORD topleft = { 0, 0 };
644 DWORD n;
646 FillConsoleOutputCharacter(current.outh, ' ',
647 current.cols * current.rows, topleft, &n);
648 FillConsoleOutputAttribute(current.outh,
649 FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN,
650 current.cols * current.rows, topleft, &n);
651 SetConsoleCursorPosition(current.outh, topleft);
655 static void cursorToLeft(struct current *current)
657 COORD pos;
658 DWORD n;
660 pos.X = 0;
661 pos.Y = (SHORT)current->y;
663 FillConsoleOutputAttribute(current->outh,
664 FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN, current->cols, pos, &n);
665 current->x = 0;
668 static int outputChars(struct current *current, const char *buf, int len)
670 COORD pos;
671 DWORD n;
673 pos.Y = (SHORT)current->y;
675 #ifdef USE_UTF8
676 while ( len > 0 ) {
677 int c, s;
678 wchar_t wc;
680 s = utf8_tounicode(buf, &c);
682 len -= s;
683 buf += s;
685 wc = (wchar_t)c;
687 pos.X = (SHORT)current->x;
689 /* fixed display utf8 character */
690 WriteConsoleOutputCharacterW(current->outh, &wc, 1, pos, &n);
692 current->x += utf8_width(c);
694 #else
695 pos.X = (SHORT)current->x;
697 WriteConsoleOutputCharacterA(current->outh, buf, len, pos, &n);
698 current->x += len;
699 #endif
701 return 0;
704 static void outputControlChar(struct current *current, char ch)
706 COORD pos;
707 DWORD n;
709 pos.X = (SHORT) current->x;
710 pos.Y = (SHORT) current->y;
712 FillConsoleOutputAttribute(current->outh, BACKGROUND_INTENSITY, 2, pos, &n);
713 outputChars(current, "^", 1);
714 outputChars(current, &ch, 1);
717 static void eraseEol(struct current *current)
719 COORD pos;
720 DWORD n;
722 pos.X = (SHORT) current->x;
723 pos.Y = (SHORT) current->y;
725 FillConsoleOutputCharacter(current->outh, ' ', current->cols - current->x, pos, &n);
728 static void setCursorPos(struct current *current, int x)
730 COORD pos;
732 pos.X = (SHORT)x;
733 pos.Y = (SHORT) current->y;
735 SetConsoleCursorPosition(current->outh, pos);
736 current->x = x;
739 static int fd_read(struct current *current)
741 while (1) {
742 INPUT_RECORD irec;
743 DWORD n;
744 if (WaitForSingleObject(current->inh, INFINITE) != WAIT_OBJECT_0) {
745 break;
747 if (!ReadConsoleInput (current->inh, &irec, 1, &n)) {
748 break;
750 if (irec.EventType == KEY_EVENT && irec.Event.KeyEvent.bKeyDown) {
751 KEY_EVENT_RECORD *k = &irec.Event.KeyEvent;
752 if (k->dwControlKeyState & ENHANCED_KEY) {
753 switch (k->wVirtualKeyCode) {
754 case VK_LEFT:
755 return SPECIAL_LEFT;
756 case VK_RIGHT:
757 return SPECIAL_RIGHT;
758 case VK_UP:
759 return SPECIAL_UP;
760 case VK_DOWN:
761 return SPECIAL_DOWN;
762 case VK_INSERT:
763 return SPECIAL_INSERT;
764 case VK_DELETE:
765 return SPECIAL_DELETE;
766 case VK_HOME:
767 return SPECIAL_HOME;
768 case VK_END:
769 return SPECIAL_END;
770 case VK_PRIOR:
771 return SPECIAL_PAGE_UP;
772 case VK_NEXT:
773 return SPECIAL_PAGE_DOWN;
776 /* Note that control characters are already translated in AsciiChar */
777 else if (k->wVirtualKeyCode == VK_CONTROL)
778 continue;
779 else {
780 #ifdef USE_UTF8
781 return k->uChar.UnicodeChar;
782 #else
783 return k->uChar.AsciiChar;
784 #endif
788 return -1;
791 static int countColorControlChars(const char* prompt)
793 /* For windows we assume that there are no embedded ansi color
794 * control sequences.
796 return 0;
799 static int getWindowSize(struct current *current)
801 CONSOLE_SCREEN_BUFFER_INFO info;
802 if (!GetConsoleScreenBufferInfo(current->outh, &info)) {
803 return -1;
805 current->cols = info.dwSize.X;
806 current->rows = info.dwSize.Y;
807 if (current->cols <= 0 || current->rows <= 0) {
808 current->cols = 80;
809 return -1;
811 current->y = info.dwCursorPosition.Y;
812 current->x = info.dwCursorPosition.X;
813 return 0;
815 #endif
817 #ifndef utf8_getchars
818 static int utf8_getchars(char *buf, int c)
820 #ifdef USE_UTF8
821 return utf8_fromunicode(buf, c);
822 #else
823 *buf = c;
824 return 1;
825 #endif
827 #endif
830 * Returns the unicode character at the given offset,
831 * or -1 if none.
833 static int get_char(struct current *current, int pos)
835 if (pos >= 0 && pos < current->chars) {
836 int c;
837 int i = utf8_index(current->buf, pos);
838 (void)utf8_tounicode(current->buf + i, &c);
839 return c;
841 return -1;
844 static void refreshLine(const char *prompt, struct current *current)
846 int plen;
847 int pchars;
848 int backup = 0;
849 int i;
850 const char *buf = current->buf;
851 int chars = current->chars;
852 int pos = current->pos;
853 int b;
854 int ch;
855 int n;
856 int width;
857 int bufwidth;
859 /* Should intercept SIGWINCH. For now, just get the size every time */
860 getWindowSize(current);
862 plen = strlen(prompt);
863 pchars = utf8_strwidth(prompt, utf8_strlen(prompt, plen));
865 /* Scan the prompt for embedded ansi color control sequences and
866 * discount them as characters/columns.
868 pchars -= countColorControlChars(prompt);
870 /* Account for a line which is too long to fit in the window.
871 * Note that control chars require an extra column
874 /* How many cols are required to the left of 'pos'?
875 * The prompt, plus one extra for each control char
877 n = pchars + utf8_strwidth(buf, utf8_strlen(buf, current->len));
878 b = 0;
879 for (i = 0; i < pos; i++) {
880 b += utf8_tounicode(buf + b, &ch);
881 if (ch < ' ') {
882 n++;
886 /* Pluse one if the current char is a control character */
887 if (current->pos < current->chars && get_char(current, current->pos) < ' ') {
888 n++;
891 /* If too many are needed, strip chars off the front of 'buf'
892 * until it fits. Note that if the current char is a control character,
893 * we need one extra col.
895 while (n >= current->cols && pos > 0) {
896 b = utf8_tounicode(buf, &ch);
897 if (ch < ' ') {
898 n--;
900 n -= utf8_width(ch);
901 buf += b;
902 pos--;
903 chars--;
906 /* Cursor to left edge, then the prompt */
907 cursorToLeft(current);
908 outputChars(current, prompt, plen);
910 /* Now the current buffer content */
912 /* Need special handling for control characters.
913 * If we hit 'cols', stop.
915 b = 0; /* unwritted bytes */
916 n = 0; /* How many control chars were written */
917 width = 0; /* current display width */
918 bufwidth = utf8_strwidth(buf, pos);
920 for (i = 0; i < chars; i++) {
921 int ch;
922 int w = utf8_tounicode(buf + b, &ch);
923 if (ch < ' ') {
924 n++;
927 width += utf8_width(ch);
929 if (pchars + width + n >= current->cols) {
930 break;
932 if (ch < ' ') {
933 /* A control character, so write the buffer so far */
934 outputChars(current, buf, b);
935 buf += b + w;
936 b = 0;
937 outputControlChar(current, ch + '@');
938 if (i < pos) {
939 backup++;
942 else {
943 b += w;
946 outputChars(current, buf, b);
948 /* Erase to right, move cursor to original position */
949 eraseEol(current);
950 setCursorPos(current, bufwidth + pchars + backup);
953 static void set_current(struct current *current, const char *str)
955 strncpy(current->buf, str, current->bufmax);
956 current->buf[current->bufmax - 1] = 0;
957 current->len = strlen(current->buf);
958 current->pos = current->chars = utf8_strlen(current->buf, current->len);
961 static int has_room(struct current *current, int bytes)
963 return current->len + bytes < current->bufmax - 1;
967 * Removes the char at 'pos'.
969 * Returns 1 if the line needs to be refreshed, 2 if not
970 * and 0 if nothing was removed
972 static int remove_char(struct current *current, int pos)
974 if (pos >= 0 && pos < current->chars) {
975 int p1, p2;
976 int ret = 1;
977 p1 = utf8_index(current->buf, pos);
978 p2 = p1 + utf8_index(current->buf + p1, 1);
980 #ifdef USE_TERMIOS
981 /* optimise remove char in the case of removing the last char */
982 if (current->pos == pos + 1 && current->pos == current->chars) {
983 if (current->buf[pos] >= ' ' && utf8_strlen(current->prompt, -1) + utf8_strlen(current->buf, current->len) < current->cols - 1) {
984 ret = 2;
985 fd_printf(current->fd, "\b \b");
988 #endif
990 /* Move the null char too */
991 memmove(current->buf + p1, current->buf + p2, current->len - p2 + 1);
992 current->len -= (p2 - p1);
993 current->chars--;
995 if (current->pos > pos) {
996 current->pos--;
998 return ret;
1000 return 0;
1004 * Insert 'ch' at position 'pos'
1006 * Returns 1 if the line needs to be refreshed, 2 if not
1007 * and 0 if nothing was inserted (no room)
1009 static int insert_char(struct current *current, int pos, int ch)
1011 char buf[3];
1012 int n = utf8_getchars(buf, ch);
1014 if (has_room(current, n) && pos >= 0 && pos <= current->chars) {
1015 int p1, p2;
1016 int ret = 1;
1017 p1 = utf8_index(current->buf, pos);
1018 p2 = p1 + n;
1020 #ifdef USE_TERMIOS
1021 /* optimise the case where adding a single char to the end and no scrolling is needed */
1022 if (current->pos == pos && current->chars == pos) {
1023 if (ch >= ' ' && utf8_strlen(current->prompt, -1) + utf8_strlen(current->buf, current->len) < current->cols - 1) {
1024 IGNORE_RC(write(current->fd, buf, n));
1025 ret = 2;
1028 #endif
1030 memmove(current->buf + p2, current->buf + p1, current->len - p1);
1031 memcpy(current->buf + p1, buf, n);
1032 current->len += n;
1034 current->chars++;
1035 if (current->pos >= pos) {
1036 current->pos++;
1038 return ret;
1040 return 0;
1044 * Captures up to 'n' characters starting at 'pos' for the cut buffer.
1046 * This replaces any existing characters in the cut buffer.
1048 static void capture_chars(struct current *current, int pos, int n)
1050 if (pos >= 0 && (pos + n - 1) < current->chars) {
1051 int p1 = utf8_index(current->buf, pos);
1052 int nbytes = utf8_index(current->buf + p1, n);
1054 if (nbytes) {
1055 free(current->capture);
1056 /* Include space for the null terminator */
1057 current->capture = (char *)malloc(nbytes + 1);
1058 memcpy(current->capture, current->buf + p1, nbytes);
1059 current->capture[nbytes] = '\0';
1065 * Removes up to 'n' characters at cursor position 'pos'.
1067 * Returns 0 if no chars were removed or non-zero otherwise.
1069 static int remove_chars(struct current *current, int pos, int n)
1071 int removed = 0;
1073 /* First save any chars which will be removed */
1074 capture_chars(current, pos, n);
1076 while (n-- && remove_char(current, pos)) {
1077 removed++;
1079 return removed;
1082 * Inserts the characters (string) 'chars' at the cursor position 'pos'.
1084 * Returns 0 if no chars were inserted or non-zero otherwise.
1086 static int insert_chars(struct current *current, int pos, const char *chars)
1088 int inserted = 0;
1090 while (*chars) {
1091 int ch;
1092 int n = utf8_tounicode(chars, &ch);
1093 if (insert_char(current, pos, ch) == 0) {
1094 break;
1096 inserted++;
1097 pos++;
1098 chars += n;
1100 return inserted;
1103 #ifndef NO_COMPLETION
1104 static linenoiseCompletionCallback *completionCallback = NULL;
1105 static void *completionUserdata = NULL;
1107 static void beep() {
1108 #ifdef USE_TERMIOS
1109 fprintf(stderr, "\x7");
1110 fflush(stderr);
1111 #endif
1114 static void freeCompletions(linenoiseCompletions *lc) {
1115 size_t i;
1116 for (i = 0; i < lc->len; i++)
1117 free(lc->cvec[i]);
1118 free(lc->cvec);
1121 static int completeLine(struct current *current) {
1122 linenoiseCompletions lc = { 0, NULL };
1123 int c = 0;
1125 completionCallback(current->buf,&lc,completionUserdata);
1126 if (lc.len == 0) {
1127 beep();
1128 } else {
1129 size_t stop = 0, i = 0;
1131 while(!stop) {
1132 /* Show completion or original buffer */
1133 if (i < lc.len) {
1134 struct current tmp = *current;
1135 tmp.buf = lc.cvec[i];
1136 tmp.pos = tmp.len = strlen(tmp.buf);
1137 tmp.chars = utf8_strlen(tmp.buf, tmp.len);
1138 refreshLine(current->prompt, &tmp);
1139 } else {
1140 refreshLine(current->prompt, current);
1143 c = fd_read(current);
1144 if (c == -1) {
1145 break;
1148 switch(c) {
1149 case '\t': /* tab */
1150 i = (i+1) % (lc.len+1);
1151 if (i == lc.len) beep();
1152 break;
1153 case 27: /* escape */
1154 /* Re-show original buffer */
1155 if (i < lc.len) {
1156 refreshLine(current->prompt, current);
1158 stop = 1;
1159 break;
1160 default:
1161 /* Update buffer and return */
1162 if (i < lc.len) {
1163 set_current(current,lc.cvec[i]);
1165 stop = 1;
1166 break;
1171 freeCompletions(&lc);
1172 return c; /* Return last read character */
1175 /* Register a callback function to be called for tab-completion.
1176 Returns the prior callback so that the caller may (if needed)
1177 restore it when done. */
1178 linenoiseCompletionCallback * linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn, void *userdata) {
1179 linenoiseCompletionCallback * old = completionCallback;
1180 completionCallback = fn;
1181 completionUserdata = userdata;
1182 return old;
1185 void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
1186 lc->cvec = (char **)realloc(lc->cvec,sizeof(char*)*(lc->len+1));
1187 lc->cvec[lc->len++] = strdup(str);
1190 #endif
1192 static int linenoiseEdit(struct current *current) {
1193 int history_index = 0;
1195 /* The latest history entry is always our current buffer, that
1196 * initially is just an empty string. */
1197 linenoiseHistoryAdd("");
1199 set_current(current, "");
1200 refreshLine(current->prompt, current);
1202 while(1) {
1203 int dir = -1;
1204 int c = fd_read(current);
1206 #ifndef NO_COMPLETION
1207 /* Only autocomplete when the callback is set. It returns < 0 when
1208 * there was an error reading from fd. Otherwise it will return the
1209 * character that should be handled next. */
1210 if (c == '\t' && current->pos == current->chars && completionCallback != NULL) {
1211 c = completeLine(current);
1212 /* Return on errors */
1213 if (c < 0) return current->len;
1214 /* Read next character when 0 */
1215 if (c == 0) continue;
1217 #endif
1219 process_char:
1220 if (c == -1) return current->len;
1221 #ifdef USE_TERMIOS
1222 if (c == 27) { /* escape sequence */
1223 c = check_special(current->fd);
1225 #endif
1226 switch(c) {
1227 case '\r': /* enter */
1228 history_len--;
1229 free(history[history_len]);
1230 return current->len;
1231 case ctrl('C'): /* ctrl-c */
1232 errno = EAGAIN;
1233 return -1;
1234 case 127: /* backspace */
1235 case ctrl('H'):
1236 if (remove_char(current, current->pos - 1) == 1) {
1237 refreshLine(current->prompt, current);
1239 break;
1240 case ctrl('D'): /* ctrl-d */
1241 if (current->len == 0) {
1242 /* Empty line, so EOF */
1243 history_len--;
1244 free(history[history_len]);
1245 return -1;
1247 /* Otherwise fall through to delete char to right of cursor */
1248 case SPECIAL_DELETE:
1249 if (remove_char(current, current->pos) == 1) {
1250 refreshLine(current->prompt, current);
1252 break;
1253 case SPECIAL_INSERT:
1254 /* Ignore. Expansion Hook.
1255 * Future possibility: Toggle Insert/Overwrite Modes
1257 break;
1258 case ctrl('W'): /* ctrl-w, delete word at left. save deleted chars */
1259 /* eat any spaces on the left */
1261 int pos = current->pos;
1262 while (pos > 0 && get_char(current, pos - 1) == ' ') {
1263 pos--;
1266 /* now eat any non-spaces on the left */
1267 while (pos > 0 && get_char(current, pos - 1) != ' ') {
1268 pos--;
1271 if (remove_chars(current, pos, current->pos - pos)) {
1272 refreshLine(current->prompt, current);
1275 break;
1276 case ctrl('R'): /* ctrl-r */
1278 /* Display the reverse-i-search prompt and process chars */
1279 char rbuf[50];
1280 char rprompt[80];
1281 int rchars = 0;
1282 int rlen = 0;
1283 int searchpos = history_len - 1;
1285 rbuf[0] = 0;
1286 while (1) {
1287 int n = 0;
1288 const char *p = NULL;
1289 int skipsame = 0;
1290 int searchdir = -1;
1292 snprintf(rprompt, sizeof(rprompt), "(reverse-i-search)'%s': ", rbuf);
1293 refreshLine(rprompt, current);
1294 c = fd_read(current);
1295 if (c == ctrl('H') || c == 127) {
1296 if (rchars) {
1297 int p = utf8_index(rbuf, --rchars);
1298 rbuf[p] = 0;
1299 rlen = strlen(rbuf);
1301 continue;
1303 #ifdef USE_TERMIOS
1304 if (c == 27) {
1305 c = check_special(current->fd);
1307 #endif
1308 if (c == ctrl('P') || c == SPECIAL_UP) {
1309 /* Search for the previous (earlier) match */
1310 if (searchpos > 0) {
1311 searchpos--;
1313 skipsame = 1;
1315 else if (c == ctrl('N') || c == SPECIAL_DOWN) {
1316 /* Search for the next (later) match */
1317 if (searchpos < history_len) {
1318 searchpos++;
1320 searchdir = 1;
1321 skipsame = 1;
1323 else if (c >= ' ') {
1324 if (rlen >= (int)sizeof(rbuf) + 3) {
1325 continue;
1328 n = utf8_getchars(rbuf + rlen, c);
1329 rlen += n;
1330 rchars++;
1331 rbuf[rlen] = 0;
1333 /* Adding a new char resets the search location */
1334 searchpos = history_len - 1;
1336 else {
1337 /* Exit from incremental search mode */
1338 break;
1341 /* Now search through the history for a match */
1342 for (; searchpos >= 0 && searchpos < history_len; searchpos += searchdir) {
1343 p = strstr(history[searchpos], rbuf);
1344 if (p) {
1345 /* Found a match */
1346 if (skipsame && strcmp(history[searchpos], current->buf) == 0) {
1347 /* But it is identical, so skip it */
1348 continue;
1350 /* Copy the matching line and set the cursor position */
1351 set_current(current,history[searchpos]);
1352 current->pos = utf8_strlen(history[searchpos], p - history[searchpos]);
1353 break;
1356 if (!p && n) {
1357 /* No match, so don't add it */
1358 rchars--;
1359 rlen -= n;
1360 rbuf[rlen] = 0;
1363 if (c == ctrl('G') || c == ctrl('C')) {
1364 /* ctrl-g terminates the search with no effect */
1365 set_current(current, "");
1366 c = 0;
1368 else if (c == ctrl('J')) {
1369 /* ctrl-j terminates the search leaving the buffer in place */
1370 c = 0;
1372 /* Go process the char normally */
1373 refreshLine(current->prompt, current);
1374 goto process_char;
1376 break;
1377 case ctrl('T'): /* ctrl-t */
1378 if (current->pos > 0 && current->pos <= current->chars) {
1379 /* If cursor is at end, transpose the previous two chars */
1380 int fixer = (current->pos == current->chars);
1381 c = get_char(current, current->pos - fixer);
1382 remove_char(current, current->pos - fixer);
1383 insert_char(current, current->pos - 1, c);
1384 refreshLine(current->prompt, current);
1386 break;
1387 case ctrl('V'): /* ctrl-v */
1388 if (has_room(current, 3)) {
1389 /* Insert the ^V first */
1390 if (insert_char(current, current->pos, c)) {
1391 refreshLine(current->prompt, current);
1392 /* Now wait for the next char. Can insert anything except \0 */
1393 c = fd_read(current);
1395 /* Remove the ^V first */
1396 remove_char(current, current->pos - 1);
1397 if (c != -1) {
1398 /* Insert the actual char */
1399 insert_char(current, current->pos, c);
1401 refreshLine(current->prompt, current);
1404 break;
1405 case ctrl('B'):
1406 case SPECIAL_LEFT:
1407 if (current->pos > 0) {
1408 current->pos--;
1409 refreshLine(current->prompt, current);
1411 break;
1412 case ctrl('F'):
1413 case SPECIAL_RIGHT:
1414 if (current->pos < current->chars) {
1415 current->pos++;
1416 refreshLine(current->prompt, current);
1418 break;
1419 case SPECIAL_PAGE_UP:
1420 dir = history_len - history_index - 1; /* move to start of history */
1421 goto history_navigation;
1422 case SPECIAL_PAGE_DOWN:
1423 dir = -history_index; /* move to 0 == end of history, i.e. current */
1424 goto history_navigation;
1425 case ctrl('P'):
1426 case SPECIAL_UP:
1427 dir = 1;
1428 goto history_navigation;
1429 case ctrl('N'):
1430 case SPECIAL_DOWN:
1431 history_navigation:
1432 if (history_len > 1) {
1433 /* Update the current history entry before to
1434 * overwrite it with tne next one. */
1435 free(history[history_len - 1 - history_index]);
1436 history[history_len - 1 - history_index] = strdup(current->buf);
1437 /* Show the new entry */
1438 history_index += dir;
1439 if (history_index < 0) {
1440 history_index = 0;
1441 break;
1442 } else if (history_index >= history_len) {
1443 history_index = history_len - 1;
1444 break;
1446 set_current(current, history[history_len - 1 - history_index]);
1447 refreshLine(current->prompt, current);
1449 break;
1450 case ctrl('A'): /* Ctrl+a, go to the start of the line */
1451 case SPECIAL_HOME:
1452 current->pos = 0;
1453 refreshLine(current->prompt, current);
1454 break;
1455 case ctrl('E'): /* ctrl+e, go to the end of the line */
1456 case SPECIAL_END:
1457 current->pos = current->chars;
1458 refreshLine(current->prompt, current);
1459 break;
1460 case ctrl('U'): /* Ctrl+u, delete to beginning of line, save deleted chars. */
1461 if (remove_chars(current, 0, current->pos)) {
1462 refreshLine(current->prompt, current);
1464 break;
1465 case ctrl('K'): /* Ctrl+k, delete from current to end of line, save deleted chars. */
1466 if (remove_chars(current, current->pos, current->chars - current->pos)) {
1467 refreshLine(current->prompt, current);
1469 break;
1470 case ctrl('Y'): /* Ctrl+y, insert saved chars at current position */
1471 if (current->capture && insert_chars(current, current->pos, current->capture)) {
1472 refreshLine(current->prompt, current);
1474 break;
1475 case ctrl('L'): /* Ctrl+L, clear screen */
1476 linenoiseClearScreen();
1477 /* Force recalc of window size for serial terminals */
1478 current->cols = 0;
1479 refreshLine(current->prompt, current);
1480 break;
1481 default:
1482 /* Only tab is allowed without ^V */
1483 if (c == '\t' || c >= ' ') {
1484 if (insert_char(current, current->pos, c) == 1) {
1485 refreshLine(current->prompt, current);
1488 break;
1491 return current->len;
1494 int linenoiseColumns(void)
1496 struct current current;
1497 enableRawMode (&current);
1498 getWindowSize (&current);
1499 disableRawMode (&current);
1500 return current.cols;
1503 char *linenoise(const char *prompt)
1505 int count;
1506 struct current current;
1507 char buf[LINENOISE_MAX_LINE];
1509 if (enableRawMode(&current) == -1) {
1510 printf("%s", prompt);
1511 fflush(stdout);
1512 if (fgets(buf, sizeof(buf), stdin) == NULL) {
1513 return NULL;
1515 count = strlen(buf);
1516 if (count && buf[count-1] == '\n') {
1517 count--;
1518 buf[count] = '\0';
1521 else
1523 current.buf = buf;
1524 current.bufmax = sizeof(buf);
1525 current.len = 0;
1526 current.chars = 0;
1527 current.pos = 0;
1528 current.prompt = prompt;
1529 current.capture = NULL;
1531 count = linenoiseEdit(&current);
1533 disableRawMode(&current);
1534 printf("\n");
1536 free(current.capture);
1537 if (count == -1) {
1538 return NULL;
1541 return strdup(buf);
1544 /* Using a circular buffer is smarter, but a bit more complex to handle. */
1545 int linenoiseHistoryAdd(const char *line) {
1546 char *linecopy;
1548 if (history_max_len == 0) return 0;
1549 if (history == NULL) {
1550 history = (char **)malloc(sizeof(char*)*history_max_len);
1551 if (history == NULL) return 0;
1552 memset(history,0,(sizeof(char*)*history_max_len));
1555 /* do not insert duplicate lines into history */
1556 if (history_len > 0 && strcmp(line, history[history_len - 1]) == 0) {
1557 return 0;
1560 linecopy = strdup(line);
1561 if (!linecopy) return 0;
1562 if (history_len == history_max_len) {
1563 free(history[0]);
1564 memmove(history,history+1,sizeof(char*)*(history_max_len-1));
1565 history_len--;
1567 history[history_len] = linecopy;
1568 history_len++;
1569 return 1;
1572 int linenoiseHistoryGetMaxLen(void) {
1573 return history_max_len;
1576 int linenoiseHistorySetMaxLen(int len) {
1577 char **newHistory;
1579 if (len < 1) return 0;
1580 if (history) {
1581 int tocopy = history_len;
1583 newHistory = (char **)malloc(sizeof(char*)*len);
1584 if (newHistory == NULL) return 0;
1586 /* If we can't copy everything, free the elements we'll not use. */
1587 if (len < tocopy) {
1588 int j;
1590 for (j = 0; j < tocopy-len; j++) free(history[j]);
1591 tocopy = len;
1593 memset(newHistory,0,sizeof(char*)*len);
1594 memcpy(newHistory,history+(history_len-tocopy), sizeof(char*)*tocopy);
1595 free(history);
1596 history = newHistory;
1598 history_max_len = len;
1599 if (history_len > history_max_len)
1600 history_len = history_max_len;
1601 return 1;
1604 /* Save the history in the specified file. On success 0 is returned
1605 * otherwise -1 is returned. */
1606 int linenoiseHistorySave(const char *filename) {
1607 FILE *fp = fopen(filename,"w");
1608 int j;
1610 if (fp == NULL) return -1;
1611 for (j = 0; j < history_len; j++) {
1612 const char *str = history[j];
1613 /* Need to encode backslash, nl and cr */
1614 while (*str) {
1615 if (*str == '\\') {
1616 fputs("\\\\", fp);
1618 else if (*str == '\n') {
1619 fputs("\\n", fp);
1621 else if (*str == '\r') {
1622 fputs("\\r", fp);
1624 else {
1625 fputc(*str, fp);
1627 str++;
1629 fputc('\n', fp);
1632 fclose(fp);
1633 return 0;
1636 /* Load the history from the specified file. If the file does not exist
1637 * zero is returned and no operation is performed.
1639 * If the file exists and the operation succeeded 0 is returned, otherwise
1640 * on error -1 is returned. */
1641 int linenoiseHistoryLoad(const char *filename) {
1642 FILE *fp = fopen(filename,"r");
1643 char buf[LINENOISE_MAX_LINE];
1645 if (fp == NULL) return -1;
1647 while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) {
1648 char *src, *dest;
1650 /* Decode backslash escaped values */
1651 for (src = dest = buf; *src; src++) {
1652 char ch = *src;
1654 if (ch == '\\') {
1655 src++;
1656 if (*src == 'n') {
1657 ch = '\n';
1659 else if (*src == 'r') {
1660 ch = '\r';
1661 } else {
1662 ch = *src;
1665 *dest++ = ch;
1667 /* Remove trailing newline */
1668 if (dest != buf && (dest[-1] == '\n' || dest[-1] == '\r')) {
1669 dest--;
1671 *dest = 0;
1673 linenoiseHistoryAdd(buf);
1675 fclose(fp);
1676 return 0;
1679 /* Provide access to the history buffer.
1681 * If 'len' is not NULL, the length is stored in *len.
1683 char **linenoiseHistory(int *len) {
1684 if (len) {
1685 *len = history_len;
1687 return history;