Team Ai
Apppublic

KBaba7/llama.cpp

sourceHugging Faceapache-2.0updated 2y agoView on Hugging Face
0likes
linenoise.cpp1351 linesDownload Raw Back to linenoise.cpp
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);

Showing the first 1,200 of 1351 lines. Download the file for the rest.