qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/5] qemu-io: readline command completion
@ 2013-11-14 10:54 Stefan Hajnoczi
  2013-11-14 10:54 ` [Qemu-devel] [PATCH 1/5] readline: decouple readline from the monitor Stefan Hajnoczi
                   ` (5 more replies)
  0 siblings, 6 replies; 10+ messages in thread
From: Stefan Hajnoczi @ 2013-11-14 10:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Stefan Hajnoczi, Luiz Capitulino

This series decouples readline.c from the QEMU monitor and then reuses it in
qemu-io.  This adds history and command completion to the qemu-io interactive
prompt.

Stefan Hajnoczi (5):
  readline: decouple readline from the monitor
  readline: move readline to a generic location
  osdep: add qemu_set_tty_echo()
  qemu-io: use readline.c
  qemu-io: add command completion

 Makefile.objs              |   1 -
 hmp.c                      |   6 +-
 include/monitor/monitor.h  |   2 +-
 include/monitor/readline.h |  56 -----
 include/qemu-io.h          |   3 +
 include/qemu/osdep.h       |   2 +
 include/qemu/readline.h    |  62 ++++++
 monitor.c                  |  41 +++-
 qemu-io-cmds.c             |  15 ++
 qemu-io.c                  | 109 +++++-----
 readline.c                 | 493 --------------------------------------------
 util/Makefile.objs         |   1 +
 util/oslib-posix.c         |  18 ++
 util/oslib-win32.c         |  19 ++
 util/readline.c            | 495 +++++++++++++++++++++++++++++++++++++++++++++
 15 files changed, 716 insertions(+), 607 deletions(-)
 delete mode 100644 include/monitor/readline.h
 create mode 100644 include/qemu/readline.h
 delete mode 100644 readline.c
 create mode 100644 util/readline.c

-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH 1/5] readline: decouple readline from the monitor
  2013-11-14 10:54 [Qemu-devel] [PATCH 0/5] qemu-io: readline command completion Stefan Hajnoczi
@ 2013-11-14 10:54 ` Stefan Hajnoczi
  2013-11-14 10:54 ` [Qemu-devel] [PATCH 2/5] readline: move readline to a generic location Stefan Hajnoczi
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Stefan Hajnoczi @ 2013-11-14 10:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Stefan Hajnoczi, Luiz Capitulino

Make the readline.c functionality reusable.  Instead of calling
monitor_printf() and monitor_flush() directly, invoke function pointers
provided by the user.

This way readline.c does not know about Monitor and other users will be
able to make use of readline.c.

Note that there is already an "opaque" argument to the ReadLineFunc
callback.  Consistently call it "readline_opaque" from now on to
distinguish from the ReadLinePrintfFunc/ReadLineFlushFunc "opaque"
argument.

I also dropped the printf macro trickery since it's now highly unlikely
that anyone modifying readline.c would call printf(3) directly.  We no
longer need this protection.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 hmp.c                      |  6 +++---
 include/monitor/readline.h | 20 +++++++++++++-------
 monitor.c                  | 39 ++++++++++++++++++++++++++++++++-------
 readline.c                 | 44 +++++++++++++++++++++++---------------------
 4 files changed, 71 insertions(+), 38 deletions(-)

diff --git a/hmp.c b/hmp.c
index 32ee285..f941d0c 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1091,11 +1091,11 @@ void hmp_eject(Monitor *mon, const QDict *qdict)
     hmp_handle_error(mon, &err);
 }
 
-static void hmp_change_read_arg(Monitor *mon, const char *password,
-                                void *opaque)
+static void hmp_change_read_arg(void *opaque, const char *password,
+                                void *readline_opaque)
 {
     qmp_change_vnc_password(password, NULL);
-    monitor_read_command(mon, 1);
+    monitor_read_command(opaque, 1);
 }
 
 void hmp_change(Monitor *mon, const QDict *qdict)
diff --git a/include/monitor/readline.h b/include/monitor/readline.h
index 0faf6e1..a89fe4a 100644
--- a/include/monitor/readline.h
+++ b/include/monitor/readline.h
@@ -1,14 +1,15 @@
 #ifndef READLINE_H
 #define READLINE_H
 
-#include "qemu-common.h"
-
 #define READLINE_CMD_BUF_SIZE 4095
 #define READLINE_MAX_CMDS 64
 #define READLINE_MAX_COMPLETIONS 256
 
