Jim Tcl
Check-in [4f1592c24e]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:linenoise: Update to support multiline mode.

Updated to: https://github.com/msteveb/linenoise/commit/ad5172e99520e2fe2a35b4bbd7fbc74d9df36df1

Now supports multiline mode (by setting $history::multiline to 1) Improved windows support

Signed-off-by: Steve Bennett <steveb@workware.net.au>

Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 4f1592c24edf9b1ca46af19917a1ea8bb5bc8577
User & Date: steveb@workware.net.au 2018-03-25 00:47:53
Context
2018-06-03
06:18
jim.c: Jim_Length/Jim_String internal checks

Perform the same internal checks as Jim_GetString() when the string rep needs to be generated by calling Jim_GetString()

Reported-by: Stuart Cassoff <stwo@bell.net> Signed-off-by: Steve Bennett <steveb@workware.net.au> check-in: 876c29d3a8 user: steveb@workware.net.au tags: trunk

2018-03-25
00:47
linenoise: Update to support multiline mode.

Updated to: https://github.com/msteveb/linenoise/commit/ad5172e99520e2fe2a35b4bbd7fbc74d9df36df1

Now supports multiline mode (by setting $history::multiline to 1) Improved windows support

Signed-off-by: Steve Bennett <steveb@workware.net.au> check-in: 4f1592c24e user: steveb@workware.net.au tags: trunk

2018-01-18
01:01
expr: prevent stack overflow

Limit the depth of the expressions to a reasonable level to prevent stack overflow

