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