-typedef void ReadLineFunc(Monitor *mon, const char *str, void *opaque);
-typedef void ReadLineCompletionFunc(Monitor *mon,
+typedef void ReadLinePrintfFunc(void *opaque, const char *fmt, ...);
+typedef void ReadLineFlushFunc(void *opaque);
+typedef void ReadLineFunc(void *opaque, const char *str,
+                          void *readline_opaque);
+typedef void ReadLineCompletionFunc(void *opaque,
                                     const char *cmdline);
 
 typedef struct ReadLineState {
@@ -35,7 +36,10 @@ typedef struct ReadLineState {
     void *readline_opaque;
     int read_password;
     char prompt[256];
-    Monitor *mon;
+
+    ReadLinePrintfFunc *printf_func;
+    ReadLineFlushFunc *flush_func;
+    void *opaque;
 } ReadLineState;
 
 void readline_add_completion(ReadLineState *rs, const char *str);
@@ -46,11 +50,13 @@ const char *readline_get_history(ReadLineState *rs, unsigned int index);
 void readline_handle_byte(ReadLineState *rs, int ch);
 
 void readline_start(ReadLineState *rs, const char *prompt, int read_password,
-                    ReadLineFunc *readline_func, void *opaque);
+                    ReadLineFunc *readline_func, void *readline_opaque);
 void readline_restart(ReadLineState *rs);
 void readline_show_prompt(ReadLineState *rs);
 
-ReadLineState *readline_init(Monitor *mon,
+ReadLineState *readline_init(ReadLinePrintfFunc *printf_func,
+                             ReadLineFlushFunc *flush_func,
+                             void *opaque,
                              ReadLineCompletionFunc *completion_finder);
 
 #endif /* !READLINE_H */
diff --git a/monitor.c b/monitor.c
index 845f608..32d0264 100644
--- a/monitor.c
+++ b/monitor.c
@@ -217,8 +217,8 @@ static const mon_cmd_t qmp_cmds[];
 Monitor *cur_mon;
 Monitor *default_mon;
 
-static void monitor_command_cb(Monitor *mon, const char *cmdline,
-                               void *opaque);
+static void monitor_command_cb(void *opaque, const char *cmdline,
+                               void *readline_opaque);
 
 static inline int qmp_cmd_mode(const Monitor *mon)
 {
@@ -4338,9 +4338,10 @@ static void monitor_find_completion_by_table(Monitor *mon,
     }
 }
 
-static void monitor_find_completion(Monitor *mon,
+static void monitor_find_completion(void *opaque,
                                     const char *cmdline)
 {
+    Monitor *mon = opaque;
     char *args[MAX_ARGS];
     int nb_args, len;
 
@@ -4751,8 +4752,11 @@ static void monitor_read(void *opaque, const uint8_t *buf, int size)
     cur_mon = old_mon;
 }
 
-static void monitor_command_cb(Monitor *mon, const char *cmdline, void *opaque)
+static void monitor_command_cb(void *opaque, const char *cmdline,
+                               void *readline_opaque)
 {
+    Monitor *mon = opaque;
+
     monitor_suspend(mon);
     handle_user_command(mon, cmdline);
     monitor_resume(mon);
@@ -4881,6 +4885,22 @@ static void sortcmdlist(void)
  * End:
  */
 
+/* These functions just adapt the readline interface in a typesafe way.  We
+ * could cast function pointers but that discards compiler checks.
+ */
+static void monitor_readline_printf(void *opaque, const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    monitor_vprintf(opaque, fmt, ap);
+    va_end(ap);
+}
+
+static void monitor_readline_flush(void *opaque)
+{
+    monitor_flush(opaque);
+}
+
 void monitor_init(CharDriverState *chr, int flags)
 {
     static int is_first_init = 1;
@@ -4898,7 +4918,10 @@ void monitor_init(CharDriverState *chr, int flags)
     mon->chr = chr;
     mon->flags = flags;
     if (flags & MONITOR_USE_READLINE) {
-        mon->rs = readline_init(mon, monitor_find_completion);
+        mon->rs = readline_init(monitor_readline_printf,
+                                monitor_readline_flush,
+                                mon,
+                                monitor_find_completion);
         monitor_read_command(mon, 0);
     }
 
@@ -4920,9 +4943,11 @@ void monitor_init(CharDriverState *chr, int flags)
         default_mon = mon;
 }
 
-static void bdrv_password_cb(Monitor *mon, const char *password, void *opaque)
+static void bdrv_password_cb(void *opaque, const char *password,
+                             void *readline_opaque)
 {
-    BlockDriverState *bs = opaque;
+    Monitor *mon = opaque;
+    BlockDriverState *bs = readline_opaque;
     int ret = 0;
 
     if (bdrv_set_key(bs, password) != 0) {
diff --git a/readline.c b/readline.c
index abf27dd..ca894d1 100644
--- a/readline.c
+++ b/readline.c
@@ -21,21 +21,19 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+
+#include "qemu-common.h"
 #include "monitor/readline.h"
-#include "monitor/monitor.h"
 
 #define IS_NORM 0
 #define IS_ESC  1
 #define IS_CSI  2
 #define IS_SS3  3
 
-#undef printf
-#define printf do_not_use_printf
-
 void readline_show_prompt(ReadLineState *rs)
 {
-    monitor_printf(rs->mon, "%s", rs->prompt);
-    monitor_flush(rs->mon);
+    rs->printf_func(rs->opaque, "%s", rs->prompt);
+    rs->flush_func(rs->opaque);
     rs->last_cmd_buf_index = 0;
     rs->last_cmd_buf_size = 0;
     rs->esc_state = IS_NORM;
@@ -49,17 +47,17 @@ static void readline_update(ReadLineState *rs)
     if (rs->cmd_buf_size != rs->last_cmd_buf_size ||
         memcmp(rs->cmd_buf, rs->last_cmd_buf, rs->cmd_buf_size) != 0) {
         for(i = 0; i < rs->last_cmd_buf_index; i++) {
-            monitor_printf(rs->mon, "\033[D");
+            rs->printf_func(rs->opaque, "\033[D");
         }
         rs->cmd_buf[rs->cmd_buf_size] = '\0';
         if (rs->read_password) {
             len = strlen(rs->cmd_buf);
             for(i = 0; i < len; i++)
-                monitor_printf(rs->mon, "*");
+                rs->printf_func(rs->opaque, "*");
         } else {
-            monitor_printf(rs->mon, "%s", rs->cmd_buf);
+            rs->printf_func(rs->opaque, "%s", rs->cmd_buf);
         }
-        monitor_printf(rs->mon, "\033[K");
+        rs->printf_func(rs->opaque, "\033[K");
         memcpy(rs->last_cmd_buf, rs->cmd_buf, rs->cmd_buf_size);
         rs->last_cmd_buf_size = rs->cmd_buf_size;
         rs->last_cmd_buf_index = rs->cmd_buf_size;
@@ -68,17 +66,17 @@ static void readline_update(ReadLineState *rs)
         delta = rs->cmd_buf_index - rs->last_cmd_buf_index;
         if (delta > 0) {
             for(i = 0;i < delta; i++) {
-                monitor_printf(rs->mon, "\033[C");
+                rs->printf_func(rs->opaque, "\033[C");
             }
         } else {
             delta = -delta;
             for(i = 0;i < delta; i++) {
-                monitor_printf(rs->mon, "\033[D");
+                rs->printf_func(rs->opaque, "\033[D");
             }
         }
         rs->last_cmd_buf_index = rs->cmd_buf_index;
     }
-    monitor_flush(rs->mon);
+    rs->flush_func(rs->opaque);
 }
 
 static void readline_insert_char(ReadLineState *rs, int ch)
@@ -284,7 +282,7 @@ static void readline_completion(ReadLineState *rs)
     cmdline = g_malloc(rs->cmd_buf_index + 1);
     memcpy(cmdline, rs->cmd_buf, rs->cmd_buf_index);
     cmdline[rs->cmd_buf_index] = '\0';
-    rs->completion_finder(rs->mon, cmdline);
+    rs->completion_finder(rs->opaque, cmdline);
     g_free(cmdline);
 
     /* no completion found */
@@ -299,7 +297,7 @@ static void readline_completion(ReadLineState *rs)
         if (len > 0 && rs->completions[0][len - 1] != '/')
             readline_insert_char(rs, ' ');
     } else {
-        monitor_printf(rs->mon, "\n");
+        rs->printf_func(rs->opaque, "\n");
         max_width = 0;
         max_prefix = 0;	
         for(i = 0; i < rs->nb_completions; i++) {
@@ -329,9 +327,9 @@ static void readline_completion(ReadLineState *rs)
         nb_cols = 80 / max_width;
         j = 0;
         for(i = 0; i < rs->nb_completions; i++) {
-            monitor_printf(rs->mon, "%-*s", max_width, rs->completions[i]);
+            rs->printf_func(rs->opaque, "%-*s", max_width, rs->completions[i]);
             if (++j == nb_cols || i == (rs->nb_completions - 1)) {
-                monitor_printf(rs->mon, "\n");
+                rs->printf_func(rs->opaque, "\n");
                 j = 0;
             }
         }
@@ -365,12 +363,12 @@ void readline_handle_byte(ReadLineState *rs, int ch)
             rs->cmd_buf[rs->cmd_buf_size] = '\0';
             if (!rs->read_password)
                 readline_hist_add(rs, rs->cmd_buf);
-            monitor_printf(rs->mon, "\n");
+            rs->printf_func(rs->opaque, "\n");
             rs->cmd_buf_index = 0;
             rs->cmd_buf_size = 0;
             rs->last_cmd_buf_index = 0;
             rs->last_cmd_buf_size = 0;
-            rs->readline_func(rs->mon, rs->cmd_buf, rs->readline_opaque);
+            rs->readline_func(rs->opaque, rs->cmd_buf, rs->readline_opaque);
             break;
         case 23:
             /* ^W */
@@ -480,13 +478,17 @@ const char *readline_get_history(ReadLineState *rs, unsigned int index)
     return rs->history[index];
 }
 
-ReadLineState *readline_init(Monitor *mon,
+ReadLineState *readline_init(ReadLinePrintfFunc *printf_func,
+                             ReadLineFlushFunc *flush_func,
+                             void *opaque,
                              ReadLineCompletionFunc *completion_finder)
 {
     ReadLineState *rs = g_malloc0(sizeof(*rs));
 
     rs->hist_entry = -1;
-    rs->mon = mon;
+    rs->opaque = opaque;
+    rs->printf_func = printf_func;
+    rs->flush_func = flush_func;
     rs->completion_finder = completion_finder;
 
     return rs;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH 2/5] readline: move readline to a generic location
  2013-11-14 10:54 [Qemu-devel] [PATCH 0/5] qemu-io: readline command completion Stefan Hajnoczi
  2013-11-14 10:54 ` [Qemu-devel] [PATCH 1/5] readline: decouple readline from the monitor Stefan Hajnoczi
@ 2013-11-14 10:54 ` Stefan Hajnoczi
  2013-11-14 10:54 ` [Qemu-devel] [PATCH 3/5] osdep: add qemu_set_tty_echo() Stefan Hajnoczi
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Stefan Hajnoczi @ 2013-11-14 10:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Stefan Hajnoczi, Luiz Capitulino

Now that the monitor and readline are decoupled, readline.h no longer
belongs in include/monitor/.  Put the header into include/qemu/.

Move the source file into util/ so it can be linked as part of
libqemuutil.a.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 Makefile.objs              |   1 -
 include/monitor/monitor.h  |   2 +-
 include/monitor/readline.h |  62 ------
 include/qemu/readline.h    |  62 ++++++
 monitor.c                  |   2 +-
 readline.c                 | 495 ---------------------------------------------
 util/Makefile.objs         |   1 +
 util/readline.c            | 495 +++++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 560 insertions(+), 560 deletions(-)
 delete mode 100644 include/monitor/readline.h
 create mode 100644 include/qemu/readline.h
 delete mode 100644 readline.c
 create mode 100644 util/readline.c

diff --git a/Makefile.objs b/Makefile.objs
index 2b6c1fe..81022b6 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -43,7 +43,6 @@ libcacard-y += libcacard/vcardt.o
 ifeq ($(CONFIG_SOFTMMU),y)
 common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o block/
 common-obj-y += net/
-common-obj-y += readline.o
 common-obj-y += qdev-monitor.o device-hotplug.o
 common-obj-$(CONFIG_WIN32) += os-win32.o
 common-obj-$(CONFIG_POSIX) += os-posix.o
diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index 10fa0e3..adfbc21 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -5,7 +5,7 @@
 #include "qapi/qmp/qerror.h"
 #include "qapi/qmp/qdict.h"
 #include "block/block.h"
-#include "monitor/readline.h"
+#include "qemu/readline.h"
 
 extern Monitor *cur_mon;
 extern Monitor *default_mon;
diff --git a/include/monitor/readline.h b/include/monitor/readline.h
deleted file mode 100644
index a89fe4a..0000000
--- a/include/monitor/readline.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef READLINE_H
-#define READLINE_H
-
-#define READLINE_CMD_BUF_SIZE 4095
-#define READLINE_MAX_CMDS 64
-#define READLINE_MAX_COMPLETIONS 256
-
-typedef void ReadLinePrintfFunc(void *opaque, const char *fmt, ...);
-typedef void ReadLineFlushFunc(void *opaque);
-typedef void ReadLineFunc(void *opaque, const char *str,
-                          void *readline_opaque);
-typedef void ReadLineCompletionFunc(void *opaque,
-                                    const char *cmdline);
-
-typedef struct ReadLineState {
-    char cmd_buf[READLINE_CMD_BUF_SIZE + 1];
-    int cmd_buf_index;
-    int cmd_buf_size;
-
-    char last_cmd_buf[READLINE_CMD_BUF_SIZE + 1];
-    int last_cmd_buf_index;
-    int last_cmd_buf_size;
-
-    int esc_state;
-    int esc_param;
-
-    char *history[READLINE_MAX_CMDS];
-    int hist_entry;
-
-    ReadLineCompletionFunc *completion_finder;
-    char *completions[READLINE_MAX_COMPLETIONS];
-    int nb_completions;
-    int completion_index;
-
-    ReadLineFunc *readline_func;
-    void *readline_opaque;
-    int read_password;
-    char prompt[256];
-
-    ReadLinePrintfFunc *printf_func;
-    ReadLineFlushFunc *flush_func;
-    void *opaque;
-} ReadLineState;
-
-void readline_add_completion(ReadLineState *rs, const char *str);
-void readline_set_completion_index(ReadLineState *rs, int completion_index);
-
-const char *readline_get_history(ReadLineState *rs, unsigned int index);
-
-void readline_handle_byte(ReadLineState *rs, int ch);
-
-void readline_start(ReadLineState *rs, const char *prompt, int read_password,
-                    ReadLineFunc *readline_func, void *readline_opaque);
-void readline_restart(ReadLineState *rs);
-void readline_show_prompt(ReadLineState *rs);
-
-ReadLineState *readline_init(ReadLinePrintfFunc *printf_func,
-                             ReadLineFlushFunc *flush_func,
-                             void *opaque,
-                             ReadLineCompletionFunc *completion_finder);
-
-#endif /* !READLINE_H */
diff --git a/include/qemu/readline.h b/include/qemu/readline.h
new file mode 100644
index 0000000..a89fe4a
--- /dev/null
+++ b/include/qemu/readline.h
@@ -0,0 +1,62 @@
+#ifndef READLINE_H
+#define READLINE_H
+
+#define READLINE_CMD_BUF_SIZE 4095
+#define READLINE_MAX_CMDS 64
+#define READLINE_MAX_COMPLETIONS 256
+
+typedef void ReadLinePrintfFunc(void *opaque, const char *fmt, ...);
+typedef void ReadLineFlushFunc(void *opaque);
+typedef void ReadLineFunc(void *opaque, const char *str,
+                          void *readline_opaque);
+typedef void ReadLineCompletionFunc(void *opaque,
+                                    const char *cmdline);
+
+typedef struct ReadLineState {
+    char cmd_buf[READLINE_CMD_BUF_SIZE + 1];
+    int cmd_buf_index;
+    int cmd_buf_size;
+
+    char last_cmd_buf[READLINE_CMD_BUF_SIZE + 1];
+    int last_cmd_buf_index;
+    int last_cmd_buf_size;
+
+    int esc_state;
+    int esc_param;
+
+    char *history[READLINE_MAX_CMDS];
+    int hist_entry;
+
+    ReadLineCompletionFunc *completion_finder;
+    char *completions[READLINE_MAX_COMPLETIONS];
+    int nb_completions;
+    int completion_index;
+
+    ReadLineFunc *readline_func;
+    void *readline_opaque;
+    int read_password;
+    char prompt[256];
+
+    ReadLinePrintfFunc *printf_func;
+    ReadLineFlushFunc *flush_func;
+    void *opaque;
+} ReadLineState;
+
+void readline_add_completion(ReadLineState *rs, const char *str);
+void readline_set_completion_index(ReadLineState *rs, int completion_index);
+
+const char *readline_get_history(ReadLineState *rs, unsigned int index);
+
+void readline_handle_byte(ReadLineState *rs, int ch);
+
+void readline_start(ReadLineState *rs, const char *prompt, int read_password,
+                    ReadLineFunc *readline_func, void *readline_opaque);
+void readline_restart(ReadLineState *rs);
+void readline_show_prompt(ReadLineState *rs);
+
+ReadLineState *readline_init(ReadLinePrintfFunc *printf_func,
+                             ReadLineFlushFunc *flush_func,
+                             void *opaque,
+                             ReadLineCompletionFunc *completion_finder);
+
+#endif /* !READLINE_H */
diff --git a/monitor.c b/monitor.c
index 32d0264..80456fb 100644
--- a/monitor.c
+++ b/monitor.c
@@ -37,7 +37,7 @@
 #include "ui/qemu-spice.h"
 #include "sysemu/sysemu.h"
 #include "monitor/monitor.h"
-#include "monitor/readline.h"
+#include "qemu/readline.h"
 #include "ui/console.h"
 #include "sysemu/blockdev.h"
 #include "audio/audio.h"
diff --git a/readline.c b/readline.c
deleted file mode 100644
index ca894d1..0000000
--- a/readline.c
+++ /dev/null
@@ -1,495 +0,0 @@
-/*
- * QEMU readline utility
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu-common.h"
-#include "monitor/readline.h"
-
-#define IS_NORM 0
-#define IS_ESC  1
-#define IS_CSI  2
-#define IS_SS3  3
-
-void readline_show_prompt(ReadLineState *rs)
-{
-    rs->printf_func(rs->opaque, "%s", rs->prompt);
-    rs->flush_func(rs->opaque);
-    rs->last_cmd_buf_index = 0;
-    rs->last_cmd_buf_size = 0;
-    rs->esc_state = IS_NORM;
-}
-
-/* update the displayed command line */
-static void readline_update(ReadLineState *rs)
-{
-    int i, delta, len;
-
-    if (rs->cmd_buf_size != rs->last_cmd_buf_size ||
-        memcmp(rs->cmd_buf, rs->last_cmd_buf, rs->cmd_buf_size) != 0) {
-        for(i = 0; i < rs->last_cmd_buf_index; i++) {
-            rs->printf_func(rs->opaque, "\033[D");
-        }
-        rs->cmd_buf[rs->cmd_buf_size] = '\0';
-        if (rs->read_password) {
-            len = strlen(rs->cmd_buf);
-            for(i = 0; i < len; i++)
-                rs->printf_func(rs->opaque, "*");
-        } else {
-            rs->printf_func(rs->opaque, "%s", rs->cmd_buf);
-        }
-        rs->printf_func(rs->opaque, "\033[K");
-        memcpy(rs->last_cmd_buf, rs->cmd_buf, rs->cmd_buf_size);
-        rs->last_cmd_buf_size = rs->cmd_buf_size;
-        rs->last_cmd_buf_index = rs->cmd_buf_size;
-    }
-    if (rs->cmd_buf_index != rs->last_cmd_buf_index) {
-        delta = rs->cmd_buf_index - rs->last_cmd_buf_index;
-        if (delta > 0) {
-            for(i = 0;i < delta; i++) {
-                rs->printf_func(rs->opaque, "\033[C");
-            }
-        } else {
-            delta = -delta;
-            for(i = 0;i < delta; i++) {
-                rs->printf_func(rs->opaque, "\033[D");
-            }
-        }
-        rs->last_cmd_buf_index = rs->cmd_buf_index;
-    }
-    rs->flush_func(rs->opaque);
-}
-
-static void readline_insert_char(ReadLineState *rs, int ch)
-{
-    if (rs->cmd_buf_index < READLINE_CMD_BUF_SIZE) {
-        memmove(rs->cmd_buf + rs->cmd_buf_index + 1,
-                rs->cmd_buf + rs->cmd_buf_index,
-                rs->cmd_buf_size - rs->cmd_buf_index);
-        rs->cmd_buf[rs->cmd_buf_index] = ch;
-        rs->cmd_buf_size++;
-        rs->cmd_buf_index++;
-    }
-}
-
-static void readline_backward_char(ReadLineState *rs)
-{
-    if (rs->cmd_buf_index > 0) {
-        rs->cmd_buf_index--;
-    }
-}
-
-static void readline_forward_char(ReadLineState *rs)
-{
-    if (rs->cmd_buf_index < rs->cmd_buf_size) {
-        rs->cmd_buf_index++;
-    }
-}
-
-static void readline_delete_char(ReadLineState *rs)
-{
-    if (rs->cmd_buf_index < rs->cmd_buf_size) {
-        memmove(rs->cmd_buf + rs->cmd_buf_index,
-                rs->cmd_buf + rs->cmd_buf_index + 1,
-                rs->cmd_buf_size - rs->cmd_buf_index - 1);
-        rs->cmd_buf_size--;
-    }
-}
-
-static void readline_backspace(ReadLineState *rs)
-{
-    if (rs->cmd_buf_index > 0) {
-        readline_backward_char(rs);
-        readline_delete_char(rs);
-    }
-}
-
-static void readline_backword(ReadLineState *rs)
-{
-    int start;
-
-    if (rs->cmd_buf_index == 0 || rs->cmd_buf_index > rs->cmd_buf_size) {
-        return;
-    }
-
-    start = rs->cmd_buf_index - 1;
-
-    /* find first word (backwards) */
-    while (start > 0) {
-        if (!qemu_isspace(rs->cmd_buf[start])) {
-            break;
-        }
-
-        --start;
-    }
-
-    /* find first space (backwards) */
-    while (start > 0) {
-        if (qemu_isspace(rs->cmd_buf[start])) {
-            ++start;
-            break;
-        }
-
-        --start;
-    }
-
-    /* remove word */
-    if (start < rs->cmd_buf_index) {
-        memmove(rs->cmd_buf + start,
-                rs->cmd_buf + rs->cmd_buf_index,
-                rs->cmd_buf_size - rs->cmd_buf_index);
-        rs->cmd_buf_size -= rs->cmd_buf_index - start;
-        rs->cmd_buf_index = start;
-    }
-}
-
-static void readline_bol(ReadLineState *rs)
-{
-    rs->cmd_buf_index = 0;
-}
-
-static void readline_eol(ReadLineState *rs)
-{
-    rs->cmd_buf_index = rs->cmd_buf_size;
-}
-
-static void readline_up_char(ReadLineState *rs)
-{
-    int idx;
-
-    if (rs->hist_entry == 0)
-	return;
-    if (rs->hist_entry == -1) {
-	/* Find latest entry */
-	for (idx = 0; idx < READLINE_MAX_CMDS; idx++) {
-	    if (rs->history[idx] == NULL)
-		break;
-	}
-	rs->hist_entry = idx;
-    }
-    rs->hist_entry--;
-    if (rs->hist_entry >= 0) {
-	pstrcpy(rs->cmd_buf, sizeof(rs->cmd_buf),
-                rs->history[rs->hist_entry]);
-	rs->cmd_buf_index = rs->cmd_buf_size = strlen(rs->cmd_buf);
-    }
-}
-
-static void readline_down_char(ReadLineState *rs)
-{
-    if (rs->hist_entry == -1)
-        return;
-    if (rs->hist_entry < READLINE_MAX_CMDS - 1 &&
-        rs->history[++rs->hist_entry] != NULL) {
-	pstrcpy(rs->cmd_buf, sizeof(rs->cmd_buf),
-                rs->history[rs->hist_entry]);
-    } else {
-        rs->cmd_buf[0] = 0;
-	rs->hist_entry = -1;
-    }
-    rs->cmd_buf_index = rs->cmd_buf_size = strlen(rs->cmd_buf);
-}
-
-static void readline_hist_add(ReadLineState *rs, const char *cmdline)
-{
-    char *hist_entry, *new_entry;
-    int idx;
-
-    if (cmdline[0] == '\0')
-	return;
-    new_entry = NULL;
-    if (rs->hist_entry != -1) {
-	/* We were editing an existing history entry: replace it */
-	hist_entry = rs->history[rs->hist_entry];
-	idx = rs->hist_entry;
-	if (strcmp(hist_entry, cmdline) == 0) {
-	    goto same_entry;
-	}
-    }
-    /* Search cmdline in history buffers */
-    for (idx = 0; idx < READLINE_MAX_CMDS; idx++) {
-	hist_entry = rs->history[idx];
-	if (hist_entry == NULL)
-	    break;
-	if (strcmp(hist_entry, cmdline) == 0) {
-	same_entry:
-	    new_entry = hist_entry;
-	    /* Put this entry at the end of history */
-	    memmove(&rs->history[idx], &rs->history[idx + 1],
-		    (READLINE_MAX_CMDS - (idx + 1)) * sizeof(char *));
-	    rs->history[READLINE_MAX_CMDS - 1] = NULL;
-	    for (; idx < READLINE_MAX_CMDS; idx++) {
-		if (rs->history[idx] == NULL)
-		    break;
-	    }
-	    break;
-	}
-    }
-    if (idx == READLINE_MAX_CMDS) {
-	/* Need to get one free slot */
-        g_free(rs->history[0]);
-	memmove(rs->history, &rs->history[1],
-	        (READLINE_MAX_CMDS - 1) * sizeof(char *));
-	rs->history[READLINE_MAX_CMDS - 1] = NULL;
-	idx = READLINE_MAX_CMDS - 1;
-    }
-    if (new_entry == NULL)
-        new_entry = g_strdup(cmdline);
-    rs->history[idx] = new_entry;
-    rs->hist_entry = -1;
-}
-
-/* completion support */
-
-void readline_add_completion(ReadLineState *rs, const char *str)
-{
-    if (rs->nb_completions < READLINE_MAX_COMPLETIONS) {
-        rs->completions[rs->nb_completions++] = g_strdup(str);
-    }
-}
-
-void readline_set_completion_index(ReadLineState *rs, int index)
-{
-    rs->completion_index = index;
-}
-
-static void readline_completion(ReadLineState *rs)
-{
-    int len, i, j, max_width, nb_cols, max_prefix;
-    char *cmdline;
-
-    rs->nb_completions = 0;
-
-    cmdline = g_malloc(rs->cmd_buf_index + 1);
-    memcpy(cmdline, rs->cmd_buf, rs->cmd_buf_index);
-    cmdline[rs->cmd_buf_index] = '\0';
-    rs->completion_finder(rs->opaque, cmdline);
-    g_free(cmdline);
-
-    /* no completion found */
-    if (rs->nb_completions <= 0)
-        return;
-    if (rs->nb_completions == 1) {
-        len = strlen(rs->completions[0]);
-        for(i = rs->completion_index; i < len; i++) {
-            readline_insert_char(rs, rs->completions[0][i]);
-        }
-        /* extra space for next argument. XXX: make it more generic */
-        if (len > 0 && rs->completions[0][len - 1] != '/')
-            readline_insert_char(rs, ' ');
-    } else {
-        rs->printf_func(rs->opaque, "\n");
-        max_width = 0;
-        max_prefix = 0;	
-        for(i = 0; i < rs->nb_completions; i++) {
-            len = strlen(rs->completions[i]);
-            if (i==0) {
-                max_prefix = len;
-            } else {
-                if (len < max_prefix)
-                    max_prefix = len;
-                for(j=0; j<max_prefix; j++) {
-                    if (rs->completions[i][j] != rs->completions[0][j])
-                        max_prefix = j;
-                }
-            }
-            if (len > max_width)
-                max_width = len;
-        }
-        if (max_prefix > 0) 
-            for(i = rs->completion_index; i < max_prefix; i++) {
-                readline_insert_char(rs, rs->completions[0][i]);
-            }
-        max_width += 2;
-        if (max_width < 10)
-            max_width = 10;
-        else if (max_width > 80)
-            max_width = 80;
-        nb_cols = 80 / max_width;
-        j = 0;
-        for(i = 0; i < rs->nb_completions; i++) {
-            rs->printf_func(rs->opaque, "%-*s", max_width, rs->completions[i]);
-            if (++j == nb_cols || i == (rs->nb_completions - 1)) {
-                rs->printf_func(rs->opaque, "\n");
-                j = 0;
-            }
-        }
-        readline_show_prompt(rs);
-    }
-    for (i = 0; i < rs->nb_completions; i++) {
-        g_free(rs->completions[i]);
-    }
-}
-
-/* return true if command handled */
-void readline_handle_byte(ReadLineState *rs, int ch)
-{
-    switch(rs->esc_state) {
-    case IS_NORM:
-        switch(ch) {
-        case 1:
-            readline_bol(rs);
-            break;
-        case 4:
-            readline_delete_char(rs);
-            break;
-        case 5:
-            readline_eol(rs);
-            break;
-        case 9:
-            readline_completion(rs);
-            break;
-        case 10:
-        case 13:
-            rs->cmd_buf[rs->cmd_buf_size] = '\0';
-            if (!rs->read_password)
-                readline_hist_add(rs, rs->cmd_buf);
-            rs->printf_func(rs->opaque, "\n");
-            rs->cmd_buf_index = 0;
-            rs->cmd_buf_size = 0;
-            rs->last_cmd_buf_index = 0;
-            rs->last_cmd_buf_size = 0;
-            rs->readline_func(rs->opaque, rs->cmd_buf, rs->readline_opaque);
-            break;
-        case 23:
-            /* ^W */
-            readline_backword(rs);
-            break;
-        case 27:
-            rs->esc_state = IS_ESC;
-            break;
-        case 127:
-        case 8:
-            readline_backspace(rs);
-            break;
-	case 155:
-            rs->esc_state = IS_CSI;
-	    break;
-        default:
-            if (ch >= 32) {
-                readline_insert_char(rs, ch);
-            }
-            break;
-        }
-        break;
-    case IS_ESC:
-        if (ch == '[') {
-            rs->esc_state = IS_CSI;
-            rs->esc_param = 0;
-        } else if (ch == 'O') {
-            rs->esc_state = IS_SS3;
-            rs->esc_param = 0;
-        } else {
-            rs->esc_state = IS_NORM;
-        }
-        break;
-    case IS_CSI:
-        switch(ch) {
-	case 'A':
-	case 'F':
-	    readline_up_char(rs);
-	    break;
-	case 'B':
-	case 'E':
-	    readline_down_char(rs);
-	    break;
-        case 'D':
-            readline_backward_char(rs);
-            break;
-        case 'C':
-            readline_forward_char(rs);
-            break;
-        case '0' ... '9':
-            rs->esc_param = rs->esc_param * 10 + (ch - '0');
-            goto the_end;
-        case '~':
-            switch(rs->esc_param) {
-            case 1:
-                readline_bol(rs);
-                break;
-            case 3:
-                readline_delete_char(rs);
-                break;
-            case 4:
-                readline_eol(rs);
-                break;
-            }
-            break;
-        default:
-            break;
-        }
-        rs->esc_state = IS_NORM;
-    the_end:
-        break;
-    case IS_SS3:
-        switch(ch) {
-        case 'F':
-            readline_eol(rs);
-            break;
-        case 'H':
-            readline_bol(rs);
-            break;
-        }
-        rs->esc_state = IS_NORM;
-        break;
-    }
-    readline_update(rs);
-}
-
-void readline_start(ReadLineState *rs, const char *prompt, int read_password,
-                    ReadLineFunc *readline_func, void *opaque)
-{
-    pstrcpy(rs->prompt, sizeof(rs->prompt), prompt);
-    rs->readline_func = readline_func;
-    rs->readline_opaque = opaque;
-    rs->read_password = read_password;
-    readline_restart(rs);
-}
-
-void readline_restart(ReadLineState *rs)
-{
-    rs->cmd_buf_index = 0;
-    rs->cmd_buf_size = 0;
-}
-
-const char *readline_get_history(ReadLineState *rs, unsigned int index)
-{
-    if (index >= READLINE_MAX_CMDS)
-        return NULL;
-    return rs->history[index];
-}
-
-ReadLineState *readline_init(ReadLinePrintfFunc *printf_func,
-                             ReadLineFlushFunc *flush_func,
-                             void *opaque,
-                             ReadLineCompletionFunc *completion_finder)
-{
-    ReadLineState *rs = g_malloc0(sizeof(*rs));
-
-    rs->hist_entry = -1;
-    rs->opaque = opaque;
-    rs->printf_func = printf_func;
-    rs->flush_func = flush_func;
-    rs->completion_finder = completion_finder;
-
-    return rs;
-}
diff --git a/util/Makefile.objs b/util/Makefile.objs
index 2bb13a2..c0e3af9 100644
--- a/util/Makefile.objs
+++ b/util/Makefile.objs
@@ -12,3 +12,4 @@ util-obj-y += qemu-option.o qemu-progress.o
 util-obj-y += hexdump.o
 util-obj-y += crc32c.o
 util-obj-y += throttle.o
+util-obj-y += readline.o
diff --git a/util/readline.c b/util/readline.c
new file mode 100644
index 0000000..8441be4
--- /dev/null
+++ b/util/readline.c
@@ -0,0 +1,495 @@
+/*
+ * QEMU readline utility
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu-common.h"
+#include "qemu/readline.h"
+
+#define IS_NORM 0
+#define IS_ESC  1
+#define IS_CSI  2
+#define IS_SS3  3
+
+void readline_show_prompt(ReadLineState *rs)
+{
+    rs->printf_func(rs->opaque, "%s", rs->prompt);
+    rs->flush_func(rs->opaque);
+    rs->last_cmd_buf_index = 0;
+    rs->last_cmd_buf_size = 0;
+    rs->esc_state = IS_NORM;
+}
+
+/* update the displayed command line */
+static void readline_update(ReadLineState *rs)
+{
+    int i, delta, len;
+
+    if (rs->cmd_buf_size != rs->last_cmd_buf_size ||
+        memcmp(rs->cmd_buf, rs->last_cmd_buf, rs->cmd_buf_size) != 0) {
+        for(i = 0; i < rs->last_cmd_buf_index; i++) {
+            rs->printf_func(rs->opaque, "\033[D");
+        }
+        rs->cmd_buf[rs->cmd_buf_size] = '\0';
+        if (rs->read_password) {
+            len = strlen(rs->cmd_buf);
+            for(i = 0; i < len; i++)
+                rs->printf_func(rs->opaque, "*");
+        } else {
+            rs->printf_func(rs->opaque, "%s", rs->cmd_buf);
+        }
+        rs->printf_func(rs->opaque, "\033[K");
+        memcpy(rs->last_cmd_buf, rs->cmd_buf, rs->cmd_buf_size);
+        rs->last_cmd_buf_size = rs->cmd_buf_size;
+        rs->last_cmd_buf_index = rs->cmd_buf_size;
+    }
+    if (rs->cmd_buf_index != rs->last_cmd_buf_index) {
+        delta = rs->cmd_buf_index - rs->last_cmd_buf_index;
+        if (delta > 0) {
+            for(i = 0;i < delta; i++) {
+                rs->printf_func(rs->opaque, "\033[C");
+            }
+        } else {
+            delta = -delta;
+            for(i = 0;i < delta; i++) {
+                rs->printf_func(rs->opaque, "\033[D");
+            }
+        }
+        rs->last_cmd_buf_index = rs->cmd_buf_index;
+    }
+    rs->flush_func(rs->opaque);
+}
+
+static void readline_insert_char(ReadLineState *rs, int ch)
+{
+    if (rs->cmd_buf_index < READLINE_CMD_BUF_SIZE) {
+        memmove(rs->cmd_buf + rs->cmd_buf_index + 1,
+                rs->cmd_buf + rs->cmd_buf_index,
+                rs->cmd_buf_size - rs->cmd_buf_index);
+        rs->cmd_buf[rs->cmd_buf_index] = ch;
+        rs->cmd_buf_size++;
+        rs->cmd_buf_index++;
+    }
+}
+
+static void readline_backward_char(ReadLineState *rs)
+{
+    if (rs->cmd_buf_index > 0) {
+        rs->cmd_buf_index--;
+    }
+}
+
+static void readline_forward_char(ReadLineState *rs)
+{
+    if (rs->cmd_buf_index < rs->cmd_buf_size) {
+        rs->cmd_buf_index++;
+    }
+}
+
+static void readline_delete_char(ReadLineState *rs)
+{
+    if (rs->cmd_buf_index < rs->cmd_buf_size) {
+        memmove(rs->cmd_buf + rs->cmd_buf_index,
+                rs->cmd_buf + rs->cmd_buf_index + 1,
+                rs->cmd_buf_size - rs->cmd_buf_index - 1);
+        rs->cmd_buf_size--;
+    }
+}
+
+static void readline_backspace(ReadLineState *rs)
+{
+    if (rs->cmd_buf_index > 0) {
+        readline_backward_char(rs);
+        readline_delete_char(rs);
+    }
+}
+
+static void readline_backword(ReadLineState *rs)
+{
+    int start;
+
+    if (rs->cmd_buf_index == 0 || rs->cmd_buf_index > rs->cmd_buf_size) {
+        return;
+    }
+
+    start = rs->cmd_buf_index - 1;
+
+    /* find first word (backwards) */
+    while (start > 0) {
+        if (!qemu_isspace(rs->cmd_buf[start])) {
+            break;
+        }
+
+        --start;
+    }
+
+    /* find first space (backwards) */
+    while (start > 0) {
+        if (qemu_isspace(rs->cmd_buf[start])) {
+            ++start;
+            break;
+        }
+
+        --start;
+    }
+
+    /* remove word */
+    if (start < rs->cmd_buf_index) {
+        memmove(rs->cmd_buf + start,
+                rs->cmd_buf + rs->cmd_buf_index,
+                rs->cmd_buf_size - rs->cmd_buf_index);
+        rs->cmd_buf_size -= rs->cmd_buf_index - start;
+        rs->cmd_buf_index = start;
+    }
+}
+
+static void readline_bol(ReadLineState *rs)
+{
+    rs->cmd_buf_index = 0;
+}
+
+static void readline_eol(ReadLineState *rs)
+{
+    rs->cmd_buf_index = rs->cmd_buf_size;
+}
+
+static void readline_up_char(ReadLineState *rs)
+{
+    int idx;
+
+    if (rs->hist_entry == 0)
+	return;
+    if (rs->hist_entry == -1) {
+	/* Find latest entry */
+	for (idx = 0; idx < READLINE_MAX_CMDS; idx++) {
+	    if (rs->history[idx] == NULL)
+		break;
+	}
+	rs->hist_entry = idx;
+    }
+    rs->hist_entry--;
+    if (rs->hist_entry >= 0) {
+	pstrcpy(rs->cmd_buf, sizeof(rs->cmd_buf),
+                rs->history[rs->hist_entry]);
+	rs->cmd_buf_index = rs->cmd_buf_size = strlen(rs->cmd_buf);
+    }
+}
+
+static void readline_down_char(ReadLineState *rs)
+{
+    if (rs->hist_entry == -1)
+        return;
+    if (rs->hist_entry < READLINE_MAX_CMDS - 1 &&
+        rs->history[++rs->hist_entry] != NULL) {
+	pstrcpy(rs->cmd_buf, sizeof(rs->cmd_buf),
+                rs->history[rs->hist_entry]);
+    } else {
+        rs->cmd_buf[0] = 0;
+	rs->hist_entry = -1;
+    }
+    rs->cmd_buf_index = rs->cmd_buf_size = strlen(rs->cmd_buf);
+}
+
+static void readline_hist_add(ReadLineState *rs, const char *cmdline)
+{
+    char *hist_entry, *new_entry;
+    int idx;
+
+    if (cmdline[0] == '\0')
+	return;
+    new_entry = NULL;
+    if (rs->hist_entry != -1) {
+	/* We were editing an existing history entry: replace it */
+	hist_entry = rs->history[rs->hist_entry];
+	idx = rs->hist_entry;
+	if (strcmp(hist_entry, cmdline) == 0) {
+	    goto same_entry;
+	}
+    }
+    /* Search cmdline in history buffers */
+    for (idx = 0; idx < READLINE_MAX_CMDS; idx++) {
+	hist_entry = rs->history[idx];
+	if (hist_entry == NULL)
+	    break;
+	if (strcmp(hist_entry, cmdline) == 0) {
+	same_entry:
+	    new_entry = hist_entry;
+	    /* Put this entry at the end of history */
+	    memmove(&rs->history[idx], &rs->history[idx + 1],
+		    (READLINE_MAX_CMDS - (idx + 1)) * sizeof(char *));
+	    rs->history[READLINE_MAX_CMDS - 1] = NULL;
+	    for (; idx < READLINE_MAX_CMDS; idx++) {
+		if (rs->history[idx] == NULL)
+		    break;
+	    }
+	    break;
+	}
+    }
+    if (idx == READLINE_MAX_CMDS) {
+	/* Need to get one free slot */
+        g_free(rs->history[0]);
+	memmove(rs->history, &rs->history[1],
+	        (READLINE_MAX_CMDS - 1) * sizeof(char *));
+	rs->history[READLINE_MAX_CMDS - 1] = NULL;
+	idx = READLINE_MAX_CMDS - 1;
+    }
+    if (new_entry == NULL)
+        new_entry = g_strdup(cmdline);
+    rs->history[idx] = new_entry;
+    rs->hist_entry = -1;
+}
+
+/* completion support */
+
+void readline_add_completion(ReadLineState *rs, const char *str)
+{
+    if (rs->nb_completions < READLINE_MAX_COMPLETIONS) {
+        rs->completions[rs->nb_completions++] = g_strdup(str);
+    }
+}
+
+void readline_set_completion_index(ReadLineState *rs, int index)
+{
+    rs->completion_index = index;
+}
+
+static void readline_completion(ReadLineState *rs)
+{
+    int len, i, j, max_width, nb_cols, max_prefix;
+    char *cmdline;
+
+    rs->nb_completions = 0;
+
+    cmdline = g_malloc(rs->cmd_buf_index + 1);
+    memcpy(cmdline, rs->cmd_buf, rs->cmd_buf_index);
+    cmdline[rs->cmd_buf_index] = '\0';
+    rs->completion_finder(rs->opaque, cmdline);
+    g_free(cmdline);
+
+    /* no completion found */
+    if (rs->nb_completions <= 0)
+        return;
+    if (rs->nb_completions == 1) {
+        len = strlen(rs->completions[0]);
+        for(i = rs->completion_index; i < len; i++) {
+            readline_insert_char(rs, rs->completions[0][i]);
+        }
+        /* extra space for next argument. XXX: make it more generic */
+        if (len > 0 && rs->completions[0][len - 1] != '/')
+            readline_insert_char(rs, ' ');
+    } else {
+        rs->printf_func(rs->opaque, "\n");
+        max_width = 0;
+        max_prefix = 0;	
+        for(i = 0; i < rs->nb_completions; i++) {
+            len = strlen(rs->completions[i]);
+            if (i==0) {
+                max_prefix = len;
+            } else {
+                if (len < max_prefix)
+                    max_prefix = len;
+                for(j=0; j<max_prefix; j++) {
+                    if (rs->completions[i][j] != rs->completions[0][j])
+                        max_prefix = j;
+                }
+            }
+            if (len > max_width)
+                max_width = len;
+        }
+        if (max_prefix > 0) 
+            for(i = rs->completion_index; i < max_prefix; i++) {
+                readline_insert_char(rs, rs->completions[0][i]);
+            }
+        max_width += 2;
+        if (max_width < 10)
+            max_width = 10;
+        else if (max_width > 80)
+            max_width = 80;
+        nb_cols = 80 / max_width;
+        j = 0;
+        for(i = 0; i < rs->nb_completions; i++) {
+            rs->printf_func(rs->opaque, "%-*s", max_width, rs->completions[i]);
+            if (++j == nb_cols || i == (rs->nb_completions - 1)) {
+                rs->printf_func(rs->opaque, "\n");
+                j = 0;
+            }
+        }
+        readline_show_prompt(rs);
+    }
+    for (i = 0; i < rs->nb_completions; i++) {
+        g_free(rs->completions[i]);
+    }
+}
+
+/* return true if command handled */
+void readline_handle_byte(ReadLineState *rs, int ch)
+{
+    switch(rs->esc_state) {
+    case IS_NORM:
+        switch(ch) {
+        case 1:
+            readline_bol(rs);
+            break;
+        case 4:
+            readline_delete_char(rs);
+            break;
+        case 5:
+            readline_eol(rs);
+            break;
+        case 9:
+            readline_completion(rs);
+            break;
+        case 10:
+        case 13:
+            rs->cmd_buf[rs->cmd_buf_size] = '\0';
+            if (!rs->read_password)
+                readline_hist_add(rs, rs->cmd_buf);
+            rs->printf_func(rs->opaque, "\n");
+            rs->cmd_buf_index = 0;
+            rs->cmd_buf_size = 0;
+            rs->last_cmd_buf_index = 0;
+            rs->last_cmd_buf_size = 0;
+            rs->readline_func(rs->opaque, rs->cmd_buf, rs->readline_opaque);
+            break;
+        case 23:
+            /* ^W */
+            readline_backword(rs);
+            break;
+        case 27:
+            rs->esc_state = IS_ESC;
+            break;
+        case 127:
+        case 8:
+            readline_backspace(rs);
+            break;
+	case 155:
+            rs->esc_state = IS_CSI;
+	    break;
+        default:
+            if (ch >= 32) {
+                readline_insert_char(rs, ch);
+            }
+            break;
+        }
+        break;
+    case IS_ESC:
+        if (ch == '[') {
+            rs->esc_state = IS_CSI;
+            rs->esc_param = 0;
+        } else if (ch == 'O') {
+            rs->esc_state = IS_SS3;
+            rs->esc_param = 0;
+        } else {
+            rs->esc_state = IS_NORM;
+        }
+        break;
+    case IS_CSI:
+        switch(ch) {
+	case 'A':
+	case 'F':
+	    readline_up_char(rs);
+	    break;
+	case 'B':
+	case 'E':
+	    readline_down_char(rs);
+	    break;
+        case 'D':
+            readline_backward_char(rs);
+            break;
+        case 'C':
+            readline_forward_char(rs);
+            break;
+        case '0' ... '9':
+            rs->esc_param = rs->esc_param * 10 + (ch - '0');
+            goto the_end;
+        case '~':
+            switch(rs->esc_param) {
+            case 1:
+                readline_bol(rs);
+                break;
+            case 3:
+                readline_delete_char(rs);
+                break;
+            case 4:
+                readline_eol(rs);
+                break;
+            }
+            break;
+        default:
+            break;
+        }
+        rs->esc_state = IS_NORM;
+    the_end:
+        break;
+    case IS_SS3:
+        switch(ch) {
+        case 'F':
+            readline_eol(rs);
+            break;
+        case 'H':
+            readline_bol(rs);
+            break;
+        }
+        rs->esc_state = IS_NORM;
+        break;
+    }
+    readline_update(rs);
+}
+
+void readline_start(ReadLineState *rs, const char *prompt, int read_password,
+                    ReadLineFunc *readline_func, void *opaque)
+{
+    pstrcpy(rs->prompt, sizeof(rs->prompt), prompt);
+    rs->readline_func = readline_func;
+    rs->readline_opaque = opaque;
+    rs->read_password = read_password;
+    readline_restart(rs);
+}
+
+void readline_restart(ReadLineState *rs)
+{
+    rs->cmd_buf_index = 0;
+    rs->cmd_buf_size = 0;
+}
+
+const char *readline_get_history(ReadLineState *rs, unsigned int index)
+{
+    if (index >= READLINE_MAX_CMDS)
+        return NULL;
+    return rs->history[index];
+}
+
+ReadLineState *readline_init(ReadLinePrintfFunc *printf_func,
+                             ReadLineFlushFunc *flush_func,
+                             void *opaque,
+                             ReadLineCompletionFunc *completion_finder)
+{
+    ReadLineState *rs = g_malloc0(sizeof(*rs));
+
+    rs->hist_entry = -1;
+    rs->opaque = opaque;
+    rs->printf_func = printf_func;
+    rs->flush_func = flush_func;
+    rs->completion_finder = completion_finder;
+
+    return rs;
+}
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH 3/5] osdep: add qemu_set_tty_echo()
  2013-11-14 10:54 [Qemu-devel] [PATCH 0/5] qemu-io: readline command completion Stefan Hajnoczi
  2013-11-14 10:54 ` [Qemu-devel] [PATCH 1/5] readline: decouple readline from the monitor Stefan Hajnoczi
  2013-11-14 10:54 ` [Qemu-devel] [PATCH 2/5] readline: move readline to a generic location Stefan Hajnoczi
@ 2013-11-14 10:54 ` Stefan Hajnoczi
  2013-11-29 10:04   ` Kevin Wolf
  2013-11-14 10:54 ` [Qemu-devel] [PATCH 4/5] qemu-io: use readline.c Stefan Hajnoczi
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 10+ messages in thread
From: Stefan Hajnoczi @ 2013-11-14 10:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Stefan Hajnoczi, Luiz Capitulino

Using stdin with readline.c requires disabling echo and line buffering.
Add a portable wrapper to set the terminal attributes under Linux and
Windows.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 include/qemu/osdep.h |  2 ++
 util/oslib-posix.c   | 18 ++++++++++++++++++
 util/oslib-win32.c   | 19 +++++++++++++++++++
 3 files changed, 39 insertions(+)

diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
index 26136f1..eb5e145 100644
--- a/include/qemu/osdep.h
+++ b/include/qemu/osdep.h
@@ -215,4 +215,6 @@ bool fips_get_state(void);
  */
 char *qemu_get_local_state_pathname(const char *relative_pathname);
 
+void qemu_set_tty_echo(int fd, bool echo);
+
 #endif
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
index e00a44c..f5c4016 100644
--- a/util/oslib-posix.c
+++ b/util/oslib-posix.c
@@ -47,6 +47,9 @@ extern int daemon(int, int);
 #  define QEMU_VMALLOC_ALIGN getpagesize()
 #endif
 
+#include <termios.h>
+#include <unistd.h>
+
 #include <glib/gprintf.h>
 
 #include "config-host.h"
@@ -251,3 +254,18 @@ qemu_get_local_state_pathname(const char *relative_pathname)
     return g_strdup_printf("%s/%s", CONFIG_QEMU_LOCALSTATEDIR,
                            relative_pathname);
 }
+
+void qemu_set_tty_echo(int fd, bool echo)
+{
+    struct termios tty;
+
+    tcgetattr(fd, &tty);
+
+    if (echo) {
+        tty.c_lflag |= ECHO | ECHONL | ICANON | IEXTEN;
+    } else {
+        tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN);
+    }
+
+    tcsetattr(fd, TCSANOW, &tty);
+}
diff --git a/util/oslib-win32.c b/util/oslib-win32.c
index 776ccfa..50be044 100644
--- a/util/oslib-win32.c
+++ b/util/oslib-win32.c
@@ -189,3 +189,22 @@ qemu_get_local_state_pathname(const char *relative_pathname)
     return g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", base_path,
                            relative_pathname);
 }
+
+void qemu_set_tty_echo(int fd, bool echo)
+{
+    HANDLE handle = (HANDLE)_get_osfhandle(fd);
+    DWORD dwMode = 0;
+
+    if (handle == INVALID_HANDLE_VALUE) {
+        return;
+    }
+
+    GetConsoleMode(handle, &dwMode);
+
+    if (echo) {
+        SetConsoleMode(handle, dwMode | ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT);
+    } else {
+        SetConsoleMode(handle,
+                       dwMode & ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT));
+    }
+}
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH 4/5] qemu-io: use readline.c
  2013-11-14 10:54 [Qemu-devel] [PATCH 0/5] qemu-io: readline command completion Stefan Hajnoczi
                   ` (2 preceding siblings ...)
  2013-11-14 10:54 ` [Qemu-devel] [PATCH 3/5] osdep: add qemu_set_tty_echo() Stefan Hajnoczi
@ 2013-11-14 10:54 ` Stefan Hajnoczi
  2013-11-14 10:54 ` [Qemu-devel] [PATCH 5/5] qemu-io: add command completion Stefan Hajnoczi
  2013-11-28  1:28 ` [Qemu-devel] [PATCH 0/5] qemu-io: readline " Luiz Capitulino
  5 siblings, 0 replies; 10+ messages in thread
From: Stefan Hajnoczi @ 2013-11-14 10:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Stefan Hajnoczi, Luiz Capitulino

Use readline.c for command-line history.  There was support for GNU
Readline and BSD Editline but it was never compiled in.  Since QEMU has
its own readline.c, just use that when qemu-io runs with stdin attached
to a terminal.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 qemu-io.c | 103 +++++++++++++++++++++++++++++++++++---------------------------
 1 file changed, 58 insertions(+), 45 deletions(-)

diff --git a/qemu-io.c b/qemu-io.c
index 3b3340a..d7c26d3 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -18,6 +18,7 @@
 #include "qemu/main-loop.h"
 #include "qemu/option.h"
 #include "qemu/config-file.h"
+#include "qemu/readline.h"
 #include "block/block_int.h"
 #include "trace/control.h"
 
@@ -32,6 +33,8 @@ extern int qemuio_misalign;
 static int ncmdline;
 static char **cmdline;
 
+static ReadLineState *readline_state;
+
 static int close_f(BlockDriverState *bs, int argc, char **argv)
 {
     bdrv_unref(bs);
@@ -203,14 +206,6 @@ static void usage(const char *name)
     name);
 }
 
-
-#if defined(ENABLE_READLINE)
-# include <readline/history.h>
-# include <readline/readline.h>
-#elif defined(ENABLE_EDITLINE)
-# include <histedit.h>
-#endif
-
 static char *get_prompt(void)
 {
     static char prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ];
@@ -222,52 +217,47 @@ static char *get_prompt(void)
     return prompt;
 }
 
-#if defined(ENABLE_READLINE)
-static char *fetchline(void)
+static void readline_printf_func(void *opaque, const char *fmt, ...)
 {
-    char *line = readline(get_prompt());
-    if (line && *line) {
-        add_history(line);
-    }
-    return line;
+    va_list ap;
+    va_start(ap, fmt);
+    vprintf(fmt, ap);
+    va_end(ap);
 }
-#elif defined(ENABLE_EDITLINE)
-static char *el_get_prompt(EditLine *e)
+
+static void readline_flush_func(void *opaque)
 {
-    return get_prompt();
+    fflush(stdout);
 }
 
-static char *fetchline(void)
+static void readline_func(void *opaque, const char *str, void *readline_opaque)
 {
-    static EditLine *el;
-    static History *hist;
-    HistEvent hevent;
-    char *line;
-    int count;
-
-    if (!el) {
-        hist = history_init();
-        history(hist, &hevent, H_SETSIZE, 100);
-        el = el_init(progname, stdin, stdout, stderr);
-        el_source(el, NULL);
-        el_set(el, EL_SIGNAL, 1);
-        el_set(el, EL_PROMPT, el_get_prompt);
-        el_set(el, EL_HIST, history, (const char *)hist);
-    }
-    line = strdup(el_gets(el, &count));
-    if (line) {
-        if (count > 0) {
-            line[count-1] = '\0';
-        }
-        if (*line) {
-            history(hist, &hevent, H_ENTER, line);
+    char **line = readline_opaque;
+    *line = g_strdup(str);
+}
+
+static void readline_completion_func(void *opaque, const char *str)
+{
+    /* No command or argument completion implemented yet */
+}
+
+static char *fetchline_readline(void)
+{
+    char *line = NULL;
+
+    readline_start(readline_state, get_prompt(), 0, readline_func, &line);
+    while (!line) {
+        int ch = getchar();
+        if (ch == EOF) {
+            break;
         }
+        readline_handle_byte(readline_state, ch);
     }
     return line;
 }
-#else
-# define MAXREADLINESZ 1024
-static char *fetchline(void)
+
+#define MAXREADLINESZ 1024
+static char *fetchline_fgets(void)
 {
     char *p, *line = g_malloc(MAXREADLINESZ);
 
@@ -283,7 +273,15 @@ static char *fetchline(void)
 
     return line;
 }
-#endif
+
+static char *fetchline(void)
+{
+    if (readline_state) {
+        return fetchline_readline();
+    } else {
+        return fetchline_fgets();
+    }
+}
 
 static void prep_fetchline(void *opaque)
 {
@@ -339,6 +337,11 @@ static void add_user_command(char *optarg)
     cmdline[ncmdline-1] = optarg;
 }
 
+static void reenable_tty_echo(void)
+{
+    qemu_set_tty_echo(STDIN_FILENO, true);
+}
+
 int main(int argc, char **argv)
 {
     int readonly = 0;
@@ -435,6 +438,15 @@ int main(int argc, char **argv)
     qemuio_add_command(&open_cmd);
     qemuio_add_command(&close_cmd);
 
+    if (isatty(STDIN_FILENO)) {
+        readline_state = readline_init(readline_printf_func,
+                                       readline_flush_func,
+                                       NULL,
+                                       readline_completion_func);
+        qemu_set_tty_echo(STDIN_FILENO, false);
+        atexit(reenable_tty_echo);
+    }
+
     /* open the device */
     if (!readonly) {
         flags |= BDRV_O_RDWR;
@@ -453,5 +465,6 @@ int main(int argc, char **argv)
     if (qemuio_bs) {
         bdrv_unref(qemuio_bs);
     }
+    g_free(readline_state);
     return 0;
 }
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH 5/5] qemu-io: add command completion
  2013-11-14 10:54 [Qemu-devel] [PATCH 0/5] qemu-io: readline command completion Stefan Hajnoczi
                   ` (3 preceding siblings ...)
  2013-11-14 10:54 ` [Qemu-devel] [PATCH 4/5] qemu-io: use readline.c Stefan Hajnoczi
@ 2013-11-14 10:54 ` Stefan Hajnoczi
  2013-11-28  1:28 ` [Qemu-devel] [PATCH 0/5] qemu-io: readline " Luiz Capitulino
  5 siblings, 0 replies; 10+ messages in thread
From: Stefan Hajnoczi @ 2013-11-14 10:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Stefan Hajnoczi, Luiz Capitulino

Autocomplete qemu-io commands at the interactive prompt.

Note this only completes command names and not their options.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 include/qemu-io.h |  3 +++
 qemu-io-cmds.c    | 15 +++++++++++++++
 qemu-io.c         |  8 +++++++-
 3 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/include/qemu-io.h b/include/qemu-io.h
index a418b46..7e7c07c 100644
--- a/include/qemu-io.h
+++ b/include/qemu-io.h
@@ -42,5 +42,8 @@ bool qemuio_command(BlockDriverState *bs, const char *cmd);
 
 void qemuio_add_command(const cmdinfo_t *ci);
 int qemuio_command_usage(const cmdinfo_t *ci);
+void qemuio_complete_command(const char *input,
+                             void (*fn)(const char *cmd, void *opaque),
+                             void *opaque);
 
 #endif /* QEMU_IO_H */
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index 667f4e4..30c23c2 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -94,6 +94,21 @@ static const cmdinfo_t *find_command(const char *cmd)
     return NULL;
 }
 
+/* Invoke fn() for commands with a matching prefix */
+void qemuio_complete_command(const char *input,
+                             void (*fn)(const char *cmd, void *opaque),
+                             void *opaque)
+{
+    cmdinfo_t *ct;
+    size_t input_len = strlen(input);
+
+    for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
+        if (strncmp(input, ct->name, input_len) == 0) {
+            fn(ct->name, opaque);
+        }
+    }
+}
+
 static char **breakline(char *input, int *count)
 {
     int c = 0;
diff --git a/qemu-io.c b/qemu-io.c
index d7c26d3..fdc46a9 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -236,9 +236,15 @@ static void readline_func(void *opaque, const char *str, void *readline_opaque)
     *line = g_strdup(str);
 }
 
+static void completion_match(const char *cmd, void *opaque)
+{
+    readline_add_completion(readline_state, cmd);
+}
+
 static void readline_completion_func(void *opaque, const char *str)
 {
-    /* No command or argument completion implemented yet */
+    readline_set_completion_index(readline_state, strlen(str));
+    qemuio_complete_command(str, completion_match, NULL);
 }
 
 static char *fetchline_readline(void)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH 0/5] qemu-io: readline command completion
  2013-11-14 10:54 [Qemu-devel] [PATCH 0/5] qemu-io: readline command completion Stefan Hajnoczi
                   ` (4 preceding siblings ...)
  2013-11-14 10:54 ` [Qemu-devel] [PATCH 5/5] qemu-io: add command completion Stefan Hajnoczi
@ 2013-11-28  1:28 ` Luiz Capitulino
  5 siblings, 0 replies; 10+ messages in thread
From: Luiz Capitulino @ 2013-11-28  1:28 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: Kevin Wolf, qemu-devel

On Thu, 14 Nov 2013 11:54:13 +0100
Stefan Hajnoczi <stefanha@redhat.com> wrote:

> This series decouples readline.c from the QEMU monitor and then reuses it in
> qemu-io.  This adds history and command completion to the qemu-io interactive
> prompt.

I don't know what's the state of this series, but I reviewed the HMP
parts in detail, and took a glance at the qemu-io parts:

Reviewed-by: Luiz Capitulino <lcapitulino@redhat.com>

> 
> Stefan Hajnoczi (5):
>   readline: decouple readline from the monitor
>   readline: move readline to a generic location
>   osdep: add qemu_set_tty_echo()
>   qemu-io: use readline.c
>   qemu-io: add command completion
> 
>  Makefile.objs              |   1 -
>  hmp.c                      |   6 +-
>  include/monitor/monitor.h  |   2 +-
>  include/monitor/readline.h |  56 -----
>  include/qemu-io.h          |   3 +
>  include/qemu/osdep.h       |   2 +
>  include/qemu/readline.h    |  62 ++++++
>  monitor.c                  |  41 +++-
>  qemu-io-cmds.c             |  15 ++
>  qemu-io.c                  | 109 +++++-----
>  readline.c                 | 493 --------------------------------------------
>  util/Makefile.objs         |   1 +
>  util/oslib-posix.c         |  18 ++
>  util/oslib-win32.c         |  19 ++
>  util/readline.c            | 495 +++++++++++++++++++++++++++++++++++++++++++++
>  15 files changed, 716 insertions(+), 607 deletions(-)
>  delete mode 100644 include/monitor/readline.h
>  create mode 100644 include/qemu/readline.h
>  delete mode 100644 readline.c
>  create mode 100644 util/readline.c
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH 3/5] osdep: add qemu_set_tty_echo()
  2013-11-14 10:54 ` [Qemu-devel] [PATCH 3/5] osdep: add qemu_set_tty_echo() Stefan Hajnoczi
@ 2013-11-29 10:04   ` Kevin Wolf
  2013-11-29 10:13     ` Kevin Wolf
  0 siblings, 1 reply; 10+ messages in thread
From: Kevin Wolf @ 2013-11-29 10:04 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: qemu-devel, Luiz Capitulino

Am 14.11.2013 um 11:54 hat Stefan Hajnoczi geschrieben:
> Using stdin with readline.c requires disabling echo and line buffering.
> Add a portable wrapper to set the terminal attributes under Linux and
> Windows.
> 
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>

There's already qemu_chr_fe_set_echo(). Can't we use that? Changing this
setting outside the context of a chardev feels wrong anyway.

Kevin

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH 3/5] osdep: add qemu_set_tty_echo()
  2013-11-29 10:04   ` Kevin Wolf
