summaryrefslogtreecommitdiff
path: root/third_party
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2011-04-11 18:54:09 -0400
committerMathias Stearn <mathias@10gen.com>2011-04-11 19:00:15 -0400
commit00c383f6c0551f5b1748a29d00a8a77b52d72a16 (patch)
tree97903ef920eda015f5edb5b7b6ce5f5b454d424c /third_party
parent73126163cc233828fa724d12ff0d197dcf3b41e3 (diff)
downloadmongo-00c383f6c0551f5b1748a29d00a8a77b52d72a16.tar.gz
first pass at merging posix and win32 linenoise codebases SERVER-1763
Diffstat (limited to 'third_party')
-rw-r--r--third_party/linenoise/linenoise.cpp305
1 files changed, 218 insertions, 87 deletions
diff --git a/third_party/linenoise/linenoise.cpp b/third_party/linenoise/linenoise.cpp
index b752ab95caf..70fdbaf7137 100644
--- a/third_party/linenoise/linenoise.cpp
+++ b/third_party/linenoise/linenoise.cpp
@@ -82,6 +82,26 @@
*
*/
+#ifdef _WIN32
+
+#include <conio.h>
+#include <windows.h>
+#include <stdio.h>
+#include <io.h>
+#include <errno.h>
+#define snprintf _snprintf
+#define strcasecmp _stricmp
+#define strdup _strdup
+#define isatty _isatty
+#define write _write
+#define STDIN_FILENO 0
+
+static HANDLE console_in, console_out;
+static DWORD oldMode;
+
+
+#else /* _WIN32 */
+
#include <termios.h>
#include <unistd.h>
#include <stdlib.h>
@@ -92,6 +112,10 @@
#include <sys/types.h>
#include <sys/ioctl.h>
#include <unistd.h>
+
+static struct termios orig_termios; /* in order to restore at exit */
+#endif /* _WIN32 */
+
#include "linenoise.h"
#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
@@ -99,7 +123,6 @@
static const char *unsupported_term[] = {"dumb","cons25",NULL};
static linenoiseCompletionCallback *completionCallback = NULL;
-static struct termios orig_termios; /* in order to restore at exit */
static int rawmode = 0; /* for atexit() function to check if restore is needed*/
static int atexit_registered = 0; /* register atexit just 1 time */
static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
@@ -130,6 +153,16 @@ static void freeHistory(void) {
}
static int enableRawMode(int fd) {
+#ifdef _WIN32
+ if (!console_in) {
+ console_in = GetStdHandle(STD_INPUT_HANDLE);
+ console_out = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ GetConsoleMode(console_in, &oldMode);
+ SetConsoleMode(console_in, oldMode & ~(ENABLE_LINE_INPUT | ENABLE_LINE_INPUT));
+ }
+ return 0;
+#else
struct termios raw;
if (!isatty(STDIN_FILENO)) goto fatal;
@@ -162,12 +195,19 @@ static int enableRawMode(int fd) {
fatal:
errno = ENOTTY;
return -1;
+#endif
}
static void disableRawMode(int fd) {
+#ifdef _WIN32
+ SetConsoleMode(console_in, oldMode);
+ console_in = 0;
+ console_out = 0;
+#else
/* Don't even check the return value as it's too late. */
if (rawmode && tcsetattr(fd,TCSAFLUSH,&orig_termios) != -1)
rawmode = 0;
+#endif
}
/* At exit we'll try to fix the terminal to the initial conditions. */
@@ -177,14 +217,28 @@ static void linenoiseAtExit(void) {
}
static int getColumns(void) {
+#ifdef _WIN32
+ CONSOLE_SCREEN_BUFFER_INFO inf = { 0 };
+ GetConsoleScreenBufferInfo(console_out, &inf);
+ return inf.dwSize.X;
+#else
struct winsize ws;
if (ioctl(1, TIOCGWINSZ, &ws) == -1) return 80;
return ws.ws_col;
+#endif
+}
+
+#ifdef _WIN32
+static void output(const char* str, size_t len, int x, int y)
+{
+ COORD pos = { (SHORT)x, (SHORT)y };
+ DWORD count = 0;
+ WriteConsoleOutputCharacterA(console_out, str, len, pos, &count);
}
+#endif
static void refreshLine(int fd, const char *prompt, char *buf, size_t len, size_t pos, size_t cols) {
- char seq[64];
size_t plen = strlen(prompt);
while((plen+pos) >= cols) {
@@ -196,21 +250,109 @@ static void refreshLine(int fd, const char *prompt, char *buf, size_t len, size_
len--;
}
- /* Cursor to left edge */
- snprintf(seq,64,"\x1b[0G");
- if (write(fd,seq,strlen(seq)) == -1) return;
- /* Write the prompt and the current buffer content */
- if (write(fd,prompt,strlen(prompt)) == -1) return;
- if (write(fd,buf,len) == -1) return;
- /* Erase to right */
- snprintf(seq,64,"\x1b[0K");
- if (write(fd,seq,strlen(seq)) == -1) return;
- /* Move cursor to original position. */
- snprintf(seq,64,"\x1b[0G\x1b[%dC", (int)(pos+plen));
- if (write(fd,seq,strlen(seq)) == -1) return;
+#ifdef _WIN32
+ CONSOLE_SCREEN_BUFFER_INFO inf = { 0 };
+ GetConsoleScreenBufferInfo(console_out, &inf);
+ output(prompt, plen, 0, inf.dwCursorPosition.Y);
+ output(buf, len, plen, inf.dwCursorPosition.Y);
+ if (plen + len < (size_t)inf.dwSize.X) {
+ /* Blank to EOL */
+ char* tmp = (char*)malloc(inf.dwSize.X - (plen + len));
+ memset(tmp, ' ', inf.dwSize.X - (plen + len));
+ output(tmp, inf.dwSize.X - (plen + len), len + plen, inf.dwCursorPosition.Y);
+ free(tmp);
+ }
+ inf.dwCursorPosition.X = (SHORT)(pos + plen);
+ SetConsoleCursorPosition(console_out, inf.dwCursorPosition);
+#else
+ {
+ char seq[64];
+ /* Cursor to left edge */
+ snprintf(seq,64,"\x1b[0G");
+ if (write(fd,seq,strlen(seq)) == -1) return;
+ /* Write the prompt and the current buffer content */
+ if (write(fd,prompt,strlen(prompt)) == -1) return;
+ if (write(fd,buf,len) == -1) return;
+ /* Erase to right */
+ snprintf(seq,64,"\x1b[0K");
+ if (write(fd,seq,strlen(seq)) == -1) return;
+ /* Move cursor to original position. */
+ snprintf(seq,64,"\x1b[0G\x1b[%dC", (int)(pos+plen));
+ if (write(fd,seq,strlen(seq)) == -1) return;
+ }
+#endif
+}
+
+/* Note that this should parse some special keys into their emacs ctrl-key combos
+ * Return of -1 signifies unrecognized code
+ */
+static char linenoiseReadChar(int fd){
+#ifdef _WIN32
+ INPUT_RECORD rec;
+ DWORD count;
+ do {
+ ReadConsoleInputA(console_in, &rec, 1, &count);
+ } while (rec.EventType != KEY_EVENT || !rec.Event.KeyEvent.bKeyDown);
+
+ if (rec.Event.KeyEvent.uChar.AsciiChar == 0) {
+ /* handle keys that aren't converted to ASCII */
+ switch (rec.Event.KeyEvent.wVirtualKeyCode) {
+ case VK_LEFT: return 2; /* ctrl-b */
+ case VK_RIGHT: return 6; /* ctrl-f */
+ case VK_UP: return 16; /* ctrl-p */
+ case VK_DOWN: return 14; /* ctrl-n */
+ case VK_DELETE: return 127; /* ascii DEL byte */
+ case VK_HOME: return 1; /* ctrl-a */
+ case VK_END: return 5; /* ctrl-e */
+ default: return -1;
+ }
+ }
+ return rec.Event.KeyEvent.uChar.AsciiChar;
+#else
+ char c;
+ int nread;
+ char seq[2], seq2[2];
+
+ nread = read(fd,&c,1);
+ if (nread <= 0) return 0;
+
+ if (c == 27) { /* escape */
+ if (read(fd,seq,2) == -1) return 0;
+ if (seq[0] == 91){
+ if (seq[1] == 68) { /* left arrow */
+ return 2; /* ctrl-b */
+ } else if (seq[1] == 67) { /* right arrow */
+ return 6; /* ctrl-f */
+ } else if (seq[1] == 65) { /* up arrow */
+ return 16; /* ctrl-p */
+ } else if (seq[1] == 66) { /* up arrow */
+ return 14; /* ctrl-n */
+ } else if (seq[1] > 48 && seq[1] < 55) {
+ /* extended escape */
+ if (read(fd,seq2,2) == -1) return 0;
+ if (seq[1] == 51 && seq2[0] == 126) { /* delete */
+ return 127; /* ascii DEL byte */
+ } else {
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+ } else if (c == 127) {
+ /* some consoles use 127 for backspace rather than delete.
+ * we only use it for delete */
+ return 8;
+ }
+
+ return c; /* normalish character */
+#endif
}
static void beep() {
+ /* doesn't do anything on windows but harmless */
fprintf(stderr, "\x7");
fflush(stderr);
}
@@ -225,7 +367,7 @@ static void freeCompletions(linenoiseCompletions *lc) {
static int completeLine(int fd, const char *prompt, char *buf, size_t buflen, size_t *len, size_t *pos, size_t cols) {
linenoiseCompletions lc = { 0, NULL };
- int nread, nwritten;
+ int nwritten;
char c = 0;
completionCallback(buf,&lc);
@@ -244,13 +386,12 @@ static int completeLine(int fd, const char *prompt, char *buf, size_t buflen, si
refreshLine(fd,prompt,buf,*len,*pos,cols);
}
- nread = read(fd,&c,1);
- if (nread <= 0) {
- freeCompletions(&lc);
- return -1;
- }
+ c = linenoiseReadChar(fd);
switch(c) {
+ case 0:
+ freeCompletions(&lc);
+ return -1;
case 9: /* tab */
i = (i+1) % (lc.len+1);
if (i == lc.len) beep();
@@ -279,9 +420,21 @@ static int completeLine(int fd, const char *prompt, char *buf, size_t buflen, si
}
void linenoiseClearScreen(void) {
- if (write(STDIN_FILENO,"\x1b[H\x1b[2J",7) <= 0) {
+#ifdef _WIN32
+ COORD coord = {0, 0};
+ CONSOLE_SCREEN_BUFFER_INFO inf;
+ DWORD count;
+ DWORD size;
+
+ GetConsoleScreenBufferInfo(console_out, &inf);
+ size = inf.dwSize.X * inf.dwSize.Y;
+ FillConsoleOutputCharacterA(console_out, ' ', size, coord, &count );
+ SetConsoleCursorPosition(console_out, coord);
+#else
+ if (write(1,"\x1b[H\x1b[2J",7) <= 0) {
/* nothing to do, just to avoid warning. */
}
+#endif
}
static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt) {
@@ -298,14 +451,12 @@ static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt)
* initially is just an empty string. */
linenoiseHistoryAdd("");
- if (write(fd,prompt,plen) == -1) return -1;
+ if (write(1,prompt,plen) == -1) return -1;
while(1) {
- char c;
- int nread;
- char seq[2], seq2[2];
+ char c = linenoiseReadChar(fd);
- nread = read(fd,&c,1);
- if (nread <= 0) return len;
+ if (c == 0) return len;
+ if (c == (char)-1) continue;
/* Only autocomplete when the callback is set. It returns < 0 when
* there was an error reading from fd. Otherwise it will return the
@@ -326,8 +477,13 @@ static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt)
case 3: /* ctrl-c */
errno = EAGAIN;
return -1;
- case 127: /* backspace */
- case 8: /* ctrl-h */
+ case 127: /* delete */
+ memmove(buf+pos,buf+pos+1,len-pos-1);
+ len--;
+ buf[len] = '\0';
+ refreshLine(fd,prompt,buf,len,pos,cols);
+ break;
+ case 8: /* backspace or ctrl-h */
if (pos > 0 && len > 0) {
memmove(buf+pos-1,buf+pos,len-pos);
pos--;
@@ -357,69 +513,44 @@ static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt)
refreshLine(fd,prompt,buf,len,pos,cols);
}
break;
- case 2: /* ctrl-b */
- goto left_arrow;
+ case 2: /* ctrl-b */ /* left arrow */
+ if (pos > 0) {
+ pos--;
+ refreshLine(fd,prompt,buf,len,pos,cols);
+ }
+ break;
case 6: /* ctrl-f */
- goto right_arrow;
+ /* right arrow */
+ if (pos != len) {
+ pos++;
+ refreshLine(fd,prompt,buf,len,pos,cols);
+ }
+ break;
case 16: /* ctrl-p */
- seq[1] = 65;
- goto up_down_arrow;
case 14: /* ctrl-n */
- seq[1] = 66;
- goto up_down_arrow;
- break;
- case 27: /* escape sequence */
- if (read(fd,seq,2) == -1) break;
- if (seq[0] == 91 && seq[1] == 68) {
-left_arrow:
- /* left arrow */
- if (pos > 0) {
- pos--;
- refreshLine(fd,prompt,buf,len,pos,cols);
- }
- } else if (seq[0] == 91 && seq[1] == 67) {
-right_arrow:
- /* right arrow */
- if (pos != len) {
- pos++;
- refreshLine(fd,prompt,buf,len,pos,cols);
- }
- } else if (seq[0] == 91 && (seq[1] == 65 || seq[1] == 66)) {
-up_down_arrow:
- /* up and down arrow: history */
- if (history_len > 1) {
- /* Update the current history entry before to
- * overwrite it with tne next one. */
- free(history[history_len-1-history_index]);
- history[history_len-1-history_index] = strdup(buf);
- /* Show the new entry */
- history_index += (seq[1] == 65) ? 1 : -1;
- if (history_index < 0) {
- history_index = 0;
- break;
- } else if (history_index >= history_len) {
- history_index = history_len-1;
- break;
- }
- strncpy(buf,history[history_len-1-history_index],buflen);
- buf[buflen] = '\0';
- len = pos = strlen(buf);
- refreshLine(fd,prompt,buf,len,pos,cols);
- }
- } else if (seq[0] == 91 && seq[1] > 48 && seq[1] < 55) {
- /* extended escape */
- if (read(fd,seq2,2) == -1) break;
- if (seq[1] == 51 && seq2[0] == 126) {
- /* delete */
- if (len > 0 && pos < len) {
- memmove(buf+pos,buf+pos+1,len-pos-1);
- len--;
- buf[len] = '\0';
- refreshLine(fd,prompt,buf,len,pos,cols);
- }
+ /* up and down arrow: history */
+ if (history_len > 1) {
+ /* Update the current history entry before to
+ * overwrite it with tne next one. */
+ free(history[history_len-1-history_index]);
+ history[history_len-1-history_index] = strdup(buf);
+ /* Show the new entry */
+ history_index += (c == 16) ? 1 : -1;
+ if (history_index < 0) {
+ history_index = 0;
+ break;
+ } else if (history_index >= history_len) {
+ history_index = history_len-1;
+ break;
}
+ strncpy(buf,history[history_len-1-history_index],buflen);
+ buf[buflen] = '\0';
+ len = pos = strlen(buf);
+ refreshLine(fd,prompt,buf,len,pos,cols);
}
break;
+ case 27: /* escape sequence */
+ break; /* should be handled by linenoiseReadChar */
default:
if (len < buflen) {
if (len == pos) {
@@ -430,7 +561,7 @@ up_down_arrow:
if (plen+len < cols) {
/* Avoid a full update of the line in the
* trivial case. */
- if (write(fd,&c,1) == -1) return -1;
+ if (write(1,&c,1) == -1) return -1;
} else {
refreshLine(fd,prompt,buf,len,pos,cols);
}