Port linenoise to Fuchsia
Made the minimum amount of modifications to support running on Fuchsia.
Change-Id: Ie2ac32d4e314be78f274c45b549c8a359547a150
diff --git a/BUILD.gn b/BUILD.gn
new file mode 100644
index 0000000..d6e7906
--- /dev/null
+++ b/BUILD.gn
@@ -0,0 +1,41 @@
+# Copyright 2016 The Fuchsia Authors
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+static_library("linenoise") {
+ sources = [
+ "linenoise.c",
+ "linenoise.h",
+ ]
+}
+
+executable("linenoise_example") {
+ sources = [
+ "example.c"
+ ]
+
+ deps = [ ":linenoise" ]
+}
diff --git a/example.c b/example.c
index 3a544d3..6d91b03 100644
--- a/example.c
+++ b/example.c
@@ -3,6 +3,7 @@
#include <string.h>
#include "linenoise.h"
+const char kHistoryFilePath[] = "/tmp/linenoise-example-history.txt";
void completion(const char *buf, linenoiseCompletions *lc) {
if (buf[0] == 'h') {
@@ -47,7 +48,7 @@
/* Load history from file. The history file is just a plain text file
* where entries are separated by newlines. */
- linenoiseHistoryLoad("history.txt"); /* Load the history at startup */
+ linenoiseHistoryLoad(kHistoryFilePath);
/* Now this is the main loop of the typical linenoise-based application.
* The call to linenoise() will block as long as the user types something
@@ -60,7 +61,7 @@
if (line[0] != '\0' && line[0] != '/') {
printf("echo: '%s'\n", line);
linenoiseHistoryAdd(line); /* Add to the history. */
- linenoiseHistorySave("history.txt"); /* Save the history on disk. */
+ linenoiseHistorySave(kHistoryFilePath); /* Save the history on disk. */
} else if (!strncmp(line,"/historylen",11)) {
/* The "/historylen" command will change the history len. */
int len = atoi(line+11);
diff --git a/linenoise.c b/linenoise.c
index fce14a7..7eb39a1 100644
--- a/linenoise.c
+++ b/linenoise.c
@@ -115,10 +115,48 @@
#include <sys/types.h>
#include <sys/ioctl.h>
#include <unistd.h>
+
+#ifdef __Fuchsia__
+#include <mxio/io.h>
+#include <ddk/protocol/console.h>
+#endif
+
#include "linenoise.h"
#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
#define LINENOISE_MAX_LINE 4096
+
+/* Pass-through version that just calls into the platform's read
+ * implementation.
+ */
+static int readNative(int fd, void* buf, size_t len) {
+ return read(fd, buf, len);
+}
+
+#ifdef __Fuchsia__
+
+/* On Fuchsia the native read implementation doesn't block yet. We provide a
+ * version here that both blocks AND does not return until at least some
+ * characters have been read from the fd.
+ */
+static int __read(int fd, void* buf, size_t len) {
+ int nread;
+
+ if (len == 0) return 0;
+
+ for (;;) {
+ mxio_wait_fd(0, MXIO_EVT_READABLE, NULL, MX_TIME_INFINITE);
+ if ((nread = read(0, buf, len)))
+ return nread;
+ }
+
+ return nread;
+}
+
+#define read __read
+
+#endif
+
static char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
static linenoiseCompletionCallback *completionCallback = NULL;
static linenoiseHintsCallback *hintsCallback = NULL;
@@ -127,11 +165,14 @@
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 mlmode = 0; /* Multi line mode. Default is single line. */
-static int atexit_registered = 0; /* Register atexit just 1 time. */
static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
static int history_len = 0;
static char **history = NULL;
+#ifndef __Fuchsia__
+static int atexit_registered = 0; /* Register atexit just 1 time. */
+#endif
+
/* The linenoiseState structure represents the state during line editing.
* We pass this state to functions implementing specific editing
* functionalities. */
@@ -160,6 +201,9 @@
CTRL_F = 6, /* Ctrl-f */
CTRL_H = 8, /* Ctrl-h */
TAB = 9, /* Tab */
+#ifdef __Fuchsia__
+ NEWLINE = 10, /* Newline */
+#endif
CTRL_K = 11, /* Ctrl+k */
CTRL_L = 12, /* Ctrl+l */
ENTER = 13, /* Enter */
@@ -172,7 +216,10 @@
BACKSPACE = 127 /* Backspace */
};
+#ifndef __Fuchsia__
static void linenoiseAtExit(void);
+#endif
+
int linenoiseHistoryAdd(const char *line);
static void refreshLine(struct linenoiseState *l);
@@ -216,6 +263,9 @@
/* Raw mode: 1960 magic shit. */
static int enableRawMode(int fd) {
+#ifdef __Fuchsia__
+ return 0;
+#else
struct termios raw;
if (!isatty(STDIN_FILENO)) goto fatal;
@@ -248,6 +298,7 @@
fatal:
errno = ENOTTY;
return -1;
+#endif
}
static void disableRawMode(int fd) {
@@ -269,7 +320,7 @@
/* Read the response: ESC [ rows ; cols R */
while (i < sizeof(buf)-1) {
- if (read(ifd,buf+i,1) != 1) break;
+ if (readNative(ifd,buf+i,1) != 1) break;
if (buf[i] == 'R') break;
i++;
}
@@ -284,9 +335,16 @@
/* Try to get the number of columns in the current terminal, or assume 80
* if it fails. */
static int getColumns(int ifd, int ofd) {
+#ifdef __Fuchsia__
+ ioctl_console_dimensions_t dims;
+ ssize_t r = mxio_ioctl(0, CONSOLE_OP_GET_DIMENSIONS, NULL, 0, &dims,
+ sizeof(dims));
+ if (r == sizeof(dims)) {
+#else
struct winsize ws;
if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
+#endif
/* ioctl() failed. Try to query the terminal itself. */
int start, cols;
@@ -309,7 +367,11 @@
}
return cols;
} else {
+#ifdef __Fuchsia__
+ return dims.width;
+#else
return ws.ws_col;
+#endif
}
failed:
@@ -812,6 +874,13 @@
}
switch(c) {
+#ifdef __Fuchsia__
+ /* We don't have support for termios in Fuchsia so "enableRawMode()"
+ * above is explicitly a no-op. This means that we have to process
+ * newline directly.
+ */
+ case NEWLINE: /* new line */
+#endif
case ENTER: /* enter */
history_len--;
free(history[history_len]);
@@ -1072,6 +1141,8 @@
/* ================================ History ================================= */
+#ifndef __Fuchsia__
+
/* Free the history, but does not reset it. Only used when we have to
* exit() to avoid memory leaks are reported by valgrind & co. */
static void freeHistory(void) {
@@ -1090,6 +1161,8 @@
freeHistory();
}
+#endif
+
/* This is the API call to add a new entry in the linenoise history.
* It uses a fixed array of char pointers that are shifted (memmoved)
* when the history max length is reached in order to remove the older