@ 2013-11-29 10:13     ` Kevin Wolf
  2013-12-02 14:23       ` Stefan Hajnoczi
  0 siblings, 1 reply; 10+ messages in thread
From: Kevin Wolf @ 2013-11-29 10:13 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: qemu-devel, Luiz Capitulino

Am 29.11.2013 um 11:04 hat Kevin Wolf geschrieben:
> Am 14.11.2013 um 11:54 hat Stefan Hajnoczi geschrieben:
> > Using stdin with readline.c requires disabling echo and line buffering.
> > Add a portable wrapper to set the terminal attributes under Linux and
> > Windows.
> > 
> > Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> 
> There's already qemu_chr_fe_set_echo(). Can't we use that? Changing this
> setting outside the context of a chardev feels wrong anyway.

Okay, I see, tools don't have chardevs, unfortunately. But can we avoid
duplication the other way round then, that is, let qemu-char.c use the
new functions? They don't seem to be exactly the same, so I'm not
completely sure if they are supposed to do different things or if they
are just buggy in different ways.

Kevin

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH 3/5] osdep: add qemu_set_tty_echo()
  2013-11-29 10:13     ` Kevin Wolf
@ 2013-12-02 14:23       ` Stefan Hajnoczi
  0 siblings, 0 replies; 10+ messages in thread
