KBaba7/llama.cpp
0
1#ifndef _WIN322/*3 * You can find the latest source code at:4 *5 * http://github.com/ericcurtin/linenoise.cpp6 *7 * Does a number of crazy assumptions that happen to be true in 99.9999% of8 * the 2010 UNIX computers around.9 *10 * ------------------------------------------------------------------------11 *12 * Copyright (c) 2010-2023, Salvatore Sanfilippo <antirez at gmail dot com>13 * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>14 * Copyright (c) 2025, Eric Curtin <ericcurtin17 at gmail dot com>15 *16 * All rights reserved.17 *18 * Redistribution and use in source and binary forms, with or without19 * modification, are permitted provided that the following conditions are20 * met:21 *22 * * Redistributions of source code must retain the above copyright23 * notice, this list of conditions and the following disclaimer.24 *25 * * Redistributions in binary form must reproduce the above copyright26 * notice, this list of conditions and the following disclaimer in the27 * documentation and/or other materials provided with the distribution.28 *29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT33 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.40 *41 * ------------------------------------------------------------------------42 *43 * References:44 * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html45 * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html46 *47 * Todo list:48 * - Filter bogus Ctrl+<char> combinations.49 * - Win32 support50 *51 * Bloat:52 * - History search like Ctrl+r in readline?53 *54 * List of escape sequences used by this program, we do everything just55 * with three sequences. In order to be so cheap we may have some56 * flickering effect with some slow terminal, but the lesser sequences57 * the more compatible.58 *59 * EL (Erase Line)60 * Sequence: ESC [ n K61 * Effect: if n is 0 or missing, clear from cursor to end of line62 * Effect: if n is 1, clear from beginning of line to cursor63 * Effect: if n is 2, clear entire line64 *65 * CUF (CUrsor Forward)66 * Sequence: ESC [ n C67 * Effect: moves cursor forward n chars68 *69 * CUB (CUrsor Backward)70 * Sequence: ESC [ n D71 * Effect: moves cursor backward n chars72 *73 * The following is used to get the terminal width if getting74 * the width with the TIOCGWINSZ ioctl fails75 *76 * DSR (Device Status Report)77 * Sequence: ESC [ 6 n78 * Effect: reports the current cusor position as ESC [ n ; m R79 * where n is the row and m is the column80 *81 * When multi line mode is enabled, we also use an additional escape82 * sequence. However multi line editing is disabled by default.83 *84 * CUU (Cursor Up)85 * Sequence: ESC [ n A86 * Effect: moves cursor up of n chars.87 *88 * CUD (Cursor Down)89 * Sequence: ESC [ n B90 * Effect: moves cursor down of n chars.91 *92 * When linenoiseClearScreen() is called, two additional escape sequences93 * are used in order to clear the screen and position the cursor at home94 * position.95 *96 * CUP (Cursor position)97 * Sequence: ESC [ H98 * Effect: moves the cursor to upper left corner99 *100 * ED (Erase display)101 * Sequence: ESC [ 2 J102 * Effect: clear the whole screen103 *104 */105 106# include "linenoise.h"107 108# include <ctype.h>109# include <errno.h>110# include <stdio.h>111# include <string.h>112# include <sys/file.h>113# include <sys/ioctl.h>114# include <sys/stat.h>115# include <sys/types.h>116# include <termios.h>117# include <unistd.h>118 119# include <memory>120# include <string>121# include <vector>122 123# define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100124# define LINENOISE_MAX_LINE 4096125static std::vector<const char *> unsupported_term = { "dumb", "cons25", "emacs" };126static linenoiseCompletionCallback *completionCallback = NULL;127static linenoiseHintsCallback *hintsCallback = NULL;128static linenoiseFreeHintsCallback *freeHintsCallback = NULL;129static char *linenoiseNoTTY(void);130static void refreshLineWithCompletion(struct linenoiseState *ls, linenoiseCompletions *lc, int flags);131static void refreshLineWithFlags(struct linenoiseState *l, int flags);132 133static struct termios orig_termios; /* In order to restore at exit.*/134static int maskmode = 0; /* Show "***" instead of input. For passwords. */135static int rawmode = 0; /* For atexit() function to check if restore is needed*/136static int mlmode = 0; /* Multi line mode. Default is single line. */137static int atexit_registered = 0; /* Register atexit just 1 time. */138static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;139static int history_len = 0;140static char **history = NULL;141 142enum KEY_ACTION{143 KEY_NULL = 0, /* NULL */144 CTRL_A = 1, /* Ctrl+a */145 CTRL_B = 2, /* Ctrl-b */146 CTRL_C = 3, /* Ctrl-c */147 CTRL_D = 4, /* Ctrl-d */148 CTRL_E = 5, /* Ctrl-e */149 CTRL_F = 6, /* Ctrl-f */150 CTRL_H = 8, /* Ctrl-h */151 TAB = 9, /* Tab */152 CTRL_K = 11, /* Ctrl+k */153 CTRL_L = 12, /* Ctrl+l */154 ENTER = 13, /* Enter */155 CTRL_N = 14, /* Ctrl-n */156 CTRL_P = 16, /* Ctrl-p */157 CTRL_T = 20, /* Ctrl-t */158 CTRL_U = 21, /* Ctrl+u */159 CTRL_W = 23, /* Ctrl+w */160 ESC = 27, /* Escape */161 BACKSPACE = 127 /* Backspace */162};163 164static void linenoiseAtExit(void);165int linenoiseHistoryAdd(const char *line);166#define REFRESH_CLEAN (1<<0) // Clean the old prompt from the screen167#define REFRESH_WRITE (1<<1) // Rewrite the prompt on the screen.168#define REFRESH_ALL (REFRESH_CLEAN|REFRESH_WRITE) // Do both.169static void refreshLine(struct linenoiseState *l);170 171class File {172 public:173 FILE * file = nullptr;174 175 FILE * open(const std::string & filename, const char * mode) {176 file = fopen(filename.c_str(), mode);177 178 return file;179 }180 181 int lock() {182 if (file) {183 fd = fileno(file);184 if (flock(fd, LOCK_EX | LOCK_NB) != 0) {185 fd = -1;186 187 return 1;188 }189 }190 191 return 0;192 }193 194 ~File() {195 if (fd >= 0) {196 flock(fd, LOCK_UN);197 }198 199 if (file) {200 fclose(file);201 }202 }203 204 private:205 int fd = -1;206};207 208__attribute__((format(printf, 1, 2)))209/* Debugging function. */210#if 0211static void lndebug(const char *fmt, ...) {212 static File file;213 if (file.file == nullptr) {214 file.open("/tmp/lndebug.txt", "a");215 }216 217 if (file.file != nullptr) {218 va_list args;219 va_start(args, fmt);220 vfprintf(file.file, fmt, args);221 va_end(args);222 fflush(file.file);223 }224}225#else226static void lndebug(const char *, ...) {227}228#endif229 230/* ======================= Low level terminal handling ====================== */231 232/* Enable "mask mode". When it is enabled, instead of the input that233 * the user is typing, the terminal will just display a corresponding234 * number of asterisks, like "****". This is useful for passwords and other235 * secrets that should not be displayed. */236void linenoiseMaskModeEnable(void) {237 maskmode = 1;238}239 240/* Disable mask mode. */241void linenoiseMaskModeDisable(void) {242 maskmode = 0;243}244 245/* Set if to use or not the multi line mode. */246void linenoiseSetMultiLine(int ml) {247 mlmode = ml;248}249 250/* Return true if the terminal name is in the list of terminals we know are251 * not able to understand basic escape sequences. */252static int isUnsupportedTerm(void) {253 char *term = getenv("TERM");254 if (term == NULL) return 0;255 for (size_t j = 0; j < unsupported_term.size(); ++j) {256 if (!strcasecmp(term, unsupported_term[j])) {257 return 1;258 }259 }260 return 0;261}262 263/* Raw mode: 1960 magic shit. */264static int enableRawMode(int fd) {265 struct termios raw;266 267 if (!isatty(STDIN_FILENO)) goto fatal;268 if (!atexit_registered) {269 atexit(linenoiseAtExit);270 atexit_registered = 1;271 }272 if (tcgetattr(fd,&orig_termios) == -1) goto fatal;273 274 raw = orig_termios; /* modify the original mode */275 /* input modes: no break, no CR to NL, no parity check, no strip char,276 * no start/stop output control. */277 raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);278 /* output modes - disable post processing */279 raw.c_oflag &= ~(OPOST);280 /* control modes - set 8 bit chars */281 raw.c_cflag |= (CS8);282 /* local modes - choing off, canonical off, no extended functions,283 * no signal chars (^Z,^C) */284 raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);285 /* control chars - set return condition: min number of bytes and timer.286 * We want read to return every single byte, without timeout. */287 raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */288 289 /* put terminal in raw mode after flushing */290 if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal;291 rawmode = 1;292 return 0;293 294fatal:295 errno = ENOTTY;296 return -1;297}298 299static void disableRawMode(int fd) {300 /* Don't even check the return value as it's too late. */301 if (rawmode && tcsetattr(fd,TCSAFLUSH,&orig_termios) != -1)302 rawmode = 0;303}304 305/* Use the ESC [6n escape sequence to query the horizontal cursor position306 * and return it. On error -1 is returned, on success the position of the307 * cursor. */308static int getCursorPosition(int ifd, int ofd) {309 char buf[32];310 int cols, rows;311 unsigned int i = 0;312 313 /* Report cursor location */314 if (write(ofd, "\x1b[6n", 4) != 4) return -1;315 316 /* Read the response: ESC [ rows ; cols R */317 while (i < sizeof(buf)-1) {318 if (read(ifd,buf+i,1) != 1) break;319 if (buf[i] == 'R') break;320 i++;321 }322 buf[i] = '\0';323 324 /* Parse it. */325 if (buf[0] != ESC || buf[1] != '[') return -1;326 if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1;327 return cols;328}329 330/* Try to get the number of columns in the current terminal, or assume 80331 * if it fails. */332static int getColumns(int ifd, int ofd) {333 struct winsize ws;334 335 if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {336 /* ioctl() failed. Try to query the terminal itself. */337 int start, cols;338 339 /* Get the initial position so we can restore it later. */340 start = getCursorPosition(ifd,ofd);341 if (start == -1) goto failed;342 343 /* Go to right margin and get position. */344 if (write(ofd,"\x1b[999C",6) != 6) goto failed;345 cols = getCursorPosition(ifd,ofd);346 if (cols == -1) goto failed;347 348 /* Restore position. */349 if (cols > start) {350 char seq[32];351 snprintf(seq,32,"\x1b[%dD",cols-start);352 if (write(ofd,seq,strlen(seq)) == -1) {353 /* Can't recover... */354 }355 }356 return cols;357 } else {358 return ws.ws_col;359 }360 361failed:362 return 80;363}364 365/* Clear the screen. Used to handle ctrl+l */366void linenoiseClearScreen(void) {367 if (write(STDOUT_FILENO,"\x1b[H\x1b[2J",7) <= 0) {368 /* nothing to do, just to avoid warning. */369 }370}371 372/* Beep, used for completion when there is nothing to complete or when all373 * the choices were already shown. */374static void linenoiseBeep(void) {375 fprintf(stderr, "\x7");376 fflush(stderr);377}378 379/* Called by completeLine() and linenoiseShow() to render the current380 * edited line with the proposed completion. If the current completion table381 * is already available, it is passed as second argument, otherwise the382 * function will use the callback to obtain it.383 *384 * Flags are the same as refreshLine*(), that is REFRESH_* macros. */385static void refreshLineWithCompletion(struct linenoiseState *ls, linenoiseCompletions *lc, int flags) {386 /* Obtain the table of completions if the caller didn't provide one. */387 linenoiseCompletions ctable;388 if (lc == NULL) {389 completionCallback(ls->buf, &ctable);390 lc = &ctable;391 }392 393 /* Show the edited line with completion if possible, or just refresh. */394 if (ls->completion_idx < lc->len) {395 struct linenoiseState saved = *ls;396 ls->len = ls->pos = strlen(lc->cvec[ls->completion_idx]);397 ls->buf = lc->cvec[ls->completion_idx];398 refreshLineWithFlags(ls, flags);399 ls->len = saved.len;400 ls->pos = saved.pos;401 ls->buf = saved.buf;402 } else {403 refreshLineWithFlags(ls, flags);404 }405 406 if (lc == &ctable) {407 ctable.to_free = false;408 }409}410 411/* This is an helper function for linenoiseEdit*() and is called when the412 * user types the <tab> key in order to complete the string currently in the413 * input.414 *415 * The state of the editing is encapsulated into the pointed linenoiseState416 * structure as described in the structure definition.417 *418 * If the function returns non-zero, the caller should handle the419 * returned value as a byte read from the standard input, and process420 * it as usually: this basically means that the function may return a byte421 * read from the termianl but not processed. Otherwise, if zero is returned,422 * the input was consumed by the completeLine() function to navigate the423 * possible completions, and the caller should read for the next characters424 * from stdin. */425static int completeLine(struct linenoiseState *ls, int keypressed) {426 linenoiseCompletions lc;427 int nwritten;428 char c = keypressed;429 430 completionCallback(ls->buf, &lc);431 if (lc.len == 0) {432 linenoiseBeep();433 ls->in_completion = 0;434 } else {435 switch(c) {436 case 9: /* tab */437 if (ls->in_completion == 0) {438 ls->in_completion = 1;439 ls->completion_idx = 0;440 } else {441 ls->completion_idx = (ls->completion_idx + 1) % (lc.len + 1);442 if (ls->completion_idx == lc.len) linenoiseBeep();443 }444 c = 0;445 break;446 case 27: /* escape */447 /* Re-show original buffer */448 if (ls->completion_idx < lc.len) refreshLine(ls);449 ls->in_completion = 0;450 c = 0;451 break;452 default:453 /* Update buffer and return */454 if (ls->completion_idx < lc.len) {455 nwritten = snprintf(ls->buf, ls->buflen, "%s", lc.cvec[ls->completion_idx]);456 ls->len = ls->pos = nwritten;457 }458 ls->in_completion = 0;459 break;460 }461 462 /* Show completion or original buffer */463 if (ls->in_completion && ls->completion_idx < lc.len) {464 refreshLineWithCompletion(ls, &lc, REFRESH_ALL);465 } else {466 refreshLine(ls);467 }468 }469 470 return c; /* Return last read character */471}472 473/* Register a callback function to be called for tab-completion. */474void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {475 completionCallback = fn;476}477 478/* Register a hits function to be called to show hits to the user at the479 * right of the prompt. */480void linenoiseSetHintsCallback(linenoiseHintsCallback *fn) {481 hintsCallback = fn;482}483 484/* Register a function to free the hints returned by the hints callback485 * registered with linenoiseSetHintsCallback(). */486void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn) {487 freeHintsCallback = fn;488}489 490/* This function is used by the callback function registered by the user491 * in order to add completion options given the input string when the492 * user typed <tab>. See the example.c source code for a very easy to493 * understand example. */494void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {495 const size_t len = strlen(str);496 auto copy = std::make_unique<char[]>(len + 1);497 if (!copy) {498 return;499 }500 501 memcpy(copy.get(), str, len + 1);502 char ** cvec = static_cast<char **>(std::realloc(lc->cvec, sizeof(char *) * (lc->len + 1)));503 if (cvec == nullptr) {504 return;505 }506 507 lc->cvec = cvec;508 lc->cvec[lc->len++] = copy.release();509}510 511/* Helper of refreshSingleLine() and refreshMultiLine() to show hints512 * to the right of the prompt. */513static void refreshShowHints(std::string & ab, struct linenoiseState * l, int plen) {514 char seq[64];515 if (hintsCallback && plen+l->len < l->cols) {516 int color = -1, bold = 0;517 const char *hint = hintsCallback(l->buf,&color,&bold);518 if (hint) {519 int hintlen = strlen(hint);520 int hintmaxlen = l->cols-(plen+l->len);521 if (hintlen > hintmaxlen) hintlen = hintmaxlen;522 if (bold == 1 && color == -1) color = 37;523 if (color != -1 || bold != 0)524 snprintf(seq,64,"\033[%d;%d;49m",bold,color);525 else526 seq[0] = '\0';527 ab.append(seq);528 ab.append(hint, hintlen);529 if (color != -1 || bold != 0)530 ab.append("\033[0m");531 532 /* Call the function to free the hint returned. */533 if (freeHintsCallback) freeHintsCallback(hint);534 }535 }536}537 538/* Single line low level line refresh.539 *540 * Rewrite the currently edited line accordingly to the buffer content,541 * cursor position, and number of columns of the terminal.542 *543 * Flags is REFRESH_* macros. The function can just remove the old544 * prompt, just write it, or both. */545static void refreshSingleLine(struct linenoiseState *l, int flags) {546 char seq[64];547 size_t plen = strlen(l->prompt);548 int fd = l->ofd;549 char *buf = l->buf;550 size_t len = l->len;551 size_t pos = l->pos;552 std::string ab;553 while((plen+pos) >= l->cols) {554 buf++;555 len--;556 pos--;557 }558 while (plen+len > l->cols) {559 len--;560 }561 562 /* Cursor to left edge */563 snprintf(seq,sizeof(seq),"\r");564 ab.append(seq);565 566 if (flags & REFRESH_WRITE) {567 /* Write the prompt and the current buffer content */568 ab.append(l->prompt);569 if (maskmode == 1) {570 while (len--) {571 ab.append("*");572 }573 } else {574 ab.append(buf, len);575 }576 /* Show hits if any. */577 refreshShowHints(ab, l, plen);578 }579 580 /* Erase to right */581 snprintf(seq,sizeof(seq),"\x1b[0K");582 ab.append(seq);583 if (flags & REFRESH_WRITE) {584 /* Move cursor to original position. */585 snprintf(seq,sizeof(seq),"\r\x1b[%dC", (int)(pos+plen));586 ab.append(seq);587 }588 589 (void) !write(fd, ab.c_str(), ab.size()); /* Can't recover from write error. */590}591 592/* Multi line low level line refresh.593 *594 * Rewrite the currently edited line accordingly to the buffer content,595 * cursor position, and number of columns of the terminal.596 *597 * Flags is REFRESH_* macros. The function can just remove the old598 * prompt, just write it, or both. */599static void refreshMultiLine(struct linenoiseState *l, int flags) {600 char seq[64];601 int plen = strlen(l->prompt);602 int rows = (plen+l->len+l->cols-1)/l->cols; /* rows used by current buf. */603 int rpos = (plen+l->oldpos+l->cols)/l->cols; /* cursor relative row. */604 int rpos2; /* rpos after refresh. */605 int col; /* colum position, zero-based. */606 int old_rows = l->oldrows;607 int fd = l->ofd, j;608 std::string ab;609 l->oldrows = rows;610 611 /* First step: clear all the lines used before. To do so start by612 * going to the last row. */613 if (flags & REFRESH_CLEAN) {614 if (old_rows-rpos > 0) {615 lndebug("go down %d", old_rows-rpos);616 snprintf(seq,64,"\x1b[%dB", old_rows-rpos);617 ab.append(seq);618 }619 620 /* Now for every row clear it, go up. */621 for (j = 0; j < old_rows-1; j++) {622 lndebug("clear+up");623 snprintf(seq,64,"\r\x1b[0K\x1b[1A");624 ab.append(seq);625 }626 }627 628 if (flags & REFRESH_ALL) {629 /* Clean the top line. */630 lndebug("clear");631 snprintf(seq,64,"\r\x1b[0K");632 ab.append(seq);633 }634 635 if (flags & REFRESH_WRITE) {636 /* Write the prompt and the current buffer content */637 ab.append(l->prompt);638 if (maskmode == 1) {639 for (unsigned int i = 0; i < l->len; ++i) {640 ab.append("*");641 }642 } else {643 ab.append(l->buf, l->len);644 }645 646 /* Show hits if any. */647 refreshShowHints(ab, l, plen);648 649 /* If we are at the very end of the screen with our prompt, we need to650 * emit a newline and move the prompt to the first column. */651 if (l->pos &&652 l->pos == l->len &&653 (l->pos+plen) % l->cols == 0)654 {655 lndebug("<newline>");656 ab.append("\n");657 snprintf(seq,64,"\r");658 ab.append(seq);659 rows++;660 if (rows > (int)l->oldrows) l->oldrows = rows;661 }662 663 /* Move cursor to right position. */664 rpos2 = (plen+l->pos+l->cols)/l->cols; /* Current cursor relative row */665 lndebug("rpos2 %d", rpos2);666 667 /* Go up till we reach the expected positon. */668 if (rows-rpos2 > 0) {669 lndebug("go-up %d", rows-rpos2);670 snprintf(seq,64,"\x1b[%dA", rows-rpos2);671 ab.append(seq);672 }673 674 /* Set column. */675 col = (plen+(int)l->pos) % (int)l->cols;676 lndebug("set col %d", 1+col);677 if (col)678 snprintf(seq,64,"\r\x1b[%dC", col);679 else680 snprintf(seq,64,"\r");681 ab.append(seq);682 }683 684 lndebug("\n");685 l->oldpos = l->pos;686 (void) !write(fd, ab.c_str(), ab.size()); /* Can't recover from write error. */687}688 689/* Calls the two low level functions refreshSingleLine() or690 * refreshMultiLine() according to the selected mode. */691static void refreshLineWithFlags(struct linenoiseState *l, int flags) {692 if (mlmode)693 refreshMultiLine(l,flags);694 else695 refreshSingleLine(l,flags);696}697 698/* Utility function to avoid specifying REFRESH_ALL all the times. */699static void refreshLine(struct linenoiseState *l) {700 refreshLineWithFlags(l,REFRESH_ALL);701}702 703/* Hide the current line, when using the multiplexing API. */704void linenoiseHide(struct linenoiseState *l) {705 if (mlmode)706 refreshMultiLine(l,REFRESH_CLEAN);707 else708 refreshSingleLine(l,REFRESH_CLEAN);709}710 711/* Show the current line, when using the multiplexing API. */712void linenoiseShow(struct linenoiseState *l) {713 if (l->in_completion) {714 refreshLineWithCompletion(l,NULL,REFRESH_WRITE);715 } else {716 refreshLineWithFlags(l,REFRESH_WRITE);717 }718}719 720/* Insert the character 'c' at cursor current position.721 *722 * On error writing to the terminal -1 is returned, otherwise 0. */723static int linenoiseEditInsert(struct linenoiseState * l, char c) {724 if (l->len < l->buflen) {725 if (l->len == l->pos) {726 l->buf[l->pos] = c;727 l->pos++;728 l->len++;729 l->buf[l->len] = '\0';730 if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) {731 /* Avoid a full update of the line in the732 * trivial case. */733 char d = (maskmode==1) ? '*' : c;734 if (write(l->ofd,&d,1) == -1) return -1;735 } else {736 refreshLine(l);737 }738 } else {739 memmove(l->buf+l->pos+1,l->buf+l->pos,l->len-l->pos);740 l->buf[l->pos] = c;741 l->len++;742 l->pos++;743 l->buf[l->len] = '\0';744 refreshLine(l);745 }746 }747 return 0;748}749 750/* Move cursor on the left. */751static void linenoiseEditMoveLeft(struct linenoiseState * l) {752 if (l->pos > 0) {753 l->pos--;754 refreshLine(l);755 }756}757 758/* Move cursor on the right. */759static void linenoiseEditMoveRight(struct linenoiseState * l) {760 if (l->pos != l->len) {761 l->pos++;762 refreshLine(l);763 }764}765 766/* Move cursor to the start of the line. */767static void linenoiseEditMoveHome(struct linenoiseState * l) {768 if (l->pos != 0) {769 l->pos = 0;770 refreshLine(l);771 }772}773 774/* Move cursor to the end of the line. */775static void linenoiseEditMoveEnd(struct linenoiseState * l) {776 if (l->pos != l->len) {777 l->pos = l->len;778 refreshLine(l);779 }780}781 782/* Substitute the currently edited line with the next or previous history783 * entry as specified by 'dir'. */784#define LINENOISE_HISTORY_NEXT 0785#define LINENOISE_HISTORY_PREV 1786 787static void linenoiseEditHistoryNext(struct linenoiseState * l, int dir) {788 if (history_len > 1) {789 /* Update the current history entry before to790 * overwrite it with the next one. */791 free(history[history_len - 1 - l->history_index]);792 history[history_len - 1 - l->history_index] = strdup(l->buf);793 /* Show the new entry */794 l->history_index += (dir == LINENOISE_HISTORY_PREV) ? 1 : -1;795 if (l->history_index < 0) {796 l->history_index = 0;797 return;798 } else if (l->history_index >= history_len) {799 l->history_index = history_len-1;800 return;801 }802 strncpy(l->buf,history[history_len - 1 - l->history_index],l->buflen);803 l->buf[l->buflen-1] = '\0';804 l->len = l->pos = strlen(l->buf);805 refreshLine(l);806 }807}808 809/* Delete the character at the right of the cursor without altering the cursor810 * position. Basically this is what happens with the "Delete" keyboard key. */811static void linenoiseEditDelete(struct linenoiseState * l) {812 if (l->len > 0 && l->pos < l->len) {813 memmove(l->buf+l->pos,l->buf+l->pos+1,l->len-l->pos-1);814 l->len--;815 l->buf[l->len] = '\0';816 refreshLine(l);817 }818}819 820/* Backspace implementation. */821static void linenoiseEditBackspace(struct linenoiseState * l) {822 if (l->pos > 0 && l->len > 0) {823 memmove(l->buf+l->pos-1,l->buf+l->pos,l->len-l->pos);824 l->pos--;825 l->len--;826 l->buf[l->len] = '\0';827 refreshLine(l);828 }829}830 831/* Delete the previosu word, maintaining the cursor at the start of the832 * current word. */833static void linenoiseEditDeletePrevWord(struct linenoiseState * l) {834 size_t old_pos = l->pos;835 size_t diff;836 837 while (l->pos > 0 && l->buf[l->pos-1] == ' ')838 l->pos--;839 while (l->pos > 0 && l->buf[l->pos-1] != ' ')840 l->pos--;841 diff = old_pos - l->pos;842 memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1);843 l->len -= diff;844 refreshLine(l);845}846 847/* This function is part of the multiplexed API of Linenoise, that is used848 * in order to implement the blocking variant of the API but can also be849 * called by the user directly in an event driven program. It will:850 *851 * 1. Initialize the linenoise state passed by the user.852 * 2. Put the terminal in RAW mode.853 * 3. Show the prompt.854 * 4. Return control to the user, that will have to call linenoiseEditFeed()855 * each time there is some data arriving in the standard input.856 *857 * The user can also call linenoiseEditHide() and linenoiseEditShow() if it858 * is required to show some input arriving asyncronously, without mixing859 * it with the currently edited line.860 *861 * When linenoiseEditFeed() returns non-NULL, the user finished with the862 * line editing session (pressed enter CTRL-D/C): in this case the caller863 * needs to call linenoiseEditStop() to put back the terminal in normal864 * mode. This will not destroy the buffer, as long as the linenoiseState865 * is still valid in the context of the caller.866 *867 * The function returns 0 on success, or -1 if writing to standard output868 * fails. If stdin_fd or stdout_fd are set to -1, the default is to use869 * STDIN_FILENO and STDOUT_FILENO.870 */871int linenoiseEditStart(struct linenoiseState *l, int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt) {872 /* Populate the linenoise state that we pass to functions implementing873 * specific editing functionalities. */874 l->in_completion = 0;875 l->ifd = stdin_fd != -1 ? stdin_fd : STDIN_FILENO;876 l->ofd = stdout_fd != -1 ? stdout_fd : STDOUT_FILENO;877 l->buf = buf;878 l->buflen = buflen;879 l->prompt = prompt;880 l->plen = strlen(prompt);881 l->oldpos = l->pos = 0;882 l->len = 0;883 884 /* Enter raw mode. */885 if (enableRawMode(l->ifd) == -1) return -1;886 887 l->cols = getColumns(stdin_fd, stdout_fd);888 l->oldrows = 0;889 l->history_index = 0;890 891 /* Buffer starts empty. */892 l->buf[0] = '\0';893 l->buflen--; /* Make sure there is always space for the nulterm */894 895 /* If stdin is not a tty, stop here with the initialization. We896 * will actually just read a line from standard input in blocking897 * mode later, in linenoiseEditFeed(). */898 if (!isatty(l->ifd)) return 0;899 900 /* The latest history entry is always our current buffer, that901 * initially is just an empty string. */902 linenoiseHistoryAdd("");903 904 if (write(l->ofd,prompt,l->plen) == -1) return -1;905 return 0;906}907 908const char* linenoiseEditMore = "If you see this, you are misusing the API: when linenoiseEditFeed() is called, if it returns linenoiseEditMore the user is yet editing the line. See the README file for more information.";909 910/* This function is part of the multiplexed API of linenoise, see the top911 * comment on linenoiseEditStart() for more information. Call this function912 * each time there is some data to read from the standard input file913 * descriptor. In the case of blocking operations, this function can just be914 * called in a loop, and block.915 *916 * The function returns linenoiseEditMore to signal that line editing is still917 * in progress, that is, the user didn't yet pressed enter / CTRL-D. Otherwise918 * the function returns the pointer to the heap-allocated buffer with the919 * edited line, that the user should free with linenoiseFree().920 *921 * On special conditions, NULL is returned and errno is populated:922 *923 * EAGAIN if the user pressed Ctrl-C924 * ENOENT if the user pressed Ctrl-D925 *926 * Some other errno: I/O error.927 */928const char *linenoiseEditFeed(struct linenoiseState *l) {929 /* Not a TTY, pass control to line reading without character930 * count limits. */931 if (!isatty(l->ifd)) return linenoiseNoTTY();932 933 char c;934 int nread;935 char seq[3];936 937 nread = read(l->ifd,&c,1);938 if (nread <= 0) return NULL;939 940 /* Only autocomplete when the callback is set. It returns < 0 when941 * there was an error reading from fd. Otherwise it will return the942 * character that should be handled next. */943 if ((l->in_completion || c == 9) && completionCallback != NULL) {944 c = completeLine(l,c);945 /* Read next character when 0 */946 if (c == 0) return linenoiseEditMore;947 }948 949 switch(c) {950 case ENTER: /* enter */951 history_len--;952 free(history[history_len]);953 if (mlmode) linenoiseEditMoveEnd(l);954 if (hintsCallback) {955 /* Force a refresh without hints to leave the previous956 * line as the user typed it after a newline. */957 linenoiseHintsCallback *hc = hintsCallback;958 hintsCallback = NULL;959 refreshLine(l);960 hintsCallback = hc;961 }962 return strdup(l->buf);963 case CTRL_C: /* ctrl-c */964 errno = EAGAIN;965 return NULL;966 case BACKSPACE: /* backspace */967 case 8: /* ctrl-h */968 linenoiseEditBackspace(l);969 break;970 case CTRL_D: /* ctrl-d, remove char at right of cursor, or if the971 line is empty, act as end-of-file. */972 if (l->len > 0) {973 linenoiseEditDelete(l);974 } else {975 history_len--;976 free(history[history_len]);977 errno = ENOENT;978 return NULL;979 }980 break;981 case CTRL_T: /* ctrl-t, swaps current character with previous. */982 if (l->pos > 0 && l->pos < l->len) {983 int aux = l->buf[l->pos-1];984 l->buf[l->pos-1] = l->buf[l->pos];985 l->buf[l->pos] = aux;986 if (l->pos != l->len-1) l->pos++;987 refreshLine(l);988 }989 break;990 case CTRL_B: /* ctrl-b */991 linenoiseEditMoveLeft(l);992 break;993 case CTRL_F: /* ctrl-f */994 linenoiseEditMoveRight(l);995 break;996 case CTRL_P: /* ctrl-p */997 linenoiseEditHistoryNext(l, LINENOISE_HISTORY_PREV);998 break;999 case CTRL_N: /* ctrl-n */1000 linenoiseEditHistoryNext(l, LINENOISE_HISTORY_NEXT);1001 break;1002 case ESC: /* escape sequence */1003 /* Read the next two bytes representing the escape sequence.1004 * Use two calls to handle slow terminals returning the two1005 * chars at different times. */1006 if (read(l->ifd,seq,1) == -1) break;1007 if (read(l->ifd,seq+1,1) == -1) break;1008 1009 /* ESC [ sequences. */1010 if (seq[0] == '[') {1011 if (seq[1] >= '0' && seq[1] <= '9') {1012 /* Extended escape, read additional byte. */1013 if (read(l->ifd,seq+2,1) == -1) break;1014 if (seq[2] == '~') {1015 switch(seq[1]) {1016 case '3': /* Delete key. */1017 linenoiseEditDelete(l);1018 break;1019 }1020 }1021 } else {1022 switch(seq[1]) {1023 case 'A': /* Up */1024 linenoiseEditHistoryNext(l, LINENOISE_HISTORY_PREV);1025 break;1026 case 'B': /* Down */1027 linenoiseEditHistoryNext(l, LINENOISE_HISTORY_NEXT);1028 break;1029 case 'C': /* Right */1030 linenoiseEditMoveRight(l);1031 break;1032 case 'D': /* Left */1033 linenoiseEditMoveLeft(l);1034 break;1035 case 'H': /* Home */1036 linenoiseEditMoveHome(l);1037 break;1038 case 'F': /* End*/1039 linenoiseEditMoveEnd(l);1040 break;1041 }1042 }1043 }1044 1045 /* ESC O sequences. */1046 else if (seq[0] == 'O') {1047 switch(seq[1]) {1048 case 'H': /* Home */1049 linenoiseEditMoveHome(l);1050 break;1051 case 'F': /* End*/1052 linenoiseEditMoveEnd(l);1053 break;1054 }1055 }1056 break;1057 default:1058 if (linenoiseEditInsert(l,c)) return NULL;1059 break;1060 case CTRL_U: /* Ctrl+u, delete the whole line. */1061 l->buf[0] = '\0';1062 l->pos = l->len = 0;1063 refreshLine(l);1064 break;1065 case CTRL_K: /* Ctrl+k, delete from current to end of line. */1066 l->buf[l->pos] = '\0';1067 l->len = l->pos;1068 refreshLine(l);1069 break;1070 case CTRL_A: /* Ctrl+a, go to the start of the line */1071 linenoiseEditMoveHome(l);1072 break;1073 case CTRL_E: /* ctrl+e, go to the end of the line */1074 linenoiseEditMoveEnd(l);1075 break;1076 case CTRL_L: /* ctrl+l, clear screen */1077 linenoiseClearScreen();1078 refreshLine(l);1079 break;1080 case CTRL_W: /* ctrl+w, delete previous word */1081 linenoiseEditDeletePrevWord(l);1082 break;1083 }1084 return linenoiseEditMore;1085}1086 1087/* This is part of the multiplexed linenoise API. See linenoiseEditStart()1088 * for more information. This function is called when linenoiseEditFeed()1089 * returns something different than NULL. At this point the user input1090 * is in the buffer, and we can restore the terminal in normal mode. */1091void linenoiseEditStop(struct linenoiseState *l) {1092 if (!isatty(l->ifd)) return;1093 disableRawMode(l->ifd);1094 printf("\n");1095}1096 1097/* This just implements a blocking loop for the multiplexed API.1098 * In many applications that are not event-drivern, we can just call1099 * the blocking linenoise API, wait for the user to complete the editing1100 * and return the buffer. */1101static const char *linenoiseBlockingEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt)1102{1103 struct linenoiseState l;1104 1105 /* Editing without a buffer is invalid. */1106 if (buflen == 0) {1107 errno = EINVAL;1108 return NULL;1109 }1110 1111 linenoiseEditStart(&l,stdin_fd,stdout_fd,buf,buflen,prompt);1112 const char *res;1113 while((res = linenoiseEditFeed(&l)) == linenoiseEditMore);1114 linenoiseEditStop(&l);1115 return res;1116}1117 1118/* This special mode is used by linenoise in order to print scan codes1119 * on screen for debugging / development purposes. It is implemented1120 * by the linenoise_example program using the --keycodes option. */1121void linenoisePrintKeyCodes(void) {1122 char quit[4];1123 1124 printf("Linenoise key codes debugging mode.\n"1125 "Press keys to see scan codes. Type 'quit' at any time to exit.\n");1126 if (enableRawMode(STDIN_FILENO) == -1) return;1127 memset(quit,' ',4);1128 while(1) {1129 char c;1130 int nread;1131 1132 nread = read(STDIN_FILENO,&c,1);1133 if (nread <= 0) continue;1134 memmove(quit,quit+1,sizeof(quit)-1); /* shift string to left. */1135 quit[sizeof(quit)-1] = c; /* Insert current char on the right. */1136 if (memcmp(quit,"quit",sizeof(quit)) == 0) break;1137 1138 printf("'%c' %02x (%d) (type quit to exit)\n",1139 isprint(c) ? c : '?', (int)c, (int)c);1140 printf("\r"); /* Go left edge manually, we are in raw mode. */1141 fflush(stdout);1142 }1143 disableRawMode(STDIN_FILENO);1144}1145 1146/* This function is called when linenoise() is called with the standard1147 * input file descriptor not attached to a TTY. So for example when the1148 * program using linenoise is called in pipe or with a file redirected1149 * to its standard input. In this case, we want to be able to return the1150 * line regardless of its length (by default we are limited to 4k). */1151static char *linenoiseNoTTY(void) {1152 char *line = NULL;1153 size_t len = 0, maxlen = 0;1154 1155 while(1) {1156 if (len == maxlen) {1157 if (maxlen == 0) maxlen = 16;1158 maxlen *= 2;1159 char *oldval = line;1160 line = (char*) realloc(line,maxlen);1161 if (line == NULL) {1162 if (oldval) free(oldval);1163 return NULL;1164 }1165 }1166 int c = fgetc(stdin);1167 if (c == EOF || c == '\n') {1168 if (c == EOF && len == 0) {1169 free(line);1170 return NULL;1171 } else {1172 line[len] = '\0';1173 return line;1174 }1175 } else {1176 line[len] = c;1177 len++;1178 }1179 }1180}1181 1182/* The high level function that is the main API of the linenoise library.1183 * This function checks if the terminal has basic capabilities, just checking1184 * for a blacklist of stupid terminals, and later either calls the line1185 * editing function or uses dummy fgets() so that you will be able to type1186 * something even in the most desperate of the conditions. */1187const char *linenoise(const char *prompt) {1188 char buf[LINENOISE_MAX_LINE];1189 1190 if (!isatty(STDIN_FILENO)) {1191 /* Not a tty: read from file / pipe. In this mode we don't want any1192 * limit to the line size, so we call a function to handle that. */1193 return linenoiseNoTTY();1194 } else if (isUnsupportedTerm()) {1195 size_t len;1196 1197 printf("%s",prompt);1198 fflush(stdout);1199 if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL;1200 len = strlen(buf);