Signed-off-by: Steve Bennett <steveb@workware.net.au> check-in: b878884ca8 user: steveb@workware.net.au tags: trunk

Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to jim-interactive.c.

    25     25    * Returns an allocated line, or NULL if EOF.
    26     26    */
    27     27   char *Jim_HistoryGetline(Jim_Interp *interp, const char *prompt)
    28     28   {
    29     29   #ifdef USE_LINENOISE
    30     30       struct JimCompletionInfo *compinfo = Jim_GetAssocData(interp, completion_callback_assoc_key);
    31     31       char *result;
           32  +    Jim_Obj *objPtr;
           33  +    long mlmode = 0;
    32     34       /* Set any completion callback just during the call to linenoise()
    33     35        * to allow for per-interp settings
    34     36        */
    35     37       if (compinfo) {
    36     38           linenoiseSetCompletionCallback(JimCompletionCallback, compinfo);
    37     39       }
           40  +    objPtr = Jim_GetVariableStr(interp, "history::multiline", JIM_NONE);
           41  +    if (objPtr && Jim_GetLong(interp, objPtr, &mlmode) == JIM_NONE) {
           42  +        linenoiseSetMultiLine(mlmode);
           43  +    }
           44  +
    38     45       result = linenoise(prompt);
    39     46       /* unset the callback */
    40     47       linenoiseSetCompletionCallback(NULL, NULL);
    41     48       return result;
    42     49   #else
    43     50       int len;
    44     51       char *line = malloc(MAX_LINE_LEN);

Changes to jim_tcl.txt.

    62     62   6. Add scriptable autocompletion support with `history completion`
    63     63   7. Add support for `tree delete`
    64     64   8. Add support for `defer` and '$jim::defer'
    65     65   9. Renamed `os.wait` to `wait`, now more Tcl-compatible and compatible with `exec ... &`
    66     66   10. `pipe` is now a synonym for `socket pipe`
    67     67   11. Closing a pipe open with `open |...` now returns Tcl-like status
    68     68   12. It is now possible to used `exec` redirection with a pipe opened with `open |...`
           69  +13. Interactive line editing now supports multiline mode if $::history::multiline is set
    69     70   
    70     71   Changes between 0.76 and 0.77
    71     72   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    72     73   1. Add support for `aio sync`
    73     74   2. Add SSL and TLS support in aio
    74     75   3. Added `zlib`
    75     76   4. Added support for boolean constants in `expr`
................................................................................
  5207   5208   The following variables have special meaning to Jim Tcl:
  5208   5209   
  5209   5210   +*jim::defer*+::
  5210   5211       If this variable is set, it is considered to be a list of scripts to evaluate
  5211   5212   	when the current proc exits (local variables), or the interpreter exits (global variable).
  5212   5213   	See `defer`.
  5213   5214   
         5215  ++*history::multiline*+::
         5216  +    If this variable is set to "1", interactive line editing operates in multiline mode.
         5217  +	That is, long lines will wrap across multiple lines rather than scrolling within a
         5218  +	single line.
  5214   5219   
  5215   5220   CHANGES IN PREVIOUS RELEASES
  5216   5221   ----------------------------
  5217   5222   
  5218   5223   === In v0.70 ===
  5219   5224   
  5220   5225   1. +platform_tcl()+ settings are now automatically determined

Added linenoise-win32.c.

            1  +
            2  +/* this code is not standalone
            3  + * it is included into linenoise.c
            4  + * for windows.
            5  + * It is deliberately kept separate so that
            6  + * applications that have no need for windows
            7  + * support can omit this
            8  + */
            9  +static DWORD orig_consolemode = 0;
           10  +
           11  +static int flushOutput(struct current *current);
           12  +static void outputNewline(struct current *current);
           13  +
           14  +static void refreshStart(struct current *current)
           15  +{
           16  +}
           17  +
           18  +static void refreshEnd(struct current *current)
           19  +{
           20  +}
           21  +
           22  +static void refreshStartChars(struct current *current)
           23  +{
           24  +    assert(current->output == NULL);
           25  +    /* We accumulate all output here */
           26  +    current->output = sb_alloc();
           27  +#ifdef USE_UTF8
           28  +    current->ubuflen = 0;
           29  +#endif
           30  +}
           31  +
           32  +static void refreshNewline(struct current *current)
           33  +{
           34  +    DRL("<nl>");
           35  +    outputNewline(current);
           36  +}
           37  +
           38  +static void refreshEndChars(struct current *current)
           39  +{
           40  +    assert(current->output);
           41  +    flushOutput(current);
           42  +    sb_free(current->output);
           43  +    current->output = NULL;
           44  +}
           45  +
           46  +static int enableRawMode(struct current *current) {
           47  +    DWORD n;
           48  +    INPUT_RECORD irec;
           49  +
           50  +    current->outh = GetStdHandle(STD_OUTPUT_HANDLE);
           51  +    current->inh = GetStdHandle(STD_INPUT_HANDLE);
           52  +
           53  +    if (!PeekConsoleInput(current->inh, &irec, 1, &n)) {
           54  +        return -1;
           55  +    }
           56  +    if (getWindowSize(current) != 0) {
           57  +        return -1;
           58  +    }
           59  +    if (GetConsoleMode(current->inh, &orig_consolemode)) {
           60  +        SetConsoleMode(current->inh, ENABLE_PROCESSED_INPUT);
           61  +    }
           62  +#ifdef USE_UTF8
           63  +    /* XXX is this the right thing to do? */
           64  +    SetConsoleCP(65001);
           65  +#endif
           66  +    return 0;
           67  +}
           68  +
           69  +static void disableRawMode(struct current *current)
           70  +{
           71  +    SetConsoleMode(current->inh, orig_consolemode);
           72  +}
           73  +
           74  +void linenoiseClearScreen(void)
           75  +{
           76  +    /* XXX: This is ugly. Should just have the caller pass a handle */
           77  +    struct current current;
           78  +
           79  +    current.outh = GetStdHandle(STD_OUTPUT_HANDLE);
           80  +
           81  +    if (getWindowSize(&current) == 0) {
           82  +        COORD topleft = { 0, 0 };
           83  +        DWORD n;
           84  +
           85  +        FillConsoleOutputCharacter(current.outh, ' ',
           86  +            current.cols * current.rows, topleft, &n);
           87  +        FillConsoleOutputAttribute(current.outh,
           88  +            FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN,
           89  +            current.cols * current.rows, topleft, &n);
           90  +        SetConsoleCursorPosition(current.outh, topleft);
           91  +    }
           92  +}
           93  +
           94  +static void cursorToLeft(struct current *current)
           95  +{
           96  +    COORD pos;
           97  +    DWORD n;
           98  +
           99  +    pos.X = 0;
          100  +    pos.Y = (SHORT)current->y;
          101  +
          102  +    FillConsoleOutputAttribute(current->outh,
          103  +        FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN, current->cols, pos, &n);
          104  +    current->x = 0;
          105  +}
          106  +
          107  +#ifdef USE_UTF8
          108  +static void flush_ubuf(struct current *current)
          109  +{
          110  +    COORD pos;
          111  +    DWORD nwritten;
          112  +    pos.Y = (SHORT)current->y;
          113  +    pos.X = (SHORT)current->x;
          114  +    SetConsoleCursorPosition(current->outh, pos);
          115  +    WriteConsoleW(current->outh, current->ubuf, current->ubuflen, &nwritten, 0);
          116  +    current->x += current->ubufcols;
          117  +    current->ubuflen = 0;
          118  +    current->ubufcols = 0;
          119  +}
          120  +
          121  +static void add_ubuf(struct current *current, int ch)
          122  +{
          123  +    /* This code originally by: Author: Mark E. Davis, 1994. */
          124  +    static const int halfShift  = 10; /* used for shifting by 10 bits */
          125  +
          126  +    static const DWORD halfBase = 0x0010000UL;
          127  +    static const DWORD halfMask = 0x3FFUL;
          128  +
          129  +    #define UNI_SUR_HIGH_START  0xD800
          130  +    #define UNI_SUR_HIGH_END    0xDBFF
          131  +    #define UNI_SUR_LOW_START   0xDC00
          132  +    #define UNI_SUR_LOW_END     0xDFFF
          133  +
          134  +    #define UNI_MAX_BMP 0x0000FFFF
          135  +
          136  +    if (ch > UNI_MAX_BMP) {
          137  +        /* convert from unicode to utf16 surrogate pairs
          138  +         * There is always space for one extra word in ubuf
          139  +         */
          140  +        ch -= halfBase;
          141  +        current->ubuf[current->ubuflen++] = (WORD)((ch >> halfShift) + UNI_SUR_HIGH_START);
          142  +        current->ubuf[current->ubuflen++] = (WORD)((ch & halfMask) + UNI_SUR_LOW_START);
          143  +    }
          144  +    else {
          145  +        current->ubuf[current->ubuflen++] = ch;
          146  +    }
          147  +    current->ubufcols += utf8_width(ch);
          148  +    if (current->ubuflen >= UBUF_MAX_CHARS) {
          149  +        flush_ubuf(current);
          150  +    }
          151  +}
          152  +#endif
          153  +
          154  +static int flushOutput(struct current *current)
          155  +{
          156  +    const char *pt = sb_str(current->output);
          157  +    int len = sb_len(current->output);
          158  +
          159  +#ifdef USE_UTF8
          160  +    /* convert utf8 in current->output into utf16 in current->ubuf
          161  +     */
          162  +    while (len) {
          163  +        int ch;
          164  +        int n = utf8_tounicode(pt, &ch);
          165  +
          166  +        pt += n;
          167  +        len -= n;
          168  +
          169  +        add_ubuf(current, ch);
          170  +    }
          171  +    flush_ubuf(current);
          172  +#else
          173  +    DWORD nwritten;
          174  +    COORD pos;
          175  +
          176  +    pos.Y = (SHORT)current->y;
          177  +    pos.X = (SHORT)current->x;
          178  +
          179  +    SetConsoleCursorPosition(current->outh, pos);
          180  +    WriteConsoleA(current->outh, pt, len, &nwritten, 0);
          181  +
          182  +    current->x += len;
          183  +#endif
          184  +
          185  +    sb_clear(current->output);
          186  +
          187  +    return 0;
          188  +}
          189  +
          190  +static int outputChars(struct current *current, const char *buf, int len)
          191  +{
          192  +    if (len < 0) {
          193  +        len = strlen(buf);
          194  +    }
          195  +    assert(current->output);
          196  +
          197  +    sb_append_len(current->output, buf, len);
          198  +
          199  +    return 0;
          200  +}
          201  +
          202  +static void outputNewline(struct current *current)
          203  +{
          204  +    /* On the last row output a newline to force a scroll */
          205  +    if (current->y + 1 == current->rows) {
          206  +        outputChars(current, "\n", 1);
          207  +    }
          208  +    flushOutput(current);
          209  +    current->x = 0;
          210  +    current->y++;
          211  +}
          212  +
          213  +static void setOutputHighlight(struct current *current, const int *props, int nprops)
          214  +{
          215  +    int colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
          216  +    int bold = 0;
          217  +    int reverse = 0;
          218  +    int i;
          219  +
          220  +    for (i = 0; i < nprops; i++) {
          221  +        switch (props[i]) {
          222  +            case 0:
          223  +               colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
          224  +               bold = 0;
          225  +               reverse = 0;
          226  +               break;
          227  +            case 1:
          228  +               bold = FOREGROUND_INTENSITY;
          229  +               break;
          230  +            case 7:
          231  +               reverse = 1;
          232  +               break;
          233  +            case 30:
          234  +               colour = 0;
          235  +               break;
          236  +            case 31:
          237  +               colour = FOREGROUND_RED;
          238  +               break;
          239  +            case 32:
          240  +               colour = FOREGROUND_GREEN;
          241  +               break;
          242  +            case 33:
          243  +               colour = FOREGROUND_RED | FOREGROUND_GREEN;
          244  +               break;
          245  +            case 34:
          246  +               colour = FOREGROUND_BLUE;
          247  +               break;
          248  +            case 35:
          249  +               colour = FOREGROUND_RED | FOREGROUND_BLUE;
          250  +               break;
          251  +            case 36:
          252  +               colour = FOREGROUND_BLUE | FOREGROUND_GREEN;
          253  +               break;
          254  +            case 37:
          255  +               colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
          256  +               break;
          257  +        }
          258  +    }
          259  +
          260  +    flushOutput(current);
          261  +
          262  +    if (reverse) {
          263  +        SetConsoleTextAttribute(current->outh, BACKGROUND_INTENSITY);
          264  +    }
          265  +    else {
          266  +        SetConsoleTextAttribute(current->outh, colour | bold);
          267  +    }
          268  +}
          269  +
          270  +static void eraseEol(struct current *current)
          271  +{
          272  +    COORD pos;
          273  +    DWORD n;
          274  +
          275  +    pos.X = (SHORT) current->x;
          276  +    pos.Y = (SHORT) current->y;
          277  +
          278  +    FillConsoleOutputCharacter(current->outh, ' ', current->cols - current->x, pos, &n);
          279  +}
          280  +
          281  +static void setCursorXY(struct current *current)
          282  +{
          283  +    COORD pos;
          284  +
          285  +    pos.X = (SHORT) current->x;
          286  +    pos.Y = (SHORT) current->y;
          287  +
          288  +    SetConsoleCursorPosition(current->outh, pos);
          289  +}
          290  +
          291  +
          292  +static void setCursorPos(struct current *current, int x)
          293  +{
          294  +    current->x = x;
          295  +    setCursorXY(current);
          296  +}
          297  +
          298  +static void cursorUp(struct current *current, int n)
          299  +{
          300  +    current->y -= n;
          301  +    setCursorXY(current);
          302  +}
          303  +
          304  +static void cursorDown(struct current *current, int n)
          305  +{
          306  +    current->y += n;
          307  +    setCursorXY(current);
          308  +}
          309  +
          310  +static int fd_read(struct current *current)
          311  +{
          312  +    while (1) {
          313  +        INPUT_RECORD irec;
          314  +        DWORD n;
          315  +        if (WaitForSingleObject(current->inh, INFINITE) != WAIT_OBJECT_0) {
          316  +            break;
          317  +        }
          318  +        if (!ReadConsoleInputW(current->inh, &irec, 1, &n)) {
          319  +            break;
          320  +        }
          321  +        if (irec.EventType == KEY_EVENT) {
          322  +            KEY_EVENT_RECORD *k = &irec.Event.KeyEvent;
          323  +            if (k->bKeyDown || k->wVirtualKeyCode == VK_MENU) {
          324  +                if (k->dwControlKeyState & ENHANCED_KEY) {
          325  +                    switch (k->wVirtualKeyCode) {
          326  +                     case VK_LEFT:
          327  +                        return SPECIAL_LEFT;
          328  +                     case VK_RIGHT:
          329  +                        return SPECIAL_RIGHT;
          330  +                     case VK_UP:
          331  +                        return SPECIAL_UP;
          332  +                     case VK_DOWN:
          333  +                        return SPECIAL_DOWN;
          334  +                     case VK_INSERT:
          335  +                        return SPECIAL_INSERT;
          336  +                     case VK_DELETE:
          337  +                        return SPECIAL_DELETE;
          338  +                     case VK_HOME:
          339  +                        return SPECIAL_HOME;
          340  +                     case VK_END:
          341  +                        return SPECIAL_END;
          342  +                     case VK_PRIOR:
          343  +                        return SPECIAL_PAGE_UP;
          344  +                     case VK_NEXT:
          345  +                        return SPECIAL_PAGE_DOWN;
          346  +                    }
          347  +                }
          348  +                /* Note that control characters are already translated in AsciiChar */
          349  +                else if (k->wVirtualKeyCode == VK_CONTROL)
          350  +                    continue;
          351  +                else {
          352  +                    return k->uChar.UnicodeChar;
          353  +                }
          354  +            }
          355  +        }
          356  +    }
          357  +    return -1;
          358  +}
          359  +
          360  +static int getWindowSize(struct current *current)
          361  +{
          362  +    CONSOLE_SCREEN_BUFFER_INFO info;
          363  +    if (!GetConsoleScreenBufferInfo(current->outh, &info)) {
          364  +        return -1;
          365  +    }
          366  +    current->cols = info.dwSize.X;
          367  +    current->rows = info.dwSize.Y;
          368  +    if (current->cols <= 0 || current->rows <= 0) {
          369  +        current->cols = 80;
          370  +        return -1;
          371  +    }
          372  +    current->y = info.dwCursorPosition.Y;
          373  +    current->x = info.dwCursorPosition.X;
          374  +    return 0;
          375  +}

Changes to linenoise.c.

            1  +#ifndef STRINGBUF_H
            2  +#define STRINGBUF_H
            3  +
            4  +/* (c) 2017 Workware Systems Pty Ltd  -- All Rights Reserved */
            5  +
            6  +#ifdef __cplusplus
            7  +extern "C" {
            8  +#endif
            9  +
           10  +/** @file
           11  + * A stringbuf is a resizing, null terminated string buffer.
           12  + *
           13  + * The buffer is reallocated as necessary.
           14  + *
           15  + * In general it is *not* OK to call these functions with a NULL pointer
           16  + * unless stated otherwise.
           17  + *
           18  + * If USE_UTF8 is defined, supports utf8.
           19  + */
           20  +
           21  +/**
           22  + * The stringbuf structure should not be accessed directly.
           23  + * Use the functions below.
           24  + */
           25  +typedef struct {
           26  +	int remaining;	/**< Allocated, but unused space */
           27  +	int last;		/**< Index of the null terminator (and thus the length of the string) */
           28  +#ifdef USE_UTF8
           29  +	int chars;		/**< Count of characters */
           30  +#endif
           31  +	char *data;		/**< Allocated memory containing the string or NULL for empty */
           32  +} stringbuf;
           33  +
           34  +/**
           35  + * Allocates and returns a new stringbuf with no elements.
           36  + */
           37  +stringbuf *sb_alloc(void);
           38  +
           39  +/**
           40  + * Frees a stringbuf.
           41  + * It is OK to call this with NULL.
           42  + */
           43  +void sb_free(stringbuf *sb);
           44  +
           45  +/**
           46  + * Returns an allocated copy of the stringbuf
           47  + */
           48  +stringbuf *sb_copy(stringbuf *sb);
           49  +
           50  +/**
           51  + * Returns the length of the buffer.
           52  + * 
           53  + * Returns 0 for both a NULL buffer and an empty buffer.
           54  + */
           55  +static inline int sb_len(stringbuf *sb) {
           56  +	return sb->last;
           57  +}
           58  +
           59  +/**
           60  + * Returns the utf8 character length of the buffer.
           61  + * 
           62  + * Returns 0 for both a NULL buffer and an empty buffer.
           63  + */
           64  +static inline int sb_chars(stringbuf *sb) {
           65  +#ifdef USE_UTF8
           66  +	return sb->chars;
           67  +#else
           68  +	return sb->last;
           69  +#endif
           70  +}
           71  +
           72  +/**
           73  + * Appends a null terminated string to the stringbuf
           74  + */
           75  +void sb_append(stringbuf *sb, const char *str);
           76  +
           77  +/**
           78  + * Like sb_append() except does not require a null terminated string.
           79  + * The length of 'str' is given as 'len'
           80  + *
           81  + * Note that in utf8 mode, characters will *not* be counted correctly
           82  + * if a partial utf8 sequence is added with sb_append_len()
           83  + */
           84  +void sb_append_len(stringbuf *sb, const char *str, int len);
           85  +
           86  +/**
           87  + * Returns a pointer to the null terminated string in the buffer.
           88  + *
           89  + * Note this pointer only remains valid until the next modification to the
           90  + * string buffer.
           91  + *
           92  + * The returned pointer can be used to update the buffer in-place
           93  + * as long as care is taken to not overwrite the end of the buffer.
           94  + */
           95  +static inline char *sb_str(const stringbuf *sb)
           96  +{
           97  +	return sb->data;
           98  +}
           99  +
          100  +/**
          101  + * Inserts the given string *before* (zero-based) 'index' in the stringbuf.
          102  + * If index is past the end of the buffer, the string is appended,
          103  + * just like sb_append()
          104  + */
          105  +void sb_insert(stringbuf *sb, int index, const char *str);
          106  +
          107  +/**
          108  + * Delete 'len' bytes in the string at the given index.
          109  + *
          110  + * Any bytes past the end of the buffer are ignored.
          111  + * The buffer remains null terminated.
          112  + *
          113  + * If len is -1, deletes to the end of the buffer.
          114  + */
          115  +void sb_delete(stringbuf *sb, int index, int len);
          116  +
          117  +/**
          118  + * Clear to an empty buffer.
          119  + */
          120  +void sb_clear(stringbuf *sb);
          121  +
          122  +/**
          123  + * Return an allocated copy of buffer and frees 'sb'.
          124  + *
          125  + * If 'sb' is empty, returns an allocated copy of "".
          126  + */
          127  +char *sb_to_string(stringbuf *sb);
          128  +
          129  +#ifdef __cplusplus
          130  +}
          131  +#endif
          132  +
          133  +#endif
          134  +#include <stdlib.h>
          135  +#include <string.h>
          136  +#include <stdio.h>
          137  +#include <ctype.h>
          138  +#include <assert.h>
          139  +
          140  +#ifndef STRINGBUF_H
          141  +#include "stringbuf.h"
          142  +#endif
          143  +#ifdef USE_UTF8
          144  +#include "utf8.h"
          145  +#endif
          146  +
          147  +#define SB_INCREMENT 200
          148  +
          149  +stringbuf *sb_alloc(void)
          150  +{
          151  +	stringbuf *sb = (stringbuf *)malloc(sizeof(*sb));
          152  +	sb->remaining = 0;
          153  +	sb->last = 0;
          154  +#ifdef USE_UTF8
          155  +	sb->chars = 0;
          156  +#endif
          157  +	sb->data = NULL;
          158  +
          159  +	return(sb);
          160  +}
          161  +
          162  +void sb_free(stringbuf *sb)
          163  +{
          164  +	if (sb) {
          165  +		free(sb->data);
          166  +	}
          167  +	free(sb);
          168  +}
          169  +
          170  +void sb_realloc(stringbuf *sb, int newlen)
          171  +{
          172  +	sb->data = (char *)realloc(sb->data, newlen);
          173  +	sb->remaining = newlen - sb->last;
          174  +}
          175  +
          176  +void sb_append(stringbuf *sb, const char *str)
          177  +{
          178  +	sb_append_len(sb, str, strlen(str));
          179  +}
          180  +
          181  +void sb_append_len(stringbuf *sb, const char *str, int len)
          182  +{
          183  +	int utf8_strlen(const char *str, int bytelen);
          184  +	if (sb->remaining < len + 1) {
          185  +		sb_realloc(sb, sb->last + len + 1 + SB_INCREMENT);
          186  +	}
          187  +	memcpy(sb->data + sb->last, str, len);
          188  +	sb->data[sb->last + len] = 0;
          189  +
          190  +	sb->last += len;
          191  +	sb->remaining -= len;
          192  +#ifdef USE_UTF8
          193  +	sb->chars += utf8_strlen(str, len);
          194  +#endif
          195  +}
          196  +
          197  +char *sb_to_string(stringbuf *sb)
          198  +{
          199  +	if (sb->data == NULL) {
          200  +		/* Return an allocated empty string, not null */
          201  +		return strdup("");
          202  +	}
          203  +	else {
          204  +		/* Just return the data and free the stringbuf structure */
          205  +		char *pt = sb->data;
          206  +		free(sb);
          207  +		return pt;
          208  +	}
          209  +}
          210  +
          211  +/* Insert and delete operations */
          212  +
          213  +/* Moves up all the data at position 'pos' and beyond by 'len' bytes
          214  + * to make room for new data
          215  + *
          216  + * Note: Does *not* update sb->chars
          217  + */
          218  +static void sb_insert_space(stringbuf *sb, int pos, int len)
          219  +{
          220  +	assert(pos <= sb->last);
          221  +
          222  +	/* Make sure there is enough space */
          223  +	if (sb->remaining < len) {
          224  +		sb_realloc(sb, sb->last + len + SB_INCREMENT);
          225  +	}
          226  +	/* Now move it up */
          227  +	memmove(sb->data + pos + len, sb->data + pos, sb->last - pos);
          228  +	sb->last += len;
          229  +	sb->remaining -= len;
          230  +	/* And null terminate */
          231  +	sb->data[sb->last] = 0;
          232  +}
          233  +
          234  +/**
          235  + * Move down all the data from pos + len, effectively
          236  + * deleting the data at position 'pos' of length 'len'
          237  + */
          238  +static void sb_delete_space(stringbuf *sb, int pos, int len)
          239  +{
          240  +	assert(pos < sb->last);
          241  +	assert(pos + len <= sb->last);
          242  +
          243  +#ifdef USE_UTF8
          244  +	sb->chars -= utf8_strlen(sb->data + pos, len);
          245  +#endif
          246  +
          247  +	/* Now move it up */
          248  +	memmove(sb->data + pos, sb->data + pos + len, sb->last - pos - len);
          249  +	sb->last -= len;
          250  +	sb->remaining += len;
          251  +	/* And null terminate */
          252  +	sb->data[sb->last] = 0;
          253  +}
          254  +
          255  +void sb_insert(stringbuf *sb, int index, const char *str)
          256  +{
          257  +	if (index >= sb->last) {
          258  +		/* Inserting after the end of the list appends. */
          259  +		sb_append(sb, str);
          260  +	}
          261  +	else {
          262  +		int len = strlen(str);
          263  +
          264  +		sb_insert_space(sb, index, len);
          265  +		memcpy(sb->data + index, str, len);
          266  +#ifdef USE_UTF8
          267  +		sb->chars += utf8_strlen(str, len);
          268  +#endif
          269  +	}
          270  +}
          271  +
          272  +/**
          273  + * Delete the bytes at index 'index' for length 'len'
          274  + * Has no effect if the index is past the end of the list.
          275  + */
          276  +void sb_delete(stringbuf *sb, int index, int len)
          277  +{
          278  +	if (index < sb->last) {
          279  +		char *pos = sb->data + index;
          280  +		if (len < 0) {
          281  +			len = sb->last;
          282  +		}
          283  +
          284  +		sb_delete_space(sb, pos - sb->data, len);
          285  +	}
          286  +}
          287  +
          288  +void sb_clear(stringbuf *sb)
          289  +{
          290  +	if (sb->data) {
          291  +		/* Null terminate */
          292  +		sb->data[0] = 0;
          293  +		sb->last = 0;
          294  +#ifdef USE_UTF8
          295  +		sb->chars = 0;
          296  +#endif
          297  +	}
          298  +}
     1    299   /* linenoise.c -- guerrilla line editing library against the idea that a
     2    300    * line editing lib needs to be 20,000 lines of C code.
     3    301    *
     4    302    * You can find the latest source code at:
     5    303    *
     6    304    *   http://github.com/msteveb/linenoise
     7    305    *   (forked from http://github.com/antirez/linenoise)
................................................................................
    53    351    * ------------
    54    352    * List of escape sequences used by this program, we do everything just
    55    353    * a few sequences. In order to be so cheap we may have some
    56    354    * flickering effect with some slow terminal, but the lesser sequences
    57    355    * the more compatible.
    58    356    *
    59    357    * 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
          358  + *    Sequence: ESC [ 0 K
          359  + *    Effect: clear from cursor to end of line
    64    360    *
    65    361    * CUF (CUrsor Forward)
    66    362    *    Sequence: ESC [ n C
    67         - *    Effect: moves cursor forward of n chars
          363  + *    Effect: moves cursor forward n chars
    68    364    *
    69    365    * CR (Carriage Return)
    70    366    *    Sequence: \r
    71    367    *    Effect: moves cursor to column 1
    72    368    *
    73    369    * The following are used to clear the screen: ESC [ H ESC [ 2 J
    74    370    * This is actually composed of two sequences:
................................................................................
    91    387    *    Effect: Exit standout mode
    92    388    *
    93    389    * == Only used if TIOCGWINSZ fails ==
    94    390    * DSR/CPR (Report cursor position)
    95    391    *    Sequence: ESC [ 6 n
    96    392    *    Effect: reports current cursor position as ESC [ NNN ; MMM R
    97    393    *
          394  + * == Only used in multiline mode ==
          395  + * CUU (Cursor Up)
          396  + *    Sequence: ESC [ n A
          397  + *    Effect: moves cursor up n chars.
          398  + *
          399  + * CUD (Cursor Down)
          400  + *    Sequence: ESC [ n B
          401  + *    Effect: moves cursor down n chars.
          402  + *
    98    403    * win32/console
    99    404    * -------------
   100    405    * If __MINGW32__ is defined, the win32 console API is used.
   101    406    * This could probably be made to work for the msvc compiler too.
   102    407    * This support based in part on work by Jon Griffiths.
   103    408    */
   104    409   
................................................................................
   131    436   #include <errno.h>
   132    437   #include <string.h>
   133    438   #include <signal.h>
   134    439   #include <stdlib.h>
   135    440   #include <sys/types.h>
   136    441   
   137    442   #include "linenoise.h"
          443  +#ifndef STRINGBUF_H
          444  +#include "stringbuf.h"
          445  +#endif
   138    446   #include "utf8.h"
   139    447   
   140    448   #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
   141         -#define LINENOISE_MAX_LINE 4096
   142    449   
   143    450   #define ctrl(C) ((C) - '@')
   144    451   
   145    452   /* Use -ve numbers here to co-exist with normal unicode chars */
   146    453   enum {
   147    454       SPECIAL_NONE,
          455  +    /* don't use -1 here since that indicates error */
   148    456       SPECIAL_UP = -20,
   149    457       SPECIAL_DOWN = -21,
   150    458       SPECIAL_LEFT = -22,
   151    459       SPECIAL_RIGHT = -23,
   152    460       SPECIAL_DELETE = -24,
   153    461       SPECIAL_HOME = -25,
   154    462       SPECIAL_END = -26,
   155    463       SPECIAL_INSERT = -27,
   156    464       SPECIAL_PAGE_UP = -28,
   157         -    SPECIAL_PAGE_DOWN = -29
          465  +    SPECIAL_PAGE_DOWN = -29,
          466  +
          467  +    /* Some handy names for other special keycodes */
          468  +    CHAR_ESCAPE = 27,
          469  +    CHAR_DELETE = 127,
   158    470   };
   159    471   
   160    472   static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
   161    473   static int history_len = 0;
   162    474   static char **history = NULL;
   163    475   
   164    476   /* Structure to contain the status of the current (being edited) line */
   165    477   struct current {
   166         -    char *buf;  /* Current buffer. Always null terminated */
   167         -    int bufmax; /* Size of the buffer, including space for the null termination */
   168         -    int len;    /* Number of bytes in 'buf' */
   169         -    int chars;  /* Number of chars in 'buf' (utf-8 chars) */
          478  +    stringbuf *buf; /* Current buffer. Always null terminated */
   170    479       int pos;    /* Cursor position, measured in chars */
   171    480       int cols;   /* Size of the window, in chars */
          481  +    int nrows;  /* How many rows are being used in multiline mode (>= 1) */
          482  +    int rpos;   /* The current row containing the cursor - multiline mode only */
   172    483       const char *prompt;
   173         -    char *capture; /* Allocated capture buffer, or NULL for none. Always null terminated */
          484  +    stringbuf *capture; /* capture buffer, or NULL for none. Always null terminated */
          485  +    stringbuf *output;  /* used only during refreshLine() - output accumulator */
   174    486   #if defined(USE_TERMIOS)
   175    487       int fd;     /* Terminal fd */
   176    488   #elif defined(USE_WINCONSOLE)
   177    489       HANDLE outh; /* Console output handle */
   178    490       HANDLE inh; /* Console input handle */
   179    491       int rows;   /* Screen rows */
   180    492       int x;      /* Current column during output */
   181    493       int y;      /* Current row */
          494  +#ifdef USE_UTF8
          495  +    #define UBUF_MAX_CHARS 132
          496  +    WORD ubuf[UBUF_MAX_CHARS + 1];  /* Accumulates utf16 output - one extra for final surrogate pairs */
          497  +    int ubuflen;      /* length used in ubuf */
          498  +    int ubufcols;     /* how many columns are represented by the chars in ubuf? */
          499  +#endif
   182    500   #endif
   183    501   };
   184    502   
   185    503   static int fd_read(struct current *current);
   186    504   static int getWindowSize(struct current *current);
          505  +static void cursorDown(struct current *current, int n);
          506  +static void cursorUp(struct current *current, int n);
          507  +static void eraseEol(struct current *current);
          508  +static void refreshLine(struct current *current);
          509  +static void refreshLineAlt(struct current *current, const char *prompt, const char *buf, int cursor_pos);
          510  +static void setCursorPos(struct current *current, int x);
          511  +static void setOutputHighlight(struct current *current, const int *props, int nprops);
          512  +static void set_current(struct current *current, const char *str);
   187    513   
   188    514   void linenoiseHistoryFree(void) {
   189    515       if (history) {
   190    516           int j;
   191    517   
   192    518           for (j = 0; j < history_len; j++)
   193    519               free(history[j]);
   194    520           free(history);
   195    521           history = NULL;
   196    522           history_len = 0;
   197    523       }
   198    524   }
          525  +
          526  +struct esc_parser {
          527  +    enum {
          528  +        EP_START,   /* looking for ESC */
          529  +        EP_ESC,     /* looking for [ */
          530  +        EP_DIGITS,  /* parsing digits */
          531  +        EP_PROPS,   /* parsing digits or semicolons */
          532  +        EP_END,     /* ok */
          533  +        EP_ERROR,   /* error */
          534  +    } state;
          535  +    int props[5];   /* properties are stored here */
          536  +    int maxprops;   /* size of the props[] array */
          537  +    int numprops;   /* number of properties found */
          538  +    int termchar;   /* terminator char, or 0 for any alpha */
          539  +    int current;    /* current (partial) property value */
          540  +};
          541  +
          542  +/**
          543  + * Initialise the escape sequence parser at *parser.
          544  + *
          545  + * If termchar is 0 any alpha char terminates ok. Otherwise only the given
          546  + * char terminates successfully.
          547  + * Run the parser state machine with calls to parseEscapeSequence() for each char.
          548  + */
          549  +static void initParseEscapeSeq(struct esc_parser *parser, int termchar)
          550  +{
          551  +    parser->state = EP_START;
          552  +    parser->maxprops = sizeof(parser->props) / sizeof(*parser->props);
          553  +    parser->numprops = 0;
          554  +    parser->current = 0;
          555  +    parser->termchar = termchar;
          556  +}
          557  +
          558  +/**
          559  + * Pass character 'ch' into the state machine to parse:
          560  + *   'ESC' '[' <digits> (';' <digits>)* <termchar>
          561  + *
          562  + * The first character must be ESC.
          563  + * Returns the current state. The state machine is done when it returns either EP_END
          564  + * or EP_ERROR.
          565  + *
          566  + * On EP_END, the "property/attribute" values can be read from parser->props[]
          567  + * of length parser->numprops.
          568  + */
          569  +static int parseEscapeSequence(struct esc_parser *parser, int ch)
          570  +{
          571  +    switch (parser->state) {
          572  +        case EP_START:
          573  +            parser->state = (ch == '\x1b') ? EP_ESC : EP_ERROR;
          574  +            break;
          575  +        case EP_ESC:
          576  +            parser->state = (ch == '[') ? EP_DIGITS : EP_ERROR;
          577  +            break;
          578  +        case EP_PROPS:
          579  +            if (ch == ';') {
          580  +                parser->state = EP_DIGITS;
          581  +donedigits:
          582  +                if (parser->numprops + 1 < parser->maxprops) {
          583  +                    parser->props[parser->numprops++] = parser->current;
          584  +                    parser->current = 0;
          585  +                }
          586  +                break;
          587  +            }
          588  +            /* fall through */
          589  +        case EP_DIGITS:
          590  +            if (ch >= '0' && ch <= '9') {
          591  +                parser->current = parser->current * 10 + (ch - '0');
          592  +                parser->state = EP_PROPS;
          593  +                break;
          594  +            }
          595  +            /* must be terminator */
          596  +            if (parser->termchar != ch) {
          597  +                if (parser->termchar != 0 || !((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))) {
          598  +                    parser->state = EP_ERROR;
          599  +                    break;
          600  +                }
          601  +            }
          602  +            parser->state = EP_END;
          603  +            goto donedigits;
          604  +        case EP_END:
          605  +            parser->state = EP_ERROR;
          606  +            break;
          607  +        case EP_ERROR:
          608  +            break;
          609  +    }
          610  +    return parser->state;
          611  +}
          612  +
          613  +/*#define DEBUG_REFRESHLINE*/
          614  +
          615  +#ifdef DEBUG_REFRESHLINE
          616  +#define DRL(ARGS...) fprintf(dfh, ARGS)
          617  +static FILE *dfh;
          618  +
          619  +static void DRL_CHAR(int ch)
          620  +{
          621  +    if (ch < ' ') {
          622  +        DRL("^%c", ch + '@');
          623  +    }
          624  +    else if (ch > 127) {
          625  +        DRL("\\u%04x", ch);
          626  +    }
          627  +    else {
          628  +        DRL("%c", ch);
          629  +    }
          630  +}
          631  +static void DRL_STR(const char *str)
          632  +{
          633  +    while (*str) {
          634  +        int ch;
          635  +        int n = utf8_tounicode(str, &ch);
          636  +        str += n;
          637  +        DRL_CHAR(ch);
          638  +    }
          639  +}
          640  +#else
          641  +#define DRL(ARGS...)
          642  +#define DRL_CHAR(ch)
          643  +#define DRL_STR(str)
          644  +#endif
          645  +
          646  +#if defined(USE_WINCONSOLE)
          647  +#include "linenoise-win32.c"
          648  +#endif
   199    649   
   200    650   #if defined(USE_TERMIOS)
   201    651   static void linenoiseAtExit(void);
   202    652   static struct termios orig_termios; /* in order to restore at exit */
   203    653   static int rawmode = 0; /* for atexit() function to check if restore is needed*/
   204    654   static int atexit_registered = 0; /* register atexit just 1 time */
   205    655   
   206         -static const char *unsupported_term[] = {"dumb","cons25",NULL};
          656  +static const char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
   207    657   
   208    658   static int isUnsupportedTerm(void) {
   209    659       char *term = getenv("TERM");
   210    660   
   211    661       if (term) {
   212    662           int j;
   213    663           for (j = 0; unsupported_term[j]; j++) {
................................................................................
   276    726   
   277    727   /* gcc/glibc insists that we care about the return code of write!
   278    728    * Clarification: This means that a void-cast like "(void) (EXPR)"
   279    729    * does not work.
   280    730    */
   281    731   #define IGNORE_RC(EXPR) if (EXPR) {}
   282    732   
   283         -/* This is fdprintf() on some systems, but use a different
   284         - * name to avoid conflicts
          733  +/**
          734  + * Output bytes directly, or accumulate output (if current->output is set)
   285    735    */
   286         -static void fd_printf(int fd, const char *format, ...)
          736  +static void outputChars(struct current *current, const char *buf, int len)
          737  +{
          738  +    if (len < 0) {
          739  +        len = strlen(buf);
          740  +    }
          741  +    if (current->output) {
          742  +        sb_append_len(current->output, buf, len);
          743  +    }
          744  +    else {
          745  +        IGNORE_RC(write(current->fd, buf, len));
          746  +    }
          747  +}
          748  +
          749  +/* Like outputChars, but using printf-style formatting
          750  + */
          751  +static void outputFormatted(struct current *current, const char *format, ...)
   287    752   {
   288    753       va_list args;
   289    754       char buf[64];
   290    755       int n;
   291    756   
   292    757       va_start(args, format);
   293    758       n = vsnprintf(buf, sizeof(buf), format, args);
   294         -    /* This will never happen because we are sure to use fd_printf() for short sequences */
   295         -    assert(n < sizeof(buf));
          759  +    /* This will never happen because we are sure to use outputFormatted() only for short sequences */
          760  +    assert(n < (int)sizeof(buf));
   296    761       va_end(args);
   297         -    IGNORE_RC(write(fd, buf, n));
   298         -}
   299         -
   300         -void linenoiseClearScreen(void)
   301         -{
   302         -    fd_printf(STDOUT_FILENO, "\x1b[H\x1b[2J");
          762  +    outputChars(current, buf, n);
   303    763   }
   304    764   
   305    765   static void cursorToLeft(struct current *current)
   306    766   {
   307         -    fd_printf(current->fd, "\r");
          767  +    outputChars(current, "\r", -1);
   308    768   }
   309    769   
   310         -static int outputChars(struct current *current, const char *buf, int len)
          770  +static void setOutputHighlight(struct current *current, const int *props, int nprops)
   311    771   {
   312         -    return write(current->fd, buf, len);
   313         -}
   314         -
   315         -static void outputControlChar(struct current *current, char ch)
   316         -{
   317         -    fd_printf(current->fd, "\x1b[7m^%c\x1b[0m", ch);
          772  +    outputChars(current, "\x1b[", -1);
          773  +    while (nprops--) {
          774  +        outputFormatted(current, "%d%c", *props, (nprops == 0) ? 'm' : ';');
          775  +        props++;
          776  +    }
   318    777   }
   319    778   
   320    779   static void eraseEol(struct current *current)
   321    780   {
   322         -    fd_printf(current->fd, "\x1b[0K");
          781  +    outputChars(current, "\x1b[0K", -1);
   323    782   }
   324    783   
   325    784   static void setCursorPos(struct current *current, int x)
   326    785   {
   327    786       if (x == 0) {
   328    787           cursorToLeft(current);
   329    788       }
   330    789       else {
   331         -        fd_printf(current->fd, "\r\x1b[%dC", x);
          790  +        outputFormatted(current, "\r\x1b[%dC", x);
   332    791       }
   333    792   }
          793  +
          794  +static void cursorUp(struct current *current, int n)
          795  +{
          796  +    if (n) {
          797  +        outputFormatted(current, "\x1b[%dA", n);
          798  +    }
          799  +}
          800  +
          801  +static void cursorDown(struct current *current, int n)
          802  +{
          803  +    if (n) {
          804  +        outputFormatted(current, "\x1b[%dB", n);
          805  +    }
          806  +}
          807  +
          808  +void linenoiseClearScreen(void)
          809  +{
          810  +    write(STDOUT_FILENO, "\x1b[H\x1b[2J", 7);
          811  +}
   334    812   
   335    813   /**
   336    814    * Reads a char from 'fd', waiting at most 'timeout' milliseconds.
   337    815    *
   338    816    * A timeout of -1 means to wait forever.
   339    817    *
   340    818    * Returns -1 if no char is received within the time or an error occurs.
................................................................................
   385    863       utf8_tounicode(buf, &c);
   386    864       return c;
   387    865   #else
   388    866       return fd_read_char(current->fd, -1);
   389    867   #endif
   390    868   }
   391    869   
   392         -static int countColorControlChars(const char* prompt)
   393         -{
   394         -    /* ANSI color control sequences have the form:
   395         -     * "\x1b" "[" [0-9;]* "m"
   396         -     * We parse them with a simple state machine.
   397         -     */
   398         -
   399         -    enum {
   400         -        search_esc,
   401         -        expect_bracket,
   402         -        expect_trail
   403         -    } state = search_esc;
   404         -    int len = 0, found = 0;
   405         -    char ch;
   406         -
   407         -    /* XXX: Strictly we should be checking utf8 chars rather than
   408         -     *      bytes in case of the extremely unlikely scenario where
   409         -     *      an ANSI sequence is part of a utf8 sequence.
   410         -     */
   411         -    while ((ch = *prompt++) != 0) {
   412         -        switch (state) {
   413         -        case search_esc:
   414         -            if (ch == '\x1b') {
   415         -                state = expect_bracket;
   416         -            }
   417         -            break;
   418         -        case expect_bracket:
   419         -            if (ch == '[') {
   420         -                state = expect_trail;
   421         -                /* 3 for "\e[ ... m" */
   422         -                len = 3;
   423         -                break;
   424         -            }
   425         -            state = search_esc;
   426         -            break;
   427         -        case expect_trail:
   428         -            if ((ch == ';') || ((ch >= '0' && ch <= '9'))) {
   429         -                /* 0-9, or semicolon */
   430         -                len++;
   431         -                break;
   432         -            }
   433         -            if (ch == 'm') {
   434         -                found += len;
   435         -            }
   436         -            state = search_esc;
   437         -            break;
   438         -        }
   439         -    }
   440         -
   441         -    return found;
   442         -}
   443    870   
   444    871   /**
   445    872    * Stores the current cursor column in '*cols'.
   446    873    * Returns 1 if OK, or 0 if failed to determine cursor pos.
   447    874    */
   448         -static int queryCursor(int fd, int* cols)
          875  +static int queryCursor(struct current *current, int* cols)
   449    876   {
          877  +    struct esc_parser parser;
          878  +    int ch;
          879  +
          880  +    /* Should not be buffering this output, it needs to go immediately */
          881  +    assert(current->output == NULL);
          882  +
   450    883       /* control sequence - report cursor location */
   451         -    fd_printf(fd, "\x1b[6n");
          884  +    outputChars(current, "\x1b[6n", -1);
   452    885   
   453    886       /* Parse the response: ESC [ rows ; cols R */
   454         -    if (fd_read_char(fd, 100) == 0x1b &&
   455         -        fd_read_char(fd, 100) == '[') {
   456         -
   457         -        int n = 0;
   458         -        while (1) {
   459         -            int ch = fd_read_char(fd, 100);
   460         -            if (ch == ';') {
   461         -                /* Ignore rows */
   462         -                n = 0;
   463         -            }
   464         -            else if (ch == 'R') {
   465         -                /* Got cols */
   466         -                if (n != 0 && n < 1000) {
   467         -                    *cols = n;
          887  +    initParseEscapeSeq(&parser, 'R');
          888  +    while ((ch = fd_read_char(current->fd, 100)) > 0) {
          889  +        switch (parseEscapeSequence(&parser, ch)) {
          890  +            default:
          891  +                continue;
          892  +            case EP_END:
          893  +                if (parser.numprops == 2 && parser.props[1] < 1000) {
          894  +                    *cols = parser.props[1];
          895  +                    return 1;
   468    896                   }
          897  +                break;
          898  +            case EP_ERROR:
   469    899                   break;
   470         -            }
   471         -            else if (ch >= 0 && ch <= '9') {
   472         -                n = n * 10 + ch - '0';
   473         -            }
   474         -            else {
   475         -                break;
   476         -            }
   477    900           }
   478         -        return 1;
          901  +        /* failed */
          902  +        break;
   479    903       }
   480         -
   481    904       return 0;
   482    905   }
   483    906   
   484    907   /**
   485    908    * Updates current->cols with the current window size (width)
   486    909    */
   487    910   static int getWindowSize(struct current *current)
................................................................................
   507    930        * This gives us the width without messing with the externally
   508    931        * visible cursor position.
   509    932        */
   510    933   
   511    934       if (current->cols == 0) {
   512    935           int here;
   513    936   
          937  +        /* If anything fails => default 80 */
   514    938           current->cols = 80;
   515    939   
   516    940           /* (a) */
   517         -        if (queryCursor (current->fd, &here)) {
          941  +        if (queryCursor (current, &here)) {
   518    942               /* (b) */
   519         -            fd_printf(current->fd, "\x1b[999C");
          943  +            setCursorPos(current, 999);
   520    944   
   521    945               /* (c). Note: If (a) succeeded, then (c) should as well.
   522    946                * For paranoia we still check and have a fallback action
   523    947                * for (d) in case of failure..
   524    948                */
   525         -            if (!queryCursor (current->fd, &current->cols)) {
   526         -                /* (d') Unable to get accurate position data, reset
   527         -                 * the cursor to the far left. While this may not
   528         -                 * restore the exact original position it should not
   529         -                 * be too bad.
   530         -                 */
   531         -                fd_printf(current->fd, "\r");
   532         -            } else {
          949  +            if (queryCursor (current, &current->cols)) {
   533    950                   /* (d) Reset the cursor back to the original location. */
   534    951                   if (current->cols > here) {
   535         -                    fd_printf(current->fd, "\x1b[%dD", current->cols - here);
          952  +                    setCursorPos(current, here);
   536    953                   }
   537    954               }
   538         -        } /* 1st query failed, doing nothing => default 80 */
          955  +        }
   539    956       }
   540    957   
   541    958       return 0;
   542    959   }
   543    960   
   544    961   /**
   545         - * If escape (27) was received, reads subsequent
          962  + * If CHAR_ESCAPE was received, reads subsequent
   546    963    * chars to determine if this is a known special key.
   547    964    *
   548    965    * Returns SPECIAL_NONE if unrecognised, or -1 if EOF.
   549    966    *
   550    967    * If no additional char is received within a short time,
   551         - * 27 is returned.
          968  + * CHAR_ESCAPE is returned.
   552    969    */
   553    970   static int check_special(int fd)
   554    971   {
   555    972       int c = fd_read_char(fd, 50);
   556    973       int c2;
   557    974   
   558    975       if (c < 0) {
   559         -        return 27;
          976  +        return CHAR_ESCAPE;
   560    977       }
   561    978   
   562    979       c2 = fd_read_char(fd, 50);
   563    980       if (c2 < 0) {
   564    981           return c2;
   565    982       }
   566    983       if (c == '[' || c == 'O') {
................................................................................
   603   1020               /* .e.g \e[12~ or '\e[11;2~   discard the complete sequence */
   604   1021               c = fd_read_char(fd, 50);
   605   1022           }
   606   1023       }
   607   1024   
   608   1025       return SPECIAL_NONE;
   609   1026   }
   610         -#elif defined(USE_WINCONSOLE)
   611         -
   612         -static DWORD orig_consolemode = 0;
   613         -
   614         -static int enableRawMode(struct current *current) {
   615         -    DWORD n;
   616         -    INPUT_RECORD irec;
   617         -
   618         -    current->outh = GetStdHandle(STD_OUTPUT_HANDLE);
   619         -    current->inh = GetStdHandle(STD_INPUT_HANDLE);
   620         -
   621         -    if (!PeekConsoleInput(current->inh, &irec, 1, &n)) {
   622         -        return -1;
   623         -    }
   624         -    if (getWindowSize(current) != 0) {
   625         -        return -1;
   626         -    }
   627         -    if (GetConsoleMode(current->inh, &orig_consolemode)) {
   628         -        SetConsoleMode(current->inh, ENABLE_PROCESSED_INPUT);
   629         -    }
   630         -    return 0;
   631         -}
   632         -
   633         -static void disableRawMode(struct current *current)
   634         -{
   635         -    SetConsoleMode(current->inh, orig_consolemode);
   636         -}
   637         -
   638         -void linenoiseClearScreen(void)
   639         -{
   640         -    /* XXX: This is ugly. Should just have the caller pass a handle */
   641         -    struct current current;
   642         -
   643         -    current.outh = GetStdHandle(STD_OUTPUT_HANDLE);
   644         -
   645         -    if (getWindowSize(&current) == 0) {
   646         -        COORD topleft = { 0, 0 };
   647         -        DWORD n;
   648         -
   649         -        FillConsoleOutputCharacter(current.outh, ' ',
   650         -            current.cols * current.rows, topleft, &n);
   651         -        FillConsoleOutputAttribute(current.outh,
   652         -            FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN,
   653         -            current.cols * current.rows, topleft, &n);
   654         -        SetConsoleCursorPosition(current.outh, topleft);
   655         -    }
   656         -}
   657         -
   658         -static void cursorToLeft(struct current *current)
   659         -{
   660         -    COORD pos;
   661         -    DWORD n;
   662         -
   663         -    pos.X = 0;
   664         -    pos.Y = (SHORT)current->y;
   665         -
   666         -    FillConsoleOutputAttribute(current->outh,
   667         -        FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN, current->cols, pos, &n);
   668         -    current->x = 0;
   669         -}
   670         -
   671         -static int outputChars(struct current *current, const char *buf, int len)
   672         -{
   673         -    COORD pos;
   674         -    DWORD n;
   675         -
   676         -    pos.Y = (SHORT)current->y;
   677         -
   678         -#ifdef USE_UTF8
   679         -    while ( len > 0 ) {
   680         -        int c, s;
   681         -        wchar_t wc;
   682         -
   683         -        s = utf8_tounicode(buf, &c);
   684         -
   685         -        len -= s;
   686         -        buf += s;
   687         -
   688         -        wc = (wchar_t)c;
   689         -
   690         -        pos.X = (SHORT)current->x;
   691         -
   692         -        /* fixed display utf8 character */
   693         -        WriteConsoleOutputCharacterW(current->outh, &wc, 1, pos, &n);
   694         -
   695         -        current->x += utf8_width(c);
   696         -    }
   697         -#else
   698         -    pos.X = (SHORT)current->x;
   699         -
   700         -    WriteConsoleOutputCharacterA(current->outh, buf, len, pos, &n);
   701         -    current->x += len;
   702         -#endif
   703         -
   704         -    return 0;
         1027  +#endif
         1028  +
         1029  +static void clearOutputHighlight(struct current *current)
         1030  +{
         1031  +    int nohighlight = 0;
         1032  +    setOutputHighlight(current, &nohighlight, 1);
   705   1033   }
   706   1034   
   707   1035   static void outputControlChar(struct current *current, char ch)
   708   1036   {
   709         -    COORD pos;
   710         -    DWORD n;
   711         -
   712         -    pos.X = (SHORT) current->x;
   713         -    pos.Y = (SHORT) current->y;
   714         -
   715         -    FillConsoleOutputAttribute(current->outh, BACKGROUND_INTENSITY, 2, pos, &n);
         1037  +    int reverse = 7;
         1038  +    setOutputHighlight(current, &reverse, 1);
   716   1039       outputChars(current, "^", 1);
   717   1040       outputChars(current, &ch, 1);
         1041  +    clearOutputHighlight(current);
   718   1042   }
   719   1043   
   720         -static void eraseEol(struct current *current)
   721         -{
   722         -    COORD pos;
   723         -    DWORD n;
   724         -
   725         -    pos.X = (SHORT) current->x;
   726         -    pos.Y = (SHORT) current->y;
   727         -
   728         -    FillConsoleOutputCharacter(current->outh, ' ', current->cols - current->x, pos, &n);
   729         -}
   730         -
   731         -static void setCursorPos(struct current *current, int x)
   732         -{
   733         -    COORD pos;
   734         -
   735         -    pos.X = (SHORT)x;
   736         -    pos.Y = (SHORT) current->y;
   737         -
   738         -    SetConsoleCursorPosition(current->outh, pos);
   739         -    current->x = x;
   740         -}
   741         -
   742         -static int fd_read(struct current *current)
   743         -{
   744         -    while (1) {
   745         -        INPUT_RECORD irec;
   746         -        DWORD n;
   747         -        if (WaitForSingleObject(current->inh, INFINITE) != WAIT_OBJECT_0) {
   748         -            break;
   749         -        }
   750         -        if (!ReadConsoleInput (current->inh, &irec, 1, &n)) {
   751         -            break;
   752         -        }
   753         -        if (irec.EventType == KEY_EVENT && irec.Event.KeyEvent.bKeyDown) {
   754         -            KEY_EVENT_RECORD *k = &irec.Event.KeyEvent;
   755         -            if (k->dwControlKeyState & ENHANCED_KEY) {
   756         -                switch (k->wVirtualKeyCode) {
   757         -                 case VK_LEFT:
   758         -                    return SPECIAL_LEFT;
   759         -                 case VK_RIGHT:
   760         -                    return SPECIAL_RIGHT;
   761         -                 case VK_UP:
   762         -                    return SPECIAL_UP;
   763         -                 case VK_DOWN:
   764         -                    return SPECIAL_DOWN;
   765         -                 case VK_INSERT:
   766         -                    return SPECIAL_INSERT;
   767         -                 case VK_DELETE:
   768         -                    return SPECIAL_DELETE;
   769         -                 case VK_HOME:
   770         -                    return SPECIAL_HOME;
   771         -                 case VK_END:
   772         -                    return SPECIAL_END;
   773         -                 case VK_PRIOR:
   774         -                    return SPECIAL_PAGE_UP;
   775         -                 case VK_NEXT:
   776         -                    return SPECIAL_PAGE_DOWN;
   777         -                }
   778         -            }
   779         -            /* Note that control characters are already translated in AsciiChar */
   780         -            else if (k->wVirtualKeyCode == VK_CONTROL)
   781         -                continue;
   782         -            else {
   783         -#ifdef USE_UTF8
   784         -                return k->uChar.UnicodeChar;
   785         -#else
   786         -                return k->uChar.AsciiChar;
   787         -#endif
   788         -            }
   789         -        }
   790         -    }
   791         -    return -1;
   792         -}
   793         -
   794         -static int countColorControlChars(const char* prompt)
   795         -{
   796         -    /* For windows we assume that there are no embedded ansi color
   797         -     * control sequences.
   798         -     */
   799         -    return 0;
   800         -}
   801         -
   802         -static int getWindowSize(struct current *current)
   803         -{
   804         -    CONSOLE_SCREEN_BUFFER_INFO info;
   805         -    if (!GetConsoleScreenBufferInfo(current->outh, &info)) {
   806         -        return -1;
   807         -    }
   808         -    current->cols = info.dwSize.X;
   809         -    current->rows = info.dwSize.Y;
   810         -    if (current->cols <= 0 || current->rows <= 0) {
   811         -        current->cols = 80;
   812         -        return -1;
   813         -    }
   814         -    current->y = info.dwCursorPosition.Y;
   815         -    current->x = info.dwCursorPosition.X;
   816         -    return 0;
   817         -}
   818         -#endif
   819         -
   820   1044   #ifndef utf8_getchars
   821   1045   static int utf8_getchars(char *buf, int c)
   822   1046   {
   823   1047   #ifdef USE_UTF8
   824   1048       return utf8_fromunicode(buf, c);
   825   1049   #else
   826   1050       *buf = c;
................................................................................
   831   1055   
   832   1056   /**
   833   1057    * Returns the unicode character at the given offset,
   834   1058    * or -1 if none.
   835   1059    */
   836   1060   static int get_char(struct current *current, int pos)
   837   1061   {
   838         -    if (pos >= 0 && pos < current->chars) {
         1062  +    if (pos >= 0 && pos < sb_chars(current->buf)) {
   839   1063           int c;
   840         -        int i = utf8_index(current->buf, pos);
   841         -        (void)utf8_tounicode(current->buf + i, &c);
         1064  +        int i = utf8_index(sb_str(current->buf), pos);
         1065  +        (void)utf8_tounicode(sb_str(current->buf) + i, &c);
   842   1066           return c;
   843   1067       }
   844   1068       return -1;
   845   1069   }
   846   1070   
   847         -static void refreshLine(const char *prompt, struct current *current)
   848         -{
   849         -    int plen;
   850         -    int pchars;
   851         -    int backup = 0;
         1071  +static int char_display_width(int ch)
         1072  +{
         1073  +    if (ch < ' ') {
         1074  +        /* control chars take two positions */
         1075  +        return 2;
         1076  +    }
         1077  +    else {
         1078  +        return utf8_width(ch);
         1079  +    }
         1080  +}
         1081  +
         1082  +#ifndef NO_COMPLETION
         1083  +static linenoiseCompletionCallback *completionCallback = NULL;
         1084  +static void *completionUserdata = NULL;
         1085  +static int showhints = 1;
         1086  +static linenoiseHintsCallback *hintsCallback = NULL;
         1087  +static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
         1088  +static void *hintsUserdata = NULL;
         1089  +
         1090  +static void beep() {
         1091  +#ifdef USE_TERMIOS
         1092  +    fprintf(stderr, "\x7");
         1093  +    fflush(stderr);
         1094  +#endif
         1095  +}
         1096  +
         1097  +static void freeCompletions(linenoiseCompletions *lc) {
         1098  +    size_t i;
         1099  +    for (i = 0; i < lc->len; i++)
         1100  +        free(lc->cvec[i]);
         1101  +    free(lc->cvec);
         1102  +}
         1103  +
         1104  +static int completeLine(struct current *current) {
         1105  +    linenoiseCompletions lc = { 0, NULL };
         1106  +    int c = 0;
         1107  +
         1108  +    completionCallback(sb_str(current->buf),&lc,completionUserdata);
         1109  +    if (lc.len == 0) {
         1110  +        beep();
         1111  +    } else {
         1112  +        size_t stop = 0, i = 0;
         1113  +
         1114  +        while(!stop) {
         1115  +            /* Show completion or original buffer */
         1116  +            if (i < lc.len) {
         1117  +                int chars = utf8_strlen(lc.cvec[i], -1);
         1118  +                refreshLineAlt(current, current->prompt, lc.cvec[i], chars);
         1119  +            } else {
         1120  +                refreshLine(current);
         1121  +            }
         1122  +
         1123  +            c = fd_read(current);
         1124  +            if (c == -1) {
         1125  +                break;
         1126  +            }
         1127  +
         1128  +            switch(c) {
         1129  +                case '\t': /* tab */
         1130  +                    i = (i+1) % (lc.len+1);
         1131  +                    if (i == lc.len) beep();
         1132  +                    break;
         1133  +                case CHAR_ESCAPE: /* escape */
         1134  +                    /* Re-show original buffer */
         1135  +                    if (i < lc.len) {
         1136  +                        refreshLine(current);
         1137  +                    }
         1138  +                    stop = 1;
         1139  +                    break;
         1140  +                default:
         1141  +                    /* Update buffer and return */
         1142  +                    if (i < lc.len) {
         1143  +                        set_current(current,lc.cvec[i]);
         1144  +                    }
         1145  +                    stop = 1;
         1146  +                    break;
         1147  +            }
         1148  +        }
         1149  +    }
         1150  +
         1151  +    freeCompletions(&lc);
         1152  +    return c; /* Return last read character */
         1153  +}
         1154  +
         1155  +/* Register a callback function to be called for tab-completion.
         1156  +   Returns the prior callback so that the caller may (if needed)
         1157  +   restore it when done. */
         1158  +linenoiseCompletionCallback * linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn, void *userdata) {
         1159  +    linenoiseCompletionCallback * old = completionCallback;
         1160  +    completionCallback = fn;
         1161  +    completionUserdata = userdata;
         1162  +    return old;
         1163  +}
         1164  +
         1165  +void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
         1166  +    lc->cvec = (char **)realloc(lc->cvec,sizeof(char*)*(lc->len+1));
         1167  +    lc->cvec[lc->len++] = strdup(str);
         1168  +}
         1169  +
         1170  +void linenoiseSetHintsCallback(linenoiseHintsCallback *callback, void *userdata)
         1171  +{
         1172  +    hintsCallback = callback;
         1173  +    hintsUserdata = userdata;
         1174  +}
         1175  +
         1176  +void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *callback)
         1177  +{
         1178  +    freeHintsCallback = callback;
         1179  +}
         1180  +
         1181  +#endif
         1182  +
         1183  +
         1184  +static const char *reduceSingleBuf(const char *buf, int availcols, int *cursor_pos)
         1185  +{
         1186  +    /* We have availcols columns available.
         1187  +     * If necessary, strip chars off the front of buf until *cursor_pos
         1188  +     * fits within availcols
         1189  +     */
         1190  +    int needcols = 0;
         1191  +    int pos = 0;
         1192  +    int new_cursor_pos = *cursor_pos;
         1193  +    const char *pt = buf;
         1194  +
         1195  +    DRL("reduceSingleBuf: availcols=%d, cursor_pos=%d\n", availcols, *cursor_pos);
         1196  +
         1197  +    while (*pt) {
         1198  +        int ch;
         1199  +        int n = utf8_tounicode(pt, &ch);
         1200  +        pt += n;
         1201  +
         1202  +        needcols += char_display_width(ch);
         1203  +
         1204  +        /* If we need too many cols, strip
         1205  +         * chars off the front of buf to make it fit.
         1206  +         * We keep 3 extra cols to the right of the cursor.
         1207  +         * 2 for possible wide chars, 1 for the last column that
         1208  +         * can't be used.
         1209  +         */
         1210  +        while (needcols >= availcols - 3) {
         1211  +            n = utf8_tounicode(buf, &ch);
         1212  +            buf += n;
         1213  +            needcols -= char_display_width(ch);
         1214  +            DRL_CHAR(ch);
         1215  +
         1216  +            /* and adjust the apparent cursor position */
         1217  +            new_cursor_pos--;
         1218  +
         1219  +            if (buf == pt) {
         1220  +                /* can't remove more than this */
         1221  +                break;
         1222  +            }
         1223  +        }
         1224  +
         1225  +        if (pos++ == *cursor_pos) {
         1226  +            break;
         1227  +        }
         1228  +
         1229  +    }
         1230  +    DRL("<snip>");
         1231  +    DRL_STR(buf);
         1232  +    DRL("\nafter reduce, needcols=%d, new_cursor_pos=%d\n", needcols, new_cursor_pos);
         1233  +
         1234  +    /* Done, now new_cursor_pos contains the adjusted cursor position
         1235  +     * and buf points to he adjusted start
         1236  +     */
         1237  +    *cursor_pos = new_cursor_pos;
         1238  +    return buf;
         1239  +}
         1240  +
         1241  +static int mlmode = 0;
         1242  +
         1243  +void linenoiseSetMultiLine(int enableml)
         1244  +{
         1245  +    mlmode = enableml;
         1246  +}
         1247  +
         1248  +/* Helper of refreshSingleLine() and refreshMultiLine() to show hints
         1249  + * to the right of the prompt. */
         1250  +static void refreshShowHints(struct current *current, const char *buf, int availcols) {
         1251  +    if (showhints && hintsCallback && availcols > 0) {
         1252  +        int bold = 0;
         1253  +        int color = -1;
         1254  +        char *hint = hintsCallback(buf, &color, &bold, hintsUserdata);
         1255  +        if (hint) {
         1256  +            const char *pt;
         1257  +            if (bold == 1 && color == -1) color = 37;
         1258  +            if (bold || color > 0) {
         1259  +                int props[3] = { bold, color, 49 }; /* bold, color, fgnormal */
         1260  +                setOutputHighlight(current, props, 3);
         1261  +            }
         1262  +            DRL("<hint bold=%d,color=%d>", bold, color);
         1263  +            pt = hint;
         1264  +            while (*pt) {
         1265  +                int ch;
         1266  +                int n = utf8_tounicode(pt, &ch);
         1267  +                int width = char_display_width(ch);
         1268  +
         1269  +                if (width >= availcols) {
         1270  +                    DRL("<hinteol>");
         1271  +                    break;
         1272  +                }
         1273  +                DRL_CHAR(ch);
         1274  +
         1275  +                availcols -= width;
         1276  +                outputChars(current, pt, n);
         1277  +                pt += n;
         1278  +            }
         1279  +            if (bold || color > 0) {
         1280  +                clearOutputHighlight(current);
         1281  +            }
         1282  +            /* Call the function to free the hint returned. */
         1283  +            if (freeHintsCallback) freeHintsCallback(hint, hintsUserdata);
         1284  +        }
         1285  +    }
         1286  +}
         1287  +
         1288  +#ifdef USE_TERMIOS
         1289  +static void refreshStart(struct current *current)
         1290  +{
         1291  +    /* We accumulate all output here */
         1292  +    assert(current->output == NULL);
         1293  +    current->output = sb_alloc();
         1294  +}
         1295  +
         1296  +static void refreshEnd(struct current *current)
         1297  +{
         1298  +    /* Output everything at once */
         1299  +    IGNORE_RC(write(current->fd, sb_str(current->output), sb_len(current->output)));
         1300  +    sb_free(current->output);
         1301  +    current->output = NULL;
         1302  +}
         1303  +
         1304  +static void refreshStartChars(struct current *current)
         1305  +{
         1306  +}
         1307  +
         1308  +static void refreshNewline(struct current *current)
         1309  +{
         1310  +    DRL("<nl>");
         1311  +    outputChars(current, "\n", 1);
         1312  +}
         1313  +
         1314  +static void refreshEndChars(struct current *current)
         1315  +{
         1316  +}
         1317  +#endif
         1318  +
         1319  +static void refreshLineAlt(struct current *current, const char *prompt, const char *buf, int cursor_pos)
         1320  +{
   852   1321       int i;
   853         -    const char *buf = current->buf;
   854         -    int chars = current->chars;
   855         -    int pos = current->pos;
   856         -    int b;
   857         -    int ch;
   858         -    int n;
   859         -    int width;
   860         -    int bufwidth;
         1322  +    const char *pt;
         1323  +    int displaycol;
         1324  +    int displayrow;
         1325  +    int visible;
         1326  +    int currentpos;
         1327  +    int notecursor;
         1328  +    int cursorcol = 0;
         1329  +    int cursorrow = 0;
         1330  +    struct esc_parser parser;
         1331  +
         1332  +#ifdef DEBUG_REFRESHLINE
         1333  +    dfh = fopen("linenoise.debuglog", "a");
         1334  +#endif
   861   1335   
   862   1336       /* Should intercept SIGWINCH. For now, just get the size every time */
   863   1337       getWindowSize(current);
   864   1338   
   865         -    plen = strlen(prompt);
   866         -    pchars = utf8_strwidth(prompt, utf8_strlen(prompt, plen));
         1339  +    refreshStart(current);
   867   1340   
   868         -    /* Scan the prompt for embedded ansi color control sequences and
   869         -     * discount them as characters/columns.
   870         -     */
   871         -    pchars -= countColorControlChars(prompt);
         1341  +    DRL("wincols=%d, cursor_pos=%d, nrows=%d, rpos=%d\n", current->cols, cursor_pos, current->nrows, current->rpos);
   872   1342   
   873         -    /* Account for a line which is too long to fit in the window.
   874         -     * Note that control chars require an extra column
         1343  +    /* Here is the plan:
         1344  +     * (a) move the the bottom row, going down the appropriate number of lines
         1345  +     * (b) move to beginning of line and erase the current line
         1346  +     * (c) go up one line and do the same, until we have erased up to the first row
         1347  +     * (d) output the prompt, counting cols and rows, taking into account escape sequences
         1348  +     * (e) output the buffer, counting cols and rows
         1349  +     *   (e') when we hit the current pos, save the cursor position
         1350  +     * (f) move the cursor to the saved cursor position
         1351  +     * (g) save the current cursor row and number of rows
   875   1352        */
   876   1353   
   877         -    /* How many cols are required to the left of 'pos'?
   878         -     * The prompt, plus one extra for each control char
   879         -     */
   880         -    n = pchars + utf8_strwidth(buf, utf8_strlen(buf, current->len));
   881         -    b = 0;
   882         -    for (i = 0; i < pos; i++) {
   883         -        b += utf8_tounicode(buf + b, &ch);
   884         -        if (ch < ' ') {
   885         -            n++;
   886         -        }
   887         -    }
   888         -
   889         -    /* Pluse one if the current char is a control character */
   890         -    if (current->pos < current->chars && get_char(current, current->pos) < ' ') {
   891         -        n++;
   892         -    }
   893         -
   894         -    /* If too many are needed, strip chars off the front of 'buf'
   895         -     * until it fits. Note that if the current char is a control character,
   896         -     * we need one extra col.
   897         -     */
   898         -    while (n >= current->cols && pos > 0) {
   899         -        b = utf8_tounicode(buf, &ch);
   900         -        if (ch < ' ') {
   901         -            n--;
   902         -        }
   903         -        n -= utf8_width(ch);
   904         -        buf += b;
   905         -        pos--;
   906         -        chars--;
   907         -    }
   908         -
   909         -    /* Cursor to left edge, then the prompt */
   910         -    cursorToLeft(current);
   911         -    outputChars(current, prompt, plen);
   912         -
   913         -    /* Now the current buffer content */
   914         -
   915         -    /* Need special handling for control characters.
   916         -     * If we hit 'cols', stop.
   917         -     */
   918         -    b = 0; /* unwritted bytes */
   919         -    n = 0; /* How many control chars were written */
   920         -    width = 0; /* current display width */
   921         -    bufwidth = utf8_strwidth(buf, pos);
   922         -
   923         -    for (i = 0; i < chars; i++) {
         1354  +    /* (a) - The cursor is currently at row rpos */
         1355  +    cursorDown(current, current->nrows - current->rpos - 1);
         1356  +    DRL("<cud=%d>", current->nrows - current->rpos - 1);
         1357  +
         1358  +    /* (b), (c) - Erase lines upwards until we get to the first row */
         1359  +    for (i = 0; i < current->nrows; i++) {
         1360  +        if (i) {
         1361  +            DRL("<cup>");
         1362  +            cursorUp(current, 1);
         1363  +        }
         1364  +        DRL("<clearline>");
         1365  +        cursorToLeft(current);
         1366  +        eraseEol(current);
         1367  +    }
         1368  +    DRL("\n");
         1369  +
         1370  +    /* (d) First output the prompt. control sequences don't take up display space */
         1371  +    pt = prompt;
         1372  +    displaycol = 0; /* current display column */
         1373  +    displayrow = 0; /* current display row */
         1374  +    visible = 1;
         1375  +
         1376  +    refreshStartChars(current);
         1377  +
         1378  +    while (*pt) {
         1379  +        int width;
         1380  +        int ch;
         1381  +        int n = utf8_tounicode(pt, &ch);
         1382  +
         1383  +        if (visible && ch == CHAR_ESCAPE) {
         1384  +            /* The start of an escape sequence, so not visible */
         1385  +            visible = 0;
         1386  +            initParseEscapeSeq(&parser, 'm');
         1387  +            DRL("<esc-seq-start>");
         1388  +        }
         1389  +
         1390  +        if (ch == '\n' || ch == '\r') {
         1391  +            /* treat both CR and NL the same and force wrap */
         1392  +            refreshNewline(current);
         1393  +            displaycol = 0;
         1394  +            displayrow++;
         1395  +        }
         1396  +        else {
         1397  +            width = visible * utf8_width(ch);
         1398  +
         1399  +            displaycol += width;
         1400  +            if (displaycol >= current->cols) {
         1401  +                /* need to wrap to the next line because of newline or if it doesn't fit
         1402  +                 * XXX this is a problem in single line mode
         1403  +                 */
         1404  +                refreshNewline(current);
         1405  +                displaycol = width;
         1406  +                displayrow++;
         1407  +            }
         1408  +
         1409  +            DRL_CHAR(ch);
         1410  +#ifdef USE_WINCONSOLE
         1411  +            if (visible) {
         1412  +                outputChars(current, pt, n);
         1413  +            }
         1414  +#else
         1415  +            outputChars(current, pt, n);
         1416  +#endif
         1417  +        }
         1418  +        pt += n;
         1419  +
         1420  +        if (!visible) {
         1421  +            switch (parseEscapeSequence(&parser, ch)) {
         1422  +                case EP_END:
         1423  +                    visible = 1;
         1424  +                    setOutputHighlight(current, parser.props, parser.numprops);
         1425  +                    DRL("<esc-seq-end,numprops=%d>", parser.numprops);
         1426  +                    break;
         1427  +                case EP_ERROR:
         1428  +                    DRL("<esc-seq-err>");
         1429  +                    visible = 1;
         1430  +                    break;
         1431  +            }
         1432  +        }
         1433  +    }
         1434  +
         1435  +    /* Now we are at the first line with all lines erased */
         1436  +    DRL("\nafter prompt: displaycol=%d, displayrow=%d\n", displaycol, displayrow);
         1437  +
         1438  +
         1439  +    /* (e) output the buffer, counting cols and rows */
         1440  +    if (mlmode == 0) {
         1441  +        /* In this mode we may need to trim chars from the start of the buffer until the
         1442  +         * cursor fits in the window.
         1443  +         */
         1444  +        pt = reduceSingleBuf(buf, current->cols - displaycol, &cursor_pos);
         1445  +    }
         1446  +    else {
         1447  +        pt = buf;
         1448  +    }
         1449  +
         1450  +    currentpos = 0;
         1451  +    notecursor = -1;
         1452  +
         1453  +    while (*pt) {
   924   1454           int ch;
   925         -        int w = utf8_tounicode(buf + b, &ch);
   926         -        if (ch < ' ') {
   927         -            n++;
         1455  +        int n = utf8_tounicode(pt, &ch);
         1456  +        int width = char_display_width(ch);
         1457  +
         1458  +        if (currentpos == cursor_pos) {
         1459  +            /* (e') wherever we output this character is where we want the cursor */
         1460  +            notecursor = 1;
   928   1461           }
   929   1462   
   930         -        width += utf8_width(ch);
         1463  +        if (displaycol + width >= current->cols) {
         1464  +            if (mlmode == 0) {
         1465  +                /* In single line mode stop once we print as much as we can on one line */
         1466  +                DRL("<slmode>");
         1467  +                break;
         1468  +            }
         1469  +            /* need to wrap to the next line since it doesn't fit */
         1470  +            refreshNewline(current);
         1471  +            displaycol = 0;
         1472  +            displayrow++;
         1473  +        }
   931   1474   
   932         -        if (pchars + width + n >= current->cols) {
   933         -            break;
         1475  +        if (notecursor == 1) {
         1476  +            /* (e') Save this position as the current cursor position */
         1477  +            cursorcol = displaycol;
         1478  +            cursorrow = displayrow;
         1479  +            notecursor = 0;
         1480  +            DRL("<cursor>");
   934   1481           }
         1482  +
         1483  +        displaycol += width;
         1484  +
   935   1485           if (ch < ' ') {
   936         -            /* A control character, so write the buffer so far */
   937         -            outputChars(current, buf, b);
   938         -            buf += b + w;
   939         -            b = 0;
   940   1486               outputControlChar(current, ch + '@');
   941         -            if (i < pos) {
   942         -                backup++;
   943         -            }
   944   1487           }
   945   1488           else {
   946         -            b += w;
         1489  +            outputChars(current, pt, n);
   947   1490           }
         1491  +        DRL_CHAR(ch);
         1492  +        if (width != 1) {
         1493  +            DRL("<w=%d>", width);
         1494  +        }
         1495  +
         1496  +        pt += n;
         1497  +        currentpos++;
   948   1498       }
   949         -    outputChars(current, buf, b);
   950   1499   
   951         -    /* Erase to right, move cursor to original position */
   952         -    eraseEol(current);
   953         -    setCursorPos(current, bufwidth + pchars + backup);
         1500  +    /* If we didn't see the cursor, it is at the current location */
         1501  +    if (notecursor) {
         1502  +        DRL("<cursor>");
         1503  +        cursorcol = displaycol;
         1504  +        cursorrow = displayrow;
         1505  +    }
         1506  +
         1507  +    DRL("\nafter buf: displaycol=%d, displayrow=%d, cursorcol=%d, cursorrow=%d\n\n", displaycol, displayrow, cursorcol, cursorrow);
         1508  +
         1509  +    /* (f) show hints */
         1510  +    refreshShowHints(current, buf, current->cols - displaycol);
         1511  +
         1512  +    refreshEndChars(current);
         1513  +
         1514  +    /* (g) move the cursor to the correct place */
         1515  +    cursorUp(current, displayrow - cursorrow);
         1516  +    setCursorPos(current, cursorcol);
         1517  +
         1518  +    /* (h) Update the number of rows if larger, but never reduce this */
         1519  +    if (displayrow >= current->nrows) {
         1520  +        current->nrows = displayrow + 1;
         1521  +    }
         1522  +    /* And remember the row that the cursor is on */
         1523  +    current->rpos = cursorrow;
         1524  +
         1525  +    refreshEnd(current);
         1526  +
         1527  +#ifdef DEBUG_REFRESHLINE
         1528  +    fclose(dfh);
         1529  +#endif
         1530  +}
         1531  +
         1532  +static void refreshLine(struct current *current)
         1533  +{
         1534  +    refreshLineAlt(current, current->prompt, sb_str(current->buf), current->pos);
   954   1535   }
   955   1536   
   956   1537   static void set_current(struct current *current, const char *str)
   957   1538   {
   958         -    strncpy(current->buf, str, current->bufmax);
   959         -    current->buf[current->bufmax - 1] = 0;
   960         -    current->len = strlen(current->buf);
   961         -    current->pos = current->chars = utf8_strlen(current->buf, current->len);
   962         -}
   963         -
   964         -static int has_room(struct current *current, int bytes)
   965         -{
   966         -    return current->len + bytes < current->bufmax - 1;
         1539  +    sb_clear(current->buf);
         1540  +    sb_append(current->buf, str);
         1541  +    current->pos = sb_chars(current->buf);
   967   1542   }
   968   1543   
   969   1544   /**
   970   1545    * Removes the char at 'pos'.
   971   1546    *
   972   1547    * Returns 1 if the line needs to be refreshed, 2 if not
   973   1548    * and 0 if nothing was removed
   974   1549    */
   975   1550   static int remove_char(struct current *current, int pos)
   976   1551   {
   977         -    if (pos >= 0 && pos < current->chars) {
   978         -        int p1, p2;
   979         -        int ret = 1;
   980         -        p1 = utf8_index(current->buf, pos);
   981         -        p2 = p1 + utf8_index(current->buf + p1, 1);
         1552  +    if (pos >= 0 && pos < sb_chars(current->buf)) {
         1553  +        int offset = utf8_index(sb_str(current->buf), pos);
         1554  +        int nbytes = utf8_index(sb_str(current->buf) + offset, 1);
   982   1555   
   983         -#ifdef USE_TERMIOS
   984         -        /* optimise remove char in the case of removing the last char */
   985         -        if (current->pos == pos + 1 && current->pos == current->chars) {
   986         -            if (current->buf[pos] >= ' ' && utf8_strlen(current->prompt, -1) + utf8_strlen(current->buf, current->len) < current->cols - 1) {
   987         -                ret = 2;
   988         -                fd_printf(current->fd, "\b \b");
   989         -            }
   990         -        }
   991         -#endif
   992         -
   993         -        /* Move the null char too */
   994         -        memmove(current->buf + p1, current->buf + p2, current->len - p2 + 1);
   995         -        current->len -= (p2 - p1);
   996         -        current->chars--;
         1556  +        /* Note that we no longer try to optimise the remove-at-end case
         1557  +         * since control characters and wide characters mess
         1558  +         * up the simple count
         1559  +         */
         1560  +        sb_delete(current->buf, offset, nbytes);
   997   1561   
   998   1562           if (current->pos > pos) {
   999   1563               current->pos--;
  1000   1564           }
  1001         -        return ret;
         1565  +        return 1;
  1002   1566       }
  1003   1567       return 0;
  1004   1568   }
  1005   1569   
  1006   1570   /**
  1007   1571    * Insert 'ch' at position 'pos'
  1008   1572    *
  1009   1573    * Returns 1 if the line needs to be refreshed, 2 if not
  1010   1574    * and 0 if nothing was inserted (no room)
  1011   1575    */
  1012   1576   static int insert_char(struct current *current, int pos, int ch)
  1013   1577   {
  1014         -    char buf[MAX_UTF8_LEN];
  1015         -    int n = utf8_getchars(buf, ch);
         1578  +    if (pos >= 0 && pos <= sb_chars(current->buf)) {
         1579  +        char buf[MAX_UTF8_LEN + 1];
         1580  +        int offset = utf8_index(sb_str(current->buf), pos);
         1581  +        int n = utf8_getchars(buf, ch);
  1016   1582   
  1017         -    if (has_room(current, n) && pos >= 0 && pos <= current->chars) {
  1018         -        int p1, p2;
  1019         -        int ret = 1;
  1020         -        p1 = utf8_index(current->buf, pos);
  1021         -        p2 = p1 + n;
         1583  +        /* null terminate since sb_insert() requires it */
         1584  +        buf[n] = 0;
  1022   1585   
  1023         -#ifdef USE_TERMIOS
  1024         -        /* optimise the case where adding a single char to the end and no scrolling is needed */
  1025         -        if (current->pos == pos && current->chars == pos) {
  1026         -            if (ch >= ' ' && utf8_strlen(current->prompt, -1) + utf8_strlen(current->buf, current->len) < current->cols - 1) {
  1027         -                IGNORE_RC(write(current->fd, buf, n));
  1028         -                ret = 2;
  1029         -            }
  1030         -        }
  1031         -#endif
         1586  +        /* Optimisation removed - see reason in remove_char() */
  1032   1587   
  1033         -        memmove(current->buf + p2, current->buf + p1, current->len - p1);
  1034         -        memcpy(current->buf + p1, buf, n);
  1035         -        current->len += n;
  1036         -
  1037         -        current->chars++;
         1588  +        sb_insert(current->buf, offset, buf);
  1038   1589           if (current->pos >= pos) {
  1039   1590               current->pos++;
  1040   1591           }
  1041         -        return ret;
         1592  +        return 1;
  1042   1593       }
  1043   1594       return 0;
  1044   1595   }
  1045   1596   
  1046   1597   /**
  1047   1598    * Captures up to 'n' characters starting at 'pos' for the cut buffer.
  1048   1599    *
  1049   1600    * This replaces any existing characters in the cut buffer.
  1050   1601    */
  1051         -static void capture_chars(struct current *current, int pos, int n)
         1602  +static void capture_chars(struct current *current, int pos, int nchars)
  1052   1603   {
  1053         -    if (pos >= 0 && (pos + n - 1) < current->chars) {
  1054         -        int p1 = utf8_index(current->buf, pos);
  1055         -        int nbytes = utf8_index(current->buf + p1, n);
         1604  +    if (pos >= 0 && (pos + nchars - 1) < sb_chars(current->buf)) {
         1605  +        int offset = utf8_index(sb_str(current->buf), pos);
         1606  +        int nbytes = utf8_index(sb_str(current->buf) + offset, nchars);
  1056   1607   
  1057   1608           if (nbytes) {
  1058         -            free(current->capture);
  1059         -            /* Include space for the null terminator */
  1060         -            current->capture = (char *)malloc(nbytes + 1);
  1061         -            memcpy(current->capture, current->buf + p1, nbytes);
  1062         -            current->capture[nbytes] = '\0';
         1609  +            if (current->capture) {
         1610  +                sb_clear(current->capture);
         1611  +            }
         1612  +            else {
         1613  +                current->capture = sb_alloc();
         1614  +            }
         1615  +            sb_append_len(current->capture, sb_str(current->buf) + offset, nbytes);
  1063   1616           }
  1064   1617       }
  1065   1618   }
  1066   1619   
  1067   1620   /**
  1068   1621    * Removes up to 'n' characters at cursor position 'pos'.
  1069   1622    *
................................................................................
  1099   1652           inserted++;
  1100   1653           pos++;
  1101   1654           chars += n;
  1102   1655       }
  1103   1656       return inserted;
  1104   1657   }
  1105   1658   
  1106         -#ifndef NO_COMPLETION
  1107         -static linenoiseCompletionCallback *completionCallback = NULL;
  1108         -static void *completionUserdata = NULL;
         1659  +/**
         1660  + * Returns the keycode to process, or 0 if none.
         1661  + */
         1662  +static int reverseIncrementalSearch(struct current *current)
         1663  +{
         1664  +    /* Display the reverse-i-search prompt and process chars */
         1665  +    char rbuf[50];
         1666  +    char rprompt[80];
         1667  +    int rchars = 0;
         1668  +    int rlen = 0;
         1669  +    int searchpos = history_len - 1;
         1670  +    int c;
  1109   1671   
  1110         -static void beep() {
         1672  +    rbuf[0] = 0;
         1673  +    while (1) {
         1674  +        int n = 0;
         1675  +        const char *p = NULL;
         1676  +        int skipsame = 0;
         1677  +        int searchdir = -1;
         1678  +
         1679  +        snprintf(rprompt, sizeof(rprompt), "(reverse-i-search)'%s': ", rbuf);
         1680  +        refreshLineAlt(current, rprompt, sb_str(current->buf), current->pos);
         1681  +        c = fd_read(current);
         1682  +        if (c == ctrl('H') || c == CHAR_DELETE) {
         1683  +            if (rchars) {
         1684  +                int p = utf8_index(rbuf, --rchars);
         1685  +                rbuf[p] = 0;
         1686  +                rlen = strlen(rbuf);
         1687  +            }
         1688  +            continue;
         1689  +        }
  1111   1690   #ifdef USE_TERMIOS
  1112         -    fprintf(stderr, "\x7");
  1113         -    fflush(stderr);
         1691  +        if (c == CHAR_ESCAPE) {
         1692  +            c = check_special(current->fd);
         1693  +        }
  1114   1694   #endif
  1115         -}
  1116         -
  1117         -static void freeCompletions(linenoiseCompletions *lc) {
  1118         -    size_t i;
  1119         -    for (i = 0; i < lc->len; i++)
  1120         -        free(lc->cvec[i]);
  1121         -    free(lc->cvec);
  1122         -}
  1123         -
  1124         -static int completeLine(struct current *current) {
  1125         -    linenoiseCompletions lc = { 0, NULL };
  1126         -    int c = 0;
  1127         -
  1128         -    completionCallback(current->buf,&lc,completionUserdata);
  1129         -    if (lc.len == 0) {
  1130         -        beep();
  1131         -    } else {
  1132         -        size_t stop = 0, i = 0;
  1133         -
  1134         -        while(!stop) {
  1135         -            /* Show completion or original buffer */
  1136         -            if (i < lc.len) {
  1137         -                struct current tmp = *current;
  1138         -                tmp.buf = lc.cvec[i];
  1139         -                tmp.pos = tmp.len = strlen(tmp.buf);
  1140         -                tmp.chars = utf8_strlen(tmp.buf, tmp.len);
  1141         -                refreshLine(current->prompt, &tmp);
  1142         -            } else {
  1143         -                refreshLine(current->prompt, current);
  1144         -            }
  1145         -
  1146         -            c = fd_read(current);
  1147         -            if (c == -1) {
         1695  +        if (c == ctrl('P') || c == SPECIAL_UP) {
         1696  +            /* Search for the previous (earlier) match */
         1697  +            if (searchpos > 0) {
         1698  +                searchpos--;
         1699  +            }
         1700  +            skipsame = 1;
         1701  +        }
         1702  +        else if (c == ctrl('N') || c == SPECIAL_DOWN) {
         1703  +            /* Search for the next (later) match */
         1704  +            if (searchpos < history_len) {
         1705  +                searchpos++;
         1706  +            }
         1707  +            searchdir = 1;
         1708  +            skipsame = 1;
         1709  +        }
         1710  +        else if (c >= ' ') {
         1711  +            /* >= here to allow for null terminator */
         1712  +            if (rlen >= (int)sizeof(rbuf) - MAX_UTF8_LEN) {
         1713  +                continue;
         1714  +            }
         1715  +
         1716  +            n = utf8_getchars(rbuf + rlen, c);
         1717  +            rlen += n;
         1718  +            rchars++;
         1719  +            rbuf[rlen] = 0;
         1720  +
         1721  +            /* Adding a new char resets the search location */
         1722  +            searchpos = history_len - 1;
         1723  +        }
         1724  +        else {
         1725  +            /* Exit from incremental search mode */
         1726  +            break;
         1727  +        }
         1728  +
         1729  +        /* Now search through the history for a match */
         1730  +        for (; searchpos >= 0 && searchpos < history_len; searchpos += searchdir) {
         1731  +            p = strstr(history[searchpos], rbuf);
         1732  +            if (p) {
         1733  +                /* Found a match */
         1734  +                if (skipsame && strcmp(history[searchpos], sb_str(current->buf)) == 0) {
         1735  +                    /* But it is identical, so skip it */
         1736  +                    continue;
         1737  +                }
         1738  +                /* Copy the matching line and set the cursor position */
         1739  +                set_current(current,history[searchpos]);
         1740  +                current->pos = utf8_strlen(history[searchpos], p - history[searchpos]);
  1148   1741                   break;
  1149   1742               }
  1150         -
  1151         -            switch(c) {
  1152         -                case '\t': /* tab */
  1153         -                    i = (i+1) % (lc.len+1);
  1154         -                    if (i == lc.len) beep();
  1155         -                    break;
  1156         -                case 27: /* escape */
  1157         -                    /* Re-show original buffer */
  1158         -                    if (i < lc.len) {
  1159         -                        refreshLine(current->prompt, current);
  1160         -                    }
  1161         -                    stop = 1;
  1162         -                    break;
  1163         -                default:
  1164         -                    /* Update buffer and return */
  1165         -                    if (i < lc.len) {
  1166         -                        set_current(current,lc.cvec[i]);
  1167         -                    }
  1168         -                    stop = 1;
  1169         -                    break;
  1170         -            }
         1743  +        }
         1744  +        if (!p && n) {
         1745  +            /* No match, so don't add it */
         1746  +            rchars--;
         1747  +            rlen -= n;
         1748  +            rbuf[rlen] = 0;
  1171   1749           }
  1172   1750       }
         1751  +    if (c == ctrl('G') || c == ctrl('C')) {
         1752  +        /* ctrl-g terminates the search with no effect */
         1753  +        set_current(current, "");
         1754  +        c = 0;
         1755  +    }
         1756  +    else if (c == ctrl('J')) {
         1757  +        /* ctrl-j terminates the search leaving the buffer in place */
         1758  +        c = 0;
         1759  +    }
  1173   1760   
  1174         -    freeCompletions(&lc);
  1175         -    return c; /* Return last read character */
         1761  +    /* Go process the char normally */
         1762  +    refreshLine(current);
         1763  +    return c;
  1176   1764   }
  1177   1765   
  1178         -/* Register a callback function to be called for tab-completion.
  1179         -   Returns the prior callback so that the caller may (if needed)
  1180         -   restore it when done. */
  1181         -linenoiseCompletionCallback * linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn, void *userdata) {
  1182         -    linenoiseCompletionCallback * old = completionCallback;
  1183         -    completionCallback = fn;
  1184         -    completionUserdata = userdata;
  1185         -    return old;
  1186         -}
  1187         -
  1188         -void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
  1189         -    lc->cvec = (char **)realloc(lc->cvec,sizeof(char*)*(lc->len+1));
  1190         -    lc->cvec[lc->len++] = strdup(str);
  1191         -}
  1192         -
  1193         -#endif
  1194         -
  1195   1766   static int linenoiseEdit(struct current *current) {
  1196   1767       int history_index = 0;
  1197   1768   
  1198   1769       /* The latest history entry is always our current buffer, that
  1199   1770        * initially is just an empty string. */
  1200   1771       linenoiseHistoryAdd("");
  1201   1772   
  1202   1773       set_current(current, "");
  1203         -    refreshLine(current->prompt, current);
         1774  +    refreshLine(current);
  1204   1775   
  1205   1776       while(1) {
  1206   1777           int dir = -1;
  1207   1778           int c = fd_read(current);
  1208   1779   
  1209   1780   #ifndef NO_COMPLETION
  1210   1781           /* Only autocomplete when the callback is set. It returns < 0 when
  1211   1782            * there was an error reading from fd. Otherwise it will return the
  1212   1783            * character that should be handled next. */
  1213         -        if (c == '\t' && current->pos == current->chars && completionCallback != NULL) {
         1784  +        if (c == '\t' && current->pos == sb_chars(current->buf) && completionCallback != NULL) {
  1214   1785               c = completeLine(current);
  1215         -            /* Return on errors */
  1216         -            if (c < 0) return current->len;
  1217         -            /* Read next character when 0 */
  1218         -            if (c == 0) continue;
  1219   1786           }
  1220   1787   #endif
         1788  +        if (c == ctrl('R')) {
         1789  +            /* reverse incremental search will provide an alternative keycode or 0 for none */
         1790  +            c = reverseIncrementalSearch(current);
         1791  +            /* go on to process the returned char normally */
         1792  +        }
  1221   1793   
  1222         -process_char:
  1223         -        if (c == -1) return current->len;
  1224   1794   #ifdef USE_TERMIOS
  1225         -        if (c == 27) {   /* escape sequence */
         1795  +        if (c == CHAR_ESCAPE) {   /* escape sequence */
  1226   1796               c = check_special(current->fd);
  1227   1797           }
  1228   1798   #endif
         1799  +        if (c == -1) {
         1800  +            /* Return on errors */
         1801  +            return sb_len(current->buf);
         1802  +        }
         1803  +
  1229   1804           switch(c) {
         1805  +        case SPECIAL_NONE:
         1806  +            break;
  1230   1807           case '\r':    /* enter */
  1231   1808               history_len--;
  1232   1809               free(history[history_len]);
  1233         -            return current->len;
         1810  +            current->pos = sb_chars(current->buf);
         1811  +            if (mlmode || hintsCallback) {
         1812  +                showhints = 0;
         1813  +                refreshLine(current);
         1814  +                showhints = 1;
         1815  +            }
         1816  +            return sb_len(current->buf);
  1234   1817           case ctrl('C'):     /* ctrl-c */
  1235   1818               errno = EAGAIN;
  1236   1819               return -1;
  1237   1820           case ctrl('Z'):     /* ctrl-z */
  1238   1821   #ifdef SIGTSTP
  1239   1822               /* send ourselves SIGSUSP */
  1240   1823               disableRawMode(current);
  1241   1824               raise(SIGTSTP);
  1242   1825               /* and resume */
  1243   1826               enableRawMode(current);
  1244         -            refreshLine(current->prompt, current);
         1827  +            refreshLine(current);
  1245   1828   #endif
  1246   1829               continue;
  1247         -        case 127:   /* backspace */
         1830  +        case CHAR_DELETE:   /* backspace */
  1248   1831           case ctrl('H'):
  1249   1832               if (remove_char(current, current->pos - 1) == 1) {
  1250         -                refreshLine(current->prompt, current);
         1833  +                refreshLine(current);
  1251   1834               }
  1252   1835               break;
  1253   1836           case ctrl('D'):     /* ctrl-d */
  1254         -            if (current->len == 0) {
         1837  +            if (sb_len(current->buf) == 0) {
  1255   1838                   /* Empty line, so EOF */
  1256   1839                   history_len--;
  1257   1840                   free(history[history_len]);
  1258   1841                   return -1;
  1259   1842               }
  1260   1843               /* Otherwise fall through to delete char to right of cursor */
  1261   1844           case SPECIAL_DELETE:
  1262   1845               if (remove_char(current, current->pos) == 1) {
  1263         -                refreshLine(current->prompt, current);
         1846  +                refreshLine(current);
  1264   1847               }
  1265   1848               break;
  1266   1849           case SPECIAL_INSERT:
  1267   1850               /* Ignore. Expansion Hook.
  1268   1851                * Future possibility: Toggle Insert/Overwrite Modes
  1269   1852                */
  1270   1853               break;
................................................................................
  1278   1861   
  1279   1862                   /* now eat any non-spaces on the left */
  1280   1863                   while (pos > 0 && get_char(current, pos - 1) != ' ') {
  1281   1864                       pos--;
  1282   1865                   }
  1283   1866   
  1284   1867                   if (remove_chars(current, pos, current->pos - pos)) {
  1285         -                    refreshLine(current->prompt, current);
         1868  +                    refreshLine(current);
  1286   1869                   }
  1287   1870               }
  1288         -            break;
  1289         -        case ctrl('R'):    /* ctrl-r */
  1290         -            {
  1291         -                /* Display the reverse-i-search prompt and process chars */
  1292         -                char rbuf[50];
  1293         -                char rprompt[80];
  1294         -                int rchars = 0;
  1295         -                int rlen = 0;
  1296         -                int searchpos = history_len - 1;
  1297         -
  1298         -                rbuf[0] = 0;
  1299         -                while (1) {
  1300         -                    int n = 0;
  1301         -                    const char *p = NULL;
  1302         -                    int skipsame = 0;
  1303         -                    int searchdir = -1;
  1304         -
  1305         -                    snprintf(rprompt, sizeof(rprompt), "(reverse-i-search)'%s': ", rbuf);
  1306         -                    refreshLine(rprompt, current);
  1307         -                    c = fd_read(current);
  1308         -                    if (c == ctrl('H') || c == 127) {
  1309         -                        if (rchars) {
  1310         -                            int p = utf8_index(rbuf, --rchars);
  1311         -                            rbuf[p] = 0;
  1312         -                            rlen = strlen(rbuf);
  1313         -                        }
  1314         -                        continue;
  1315         -                    }
  1316         -#ifdef USE_TERMIOS
  1317         -                    if (c == 27) {
  1318         -                        c = check_special(current->fd);
  1319         -                    }
  1320         -#endif
  1321         -                    if (c == ctrl('P') || c == SPECIAL_UP) {
  1322         -                        /* Search for the previous (earlier) match */
  1323         -                        if (searchpos > 0) {
  1324         -                            searchpos--;
  1325         -                        }
  1326         -                        skipsame = 1;
  1327         -                    }
  1328         -                    else if (c == ctrl('N') || c == SPECIAL_DOWN) {
  1329         -                        /* Search for the next (later) match */
  1330         -                        if (searchpos < history_len) {
  1331         -                            searchpos++;
  1332         -                        }
  1333         -                        searchdir = 1;
  1334         -                        skipsame = 1;
  1335         -                    }
  1336         -                    else if (c >= ' ') {
  1337         -                        /* >= here to allow for null terminator */
  1338         -                        if (rlen >= (int)sizeof(rbuf) - MAX_UTF8_LEN) {
  1339         -                            continue;
  1340         -                        }
  1341         -
  1342         -                        n = utf8_getchars(rbuf + rlen, c);
  1343         -                        rlen += n;
  1344         -                        rchars++;
  1345         -                        rbuf[rlen] = 0;
  1346         -
  1347         -                        /* Adding a new char resets the search location */
  1348         -                        searchpos = history_len - 1;
  1349         -                    }
  1350         -                    else {
  1351         -                        /* Exit from incremental search mode */
  1352         -                        break;
  1353         -                    }
  1354         -
  1355         -                    /* Now search through the history for a match */
  1356         -                    for (; searchpos >= 0 && searchpos < history_len; searchpos += searchdir) {
  1357         -                        p = strstr(history[searchpos], rbuf);
  1358         -                        if (p) {
  1359         -                            /* Found a match */
  1360         -                            if (skipsame && strcmp(history[searchpos], current->buf) == 0) {
  1361         -                                /* But it is identical, so skip it */
  1362         -                                continue;
  1363         -                            }
  1364         -                            /* Copy the matching line and set the cursor position */
  1365         -                            set_current(current,history[searchpos]);
  1366         -                            current->pos = utf8_strlen(history[searchpos], p - history[searchpos]);
  1367         -                            break;
  1368         -                        }
  1369         -                    }
  1370         -                    if (!p && n) {
  1371         -                        /* No match, so don't add it */
  1372         -                        rchars--;
  1373         -                        rlen -= n;
  1374         -                        rbuf[rlen] = 0;
  1375         -                    }
  1376         -                }
  1377         -                if (c == ctrl('G') || c == ctrl('C')) {
  1378         -                    /* ctrl-g terminates the search with no effect */
  1379         -                    set_current(current, "");
  1380         -                    c = 0;
  1381         -                }
  1382         -                else if (c == ctrl('J')) {
  1383         -                    /* ctrl-j terminates the search leaving the buffer in place */
  1384         -                    c = 0;
  1385         -                }
  1386         -                /* Go process the char normally */
  1387         -                refreshLine(current->prompt, current);
  1388         -                goto process_char;
  1389         -            }
  1390   1871               break;
  1391   1872           case ctrl('T'):    /* ctrl-t */
  1392         -            if (current->pos > 0 && current->pos <= current->chars) {
         1873  +            if (current->pos > 0 && current->pos <= sb_chars(current->buf)) {
  1393   1874                   /* If cursor is at end, transpose the previous two chars */
  1394         -                int fixer = (current->pos == current->chars);
         1875  +                int fixer = (current->pos == sb_chars(current->buf));
  1395   1876                   c = get_char(current, current->pos - fixer);
  1396   1877                   remove_char(current, current->pos - fixer);
  1397   1878                   insert_char(current, current->pos - 1, c);
  1398         -                refreshLine(current->prompt, current);
         1879  +                refreshLine(current);
  1399   1880               }
  1400   1881               break;
  1401   1882           case ctrl('V'):    /* ctrl-v */
  1402         -            if (has_room(current, MAX_UTF8_LEN)) {
  1403         -                /* Insert the ^V first */
  1404         -                if (insert_char(current, current->pos, c)) {
  1405         -                    refreshLine(current->prompt, current);
  1406         -                    /* Now wait for the next char. Can insert anything except \0 */
  1407         -                    c = fd_read(current);
         1883  +            /* Insert the ^V first */
         1884  +            if (insert_char(current, current->pos, c)) {
         1885  +                refreshLine(current);
         1886  +                /* Now wait for the next char. Can insert anything except \0 */
         1887  +                c = fd_read(current);
  1408   1888   
  1409         -                    /* Remove the ^V first */
  1410         -                    remove_char(current, current->pos - 1);
  1411         -                    if (c != -1) {
  1412         -                        /* Insert the actual char */
  1413         -                        insert_char(current, current->pos, c);
  1414         -                    }
  1415         -                    refreshLine(current->prompt, current);
         1889  +                /* Remove the ^V first */
         1890  +                remove_char(current, current->pos - 1);
         1891  +                if (c > 0) {
         1892  +                    /* Insert the actual char, can't be error or null */
         1893  +                    insert_char(current, current->pos, c);
  1416   1894                   }
         1895  +                refreshLine(current);
  1417   1896               }
  1418   1897               break;
  1419   1898           case ctrl('B'):
  1420   1899           case SPECIAL_LEFT:
  1421   1900               if (current->pos > 0) {
  1422   1901                   current->pos--;
  1423         -                refreshLine(current->prompt, current);
         1902  +                refreshLine(current);
  1424   1903               }
  1425   1904               break;
  1426   1905           case ctrl('F'):
  1427   1906           case SPECIAL_RIGHT:
  1428         -            if (current->pos < current->chars) {
         1907  +            if (current->pos < sb_chars(current->buf)) {
  1429   1908                   current->pos++;
  1430         -                refreshLine(current->prompt, current);
         1909  +                refreshLine(current);
  1431   1910               }
  1432   1911               break;
  1433   1912           case SPECIAL_PAGE_UP:
  1434   1913             dir = history_len - history_index - 1; /* move to start of history */
  1435   1914             goto history_navigation;
  1436   1915           case SPECIAL_PAGE_DOWN:
  1437   1916             dir = -history_index; /* move to 0 == end of history, i.e. current */
................................................................................
  1443   1922           case ctrl('N'):
  1444   1923           case SPECIAL_DOWN:
  1445   1924   history_navigation:
  1446   1925               if (history_len > 1) {
  1447   1926                   /* Update the current history entry before to
  1448   1927                    * overwrite it with tne next one. */
  1449   1928                   free(history[history_len - 1 - history_index]);
  1450         -                history[history_len - 1 - history_index] = strdup(current->buf);
         1929  +                history[history_len - 1 - history_index] = strdup(sb_str(current->buf));
  1451   1930                   /* Show the new entry */
  1452   1931                   history_index += dir;
  1453   1932                   if (history_index < 0) {
  1454   1933                       history_index = 0;
  1455   1934                       break;
  1456   1935                   } else if (history_index >= history_len) {
  1457   1936                       history_index = history_len - 1;
  1458   1937                       break;
  1459   1938                   }
  1460   1939                   set_current(current, history[history_len - 1 - history_index]);
  1461         -                refreshLine(current->prompt, current);
         1940  +                refreshLine(current);
  1462   1941               }
  1463   1942               break;
  1464   1943           case ctrl('A'): /* Ctrl+a, go to the start of the line */
  1465   1944           case SPECIAL_HOME:
  1466   1945               current->pos = 0;
  1467         -            refreshLine(current->prompt, current);
         1946  +            refreshLine(current);
  1468   1947               break;
  1469   1948           case ctrl('E'): /* ctrl+e, go to the end of the line */
  1470   1949           case SPECIAL_END:
  1471         -            current->pos = current->chars;
  1472         -            refreshLine(current->prompt, current);
         1950  +            current->pos = sb_chars(current->buf);
         1951  +            refreshLine(current);
  1473   1952               break;
  1474   1953           case ctrl('U'): /* Ctrl+u, delete to beginning of line, save deleted chars. */
  1475   1954               if (remove_chars(current, 0, current->pos)) {
  1476         -                refreshLine(current->prompt, current);
         1955  +                refreshLine(current);
  1477   1956               }
  1478   1957               break;
  1479   1958           case ctrl('K'): /* Ctrl+k, delete from current to end of line, save deleted chars. */
  1480         -            if (remove_chars(current, current->pos, current->chars - current->pos)) {
  1481         -                refreshLine(current->prompt, current);
         1959  +            if (remove_chars(current, current->pos, sb_chars(current->buf) - current->pos)) {
         1960  +                refreshLine(current);
  1482   1961               }
  1483   1962               break;
  1484   1963           case ctrl('Y'): /* Ctrl+y, insert saved chars at current position */
  1485         -            if (current->capture && insert_chars(current, current->pos, current->capture)) {
  1486         -                refreshLine(current->prompt, current);
         1964  +            if (current->capture && insert_chars(current, current->pos, sb_str(current->capture))) {
         1965  +                refreshLine(current);
  1487   1966               }
  1488   1967               break;
  1489   1968           case ctrl('L'): /* Ctrl+L, clear screen */
  1490   1969               linenoiseClearScreen();
  1491   1970               /* Force recalc of window size for serial terminals */
  1492   1971               current->cols = 0;
  1493         -            refreshLine(current->prompt, current);
         1972  +            current->rpos = 0;
         1973  +            refreshLine(current);
  1494   1974               break;
  1495   1975           default:
  1496   1976               /* Only tab is allowed without ^V */
  1497   1977               if (c == '\t' || c >= ' ') {
  1498   1978                   if (insert_char(current, current->pos, c) == 1) {
  1499         -                    refreshLine(current->prompt, current);
         1979  +                    refreshLine(current);
  1500   1980                   }
  1501   1981               }
  1502   1982               break;
  1503   1983           }
  1504   1984       }
  1505         -    return current->len;
         1985  +    return sb_len(current->buf);
  1506   1986   }
  1507   1987   
  1508   1988   int linenoiseColumns(void)
  1509   1989   {
  1510   1990       struct current current;
  1511   1991       enableRawMode (&current);
  1512   1992       getWindowSize (&current);
  1513   1993       disableRawMode (&current);
  1514   1994       return current.cols;
  1515   1995   }
         1996  +
         1997  +/**
         1998  + * Reads a line from the file handle (without the trailing NL or CRNL)
         1999  + * and returns it in a stringbuf.
         2000  + * Returns NULL if no characters are read before EOF or error.
         2001  + *
         2002  + * Note that the character count will *not* be correct for lines containing
         2003  + * utf8 sequences. Do not rely on the character count.
         2004  + */
         2005  +static stringbuf *sb_getline(FILE *fh)
         2006  +{
         2007  +    stringbuf *sb = sb_alloc();
         2008  +    int c;
         2009  +    int n = 0;
         2010  +
         2011  +    while ((c = getc(fh)) != EOF) {
         2012  +        char ch;
         2013  +        n++;
         2014  +        if (c == '\r') {
         2015  +            /* CRLF -> LF */
         2016  +            continue;
         2017  +        }
         2018  +        if (c == '\n' || c == '\r') {
         2019  +            break;
         2020  +        }
         2021  +        ch = c;
         2022  +        /* ignore the effect of character count for partial utf8 sequences */
         2023  +        sb_append_len(sb, &ch, 1);
         2024  +    }
         2025  +    if (n == 0) {
         2026  +        sb_free(sb);
         2027  +        return NULL;
         2028  +    }
         2029  +    return sb;
         2030  +}
  1516   2031   
  1517   2032   char *linenoise(const char *prompt)
  1518   2033   {
  1519   2034       int count;
  1520   2035       struct current current;
  1521         -    char buf[LINENOISE_MAX_LINE];
         2036  +    stringbuf *sb;
         2037  +
         2038  +    memset(&current, 0, sizeof(current));
  1522   2039   
  1523   2040       if (enableRawMode(&current) == -1) {
  1524   2041           printf("%s", prompt);
  1525   2042           fflush(stdout);
  1526         -        if (fgets(buf, sizeof(buf), stdin) == NULL) {
  1527         -            return NULL;
  1528         -        }
  1529         -        count = strlen(buf);
  1530         -        if (count && buf[count-1] == '\n') {
  1531         -            count--;
  1532         -            buf[count] = '\0';
  1533         -        }
         2043  +        sb = sb_getline(stdin);
  1534   2044       }
  1535         -    else
  1536         -    {
  1537         -        current.buf = buf;
  1538         -        current.bufmax = sizeof(buf);
  1539         -        current.len = 0;
  1540         -        current.chars = 0;
         2045  +    else {
         2046  +        current.buf = sb_alloc();
  1541   2047           current.pos = 0;
         2048  +        current.nrows = 1;
  1542   2049           current.prompt = prompt;
  1543         -        current.capture = NULL;
  1544   2050   
  1545   2051           count = linenoiseEdit(&current);
  1546   2052   
  1547   2053           disableRawMode(&current);
  1548   2054           printf("\n");
  1549   2055   
  1550         -        free(current.capture);
         2056  +        sb_free(current.capture);
  1551   2057           if (count == -1) {
         2058  +            sb_free(current.buf);
  1552   2059               return NULL;
  1553   2060           }
         2061  +        sb = current.buf;
  1554   2062       }
  1555         -    return strdup(buf);
         2063  +    return sb ? sb_to_string(sb) : NULL;
  1556   2064   }
  1557   2065   
  1558   2066   /* Using a circular buffer is smarter, but a bit more complex to handle. */
  1559         -int linenoiseHistoryAdd(const char *line) {
  1560         -    char *linecopy;
         2067  +int linenoiseHistoryAddAllocated(char *line) {
  1561   2068   
  1562         -    if (history_max_len == 0) return 0;
         2069  +    if (history_max_len == 0) {
         2070  +notinserted:
         2071  +        free(line);
         2072  +        return 0;
         2073  +    }
  1563   2074       if (history == NULL) {
  1564         -        history = (char **)malloc(sizeof(char*)*history_max_len);
  1565         -        if (history == NULL) return 0;
  1566         -        memset(history,0,(sizeof(char*)*history_max_len));
         2075  +        history = (char **)calloc(sizeof(char*), history_max_len);
  1567   2076       }
  1568   2077   
  1569   2078       /* do not insert duplicate lines into history */
  1570   2079       if (history_len > 0 && strcmp(line, history[history_len - 1]) == 0) {
  1571         -        return 0;
         2080  +        goto notinserted;
  1572   2081       }
  1573   2082   
  1574         -    linecopy = strdup(line);
  1575         -    if (!linecopy) return 0;
  1576   2083       if (history_len == history_max_len) {
  1577   2084           free(history[0]);
  1578   2085           memmove(history,history+1,sizeof(char*)*(history_max_len-1));
  1579   2086           history_len--;
  1580   2087       }
  1581         -    history[history_len] = linecopy;
         2088  +    history[history_len] = line;
  1582   2089       history_len++;
  1583   2090       return 1;
  1584   2091   }
         2092  +
         2093  +int linenoiseHistoryAdd(const char *line) {
         2094  +    return linenoiseHistoryAddAllocated(strdup(line));
         2095  +}
  1585   2096   
  1586   2097   int linenoiseHistoryGetMaxLen(void) {
  1587   2098       return history_max_len;
  1588   2099   }
  1589   2100   
  1590   2101   int linenoiseHistorySetMaxLen(int len) {
  1591   2102       char **newHistory;
  1592   2103   
  1593   2104       if (len < 1) return 0;
  1594   2105       if (history) {
  1595   2106           int tocopy = history_len;
  1596   2107   
  1597         -        newHistory = (char **)malloc(sizeof(char*)*len);
  1598         -        if (newHistory == NULL) return 0;
         2108  +        newHistory = (char **)calloc(sizeof(char*), len);
  1599   2109   
  1600   2110           /* If we can't copy everything, free the elements we'll not use. */
  1601   2111           if (len < tocopy) {
  1602   2112               int j;
  1603   2113   
  1604   2114               for (j = 0; j < tocopy-len; j++) free(history[j]);
  1605   2115               tocopy = len;
  1606   2116           }
  1607         -        memset(newHistory,0,sizeof(char*)*len);
  1608   2117           memcpy(newHistory,history+(history_len-tocopy), sizeof(char*)*tocopy);
  1609   2118           free(history);
  1610   2119           history = newHistory;
  1611   2120       }
  1612   2121       history_max_len = len;
  1613   2122       if (history_len > history_max_len)
  1614   2123           history_len = history_max_len;
................................................................................
  1643   2152           fputc('\n', fp);
  1644   2153       }
  1645   2154   
  1646   2155       fclose(fp);
  1647   2156       return 0;
  1648   2157   }
  1649   2158   
  1650         -/* Load the history from the specified file. If the file does not exist
  1651         - * zero is returned and no operation is performed.
         2159  +/* Load the history from the specified file.
  1652   2160    *
  1653         - * If the file exists and the operation succeeded 0 is returned, otherwise
  1654         - * on error -1 is returned. */
         2161  + * If the file does not exist or can't be opened, no operation is performed
         2162  + * and -1 is returned.
         2163  + * Otherwise 0 is returned.
         2164  + */
  1655   2165   int linenoiseHistoryLoad(const char *filename) {
  1656   2166       FILE *fp = fopen(filename,"r");
  1657         -    char buf[LINENOISE_MAX_LINE];
         2167  +    stringbuf *sb;
  1658   2168   
  1659   2169       if (fp == NULL) return -1;
  1660   2170   
  1661         -    while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) {
  1662         -        char *src, *dest;
         2171  +    while ((sb = sb_getline(fp)) != NULL) {
         2172  +        /* Take the stringbuf and decode backslash escaped values */
         2173  +        char *buf = sb_to_string(sb);
         2174  +        char *dest = buf;
         2175  +        const char *src;
  1663   2176   
  1664         -        /* Decode backslash escaped values */
  1665         -        for (src = dest = buf; *src; src++) {
         2177  +        for (src = buf; *src; src++) {
  1666   2178               char ch = *src;
  1667   2179   
  1668   2180               if (ch == '\\') {
  1669   2181                   src++;
  1670   2182                   if (*src == 'n') {
  1671   2183                       ch = '\n';
  1672   2184                   }
................................................................................
  1674   2186                       ch = '\r';
  1675   2187                   } else {
  1676   2188                       ch = *src;
  1677   2189                   }
  1678   2190               }
  1679   2191               *dest++ = ch;
  1680   2192           }
  1681         -        /* Remove trailing newline */
  1682         -        if (dest != buf && (dest[-1] == '\n' || dest[-1] == '\r')) {
  1683         -            dest--;
  1684         -        }
  1685   2193           *dest = 0;
  1686   2194   
  1687         -        linenoiseHistoryAdd(buf);
         2195  +        linenoiseHistoryAddAllocated(buf);
  1688   2196       }
  1689   2197       fclose(fp);
  1690   2198       return 0;
  1691   2199   }
  1692   2200   
  1693   2201   /* Provide access to the history buffer.
  1694   2202    *

Changes to linenoise.h.

    55     55   linenoiseCompletionCallback * linenoiseSetCompletionCallback(linenoiseCompletionCallback *comp, void *userdata);
    56     56   
    57     57   /*
    58     58    * Adds a copy of the given string to the given completion list. The copy is owned
    59     59    * by the linenoiseCompletions object.
    60     60    */
    61     61   void linenoiseAddCompletion(linenoiseCompletions *comp, const char *str);
           62  +
           63  +typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold, void *userdata);
           64  +typedef void(linenoiseFreeHintsCallback)(void *hint, void *userdata);
           65  +void linenoiseSetHintsCallback(linenoiseHintsCallback *callback, void *userdata);
           66  +void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *callback);
           67  +
    62     68   #endif
    63     69   
    64     70   /*
    65     71    * Prompts for input using the given string as the input
    66     72    * prompt. Returns when the user has tapped ENTER or (on an empty
    67     73    * line) EOF (Ctrl-D on Unix, Ctrl-Z on Windows). Returns either
    68     74    * a copy of the entered string (for ENTER) or NULL (on EOF).  The
................................................................................
   118    124   char **linenoiseHistory(int *len);
   119    125   
   120    126   /*
   121    127    * Returns the number of display columns in the current terminal.
   122    128    */
   123    129   int linenoiseColumns(void);
   124    130   
          131  +/**
          132  + * Enable or disable multiline mode (disabled by default)
          133  + */
          134  +void linenoiseSetMultiLine(int enableml);
          135  +
   125    136   #endif /* __LINENOISE_H */