From: Stefan Hajnoczi @ 2013-12-02 14:23 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-devel, Luiz Capitulino

On Fri, Nov 29, 2013 at 11:13:41AM +0100, Kevin Wolf wrote:
> Am 29.11.2013 um 11:04 hat Kevin Wolf geschrieben:
> > Am 14.11.2013 um 11:54 hat Stefan Hajnoczi geschrieben:
> > > Using stdin with readline.c requires disabling echo and line buffering.
> > > Add a portable wrapper to set the terminal attributes under Linux and
> > > Windows.
> > > 
> > > Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> > 
> > There's already qemu_chr_fe_set_echo(). Can't we use that? Changing this
> > setting outside the context of a chardev feels wrong anyway.
> 
> Okay, I see, tools don't have chardevs, unfortunately. But can we avoid
> duplication the other way round then, that is, let qemu-char.c use the
> new functions? They don't seem to be exactly the same, so I'm not
> completely sure if they are supposed to do different things or if they
> are just buggy in different ways.

I didn't see a nice way of doing that.  The chardev approach is a little
different - it tries to restore termios on shutdown by stashing it in a
global variable.

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2013-12-02 14:23 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-11-14 10:54 [Qemu-devel] [PATCH 0/5] qemu-io: readline command completion Stefan Hajnoczi
2013-11-14 10:54 ` [Qemu-devel] [PATCH 1/5] readline: decouple readline from the monitor Stefan Hajnoczi
2013-11-14 10:54 ` [Qemu-devel] [PATCH 2/5] readline: move readline to a generic location Stefan Hajnoczi
2013-11-14 10:54 ` [Qemu-devel] [PATCH 3/5] osdep: add qemu_set_tty_echo() Stefan Hajnoczi
2013-11-29 10:04   ` Kevin Wolf
2013-11-29 10:13     ` Kevin Wolf
2013-12-02 14:23       ` Stefan Hajnoczi
2013-11-14 10:54 ` [Qemu-devel] [PATCH 4/5] qemu-io: use readline.c Stefan Hajnoczi
2013-11-14 10:54 ` [Qemu-devel] [PATCH 5/5] qemu-io: add command completion Stefan Hajnoczi
2013-11-28  1:28 ` [Qemu-devel] [PATCH 0/5] qemu-io: readline " Luiz Capitulino

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).