[cli] Add interactive mode.
authorMatthias Bolte <matthias.bolte@googlemail.com>
Fri, 10 Apr 2009 00:06:26 +0000 (02:06 +0200)
committerMatthias Bolte <matthias.bolte@googlemail.com>
Fri, 10 Apr 2009 00:09:20 +0000 (02:09 +0200)
Signed-off-by: Matthias Bolte <matthias.bolte@googlemail.com>

cli/Makefile
cli/core.c
cli/help.c
include/libvsccli/core.h
include/libvsccli/types.h

index 32e5c74..33ea178 100644 (file)
@@ -17,6 +17,9 @@ TARGET   = libvsccli.so
 # libvscmisc
 CFLAGS  += -I ../include
 
+# libreadline
+LDFLAGS += -lreadline
+
 #
 # Rules
 #
index c46b6a2..e292d75 100644 (file)
@@ -18,6 +18,9 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
  */
 
+#include <readline/readline.h>
+#include <readline/history.h>
+
 #include <libvscmisc/assert.h>
 #include <libvscmisc/error.h>
 #include <libvscmisc/memory.h>
@@ -36,6 +39,31 @@ const char *_vsc_cli_name = NULL;
 const char *_vsc_cli_help = NULL;
 const struct VscCliOptionInfo *_vsc_cli_option_infos = NULL;
 const struct VscCliCommandInfo **_vsc_cli_command_infos = NULL;
+int _vsc_cli_interactive = FALSE;
+
+static void
+_quit (struct VscError *error, const struct VscCliOption *option_list,
+       void *user_data);
+
+static const struct VscCliOptionInfo _quit_option_infos[] = {
+       { -1, NULL, NULL, 0, FALSE },
+};
+
+const struct VscCliCommandInfo vsc_cli_quit_command_info = {
+       "quit",
+       "quit interactive mode",
+       "",
+       _quit,
+       _quit_option_infos,
+};
+
+static void
+_quit (struct VscError *error VSC__ATTR__UNUSED,
+       const struct VscCliOption *option_list VSC__ATTR__UNUSED,
+       void *user_data VSC__ATTR__UNUSED)
+{
+       _vsc_cli_interactive = FALSE;
+}
 
 void
 vsc_cli_init (struct VscError *error,
@@ -67,6 +95,11 @@ vsc_cli_init (struct VscError *error,
        _vsc_cli_option_infos = option_infos;
        _vsc_cli_command_infos = command_infos;
 
+       rl_readline_name = "vscmgmt-cli";
+       /*rl_attempted_completion_function = _readline_completion;*/
+
+       stifle_history (500);
+
        _initialized = TRUE;
 }
 
@@ -90,12 +123,12 @@ vsc_cli_error_fprint (struct VscError *error, FILE *stream)
        } else {
                if (error->message != NULL) {
                        if (error->code == VSC__ERROR_CODE__REMOTE_ERROR) {
-                               fprintf (stream, "Error: Remote: %s\n", error->message);
+                               fprintf (stream, "\033[01;31mError\033[0m: Remote: %s\n", error->message);
                        } else {
-                               fprintf (stream, "Error: %s\n", error->message);
+                               fprintf (stream, "\033[01;31mError\033[0m: %s\n", error->message);
                        }
                } else {
-                       fprintf (stream, "Error: %s\n", vsc_error_string(error->code));
+                       fprintf (stream, "\033[01;31mError\033[0m: %s\n", vsc_error_string(error->code));
                }
        }
 }
@@ -211,3 +244,67 @@ vsc_cli_run_command_list (struct VscError *error,
                }
        }
 }
+
+void
+vsc_cli_enter_interactive (VscCliErrorFunction error_function,
+                           VscCliPromptFunction prompt_function,
+                           void *user_data)
+{
+       struct VscError error;
+       char *input = NULL;
+       char prompt[256];
+       const char *input_tail = NULL;
+       struct VscCliCommand *command_list = NULL;
+
+       VSC__ASSERT (error_function != NULL);
+       VSC__ASSERT (prompt_function != NULL);
+       VSC__ASSERT (_vsc_cli_command_info_lookup ("quit") != NULL);
+
+       vsc_error_init (&error);
+
+       _vsc_cli_interactive = TRUE;
+
+       while (_vsc_cli_interactive) {
+               prompt_function (prompt, 256, user_data);
+
+               input = readline (prompt);
+
+               if (input == NULL) {
+                       goto outer_cleanup;
+               }
+
+               if (*input == '\0') {
+                       goto inner_cleanup;
+               }
+
+               add_history (input);
+
+               command_list = vsc_cli_parse_command_list
+                                 (&error, input, &input_tail);
+
+               if (error.occured) {
+                       error_function (&error, user_data);
+                       goto inner_cleanup;
+               }
+
+               if (command_list != NULL) {
+                       vsc_cli_run_command_list (&error, command_list, user_data);
+
+                       if (error.occured) {
+                               error_function (&error, user_data);
+                               goto inner_cleanup;
+                       }
+               }
+
+inner_cleanup:
+               vsc_free (&input);
+               vsc_cli_command_list_free (&command_list);
+               vsc_error_cleanup (&error);
+               vsc_error_init (&error);
+       }
+
+outer_cleanup:
+       vsc_error_cleanup (&error);
+
+       _vsc_cli_interactive = FALSE;
+}
index 4b111b5..1135a7b 100644 (file)
@@ -32,6 +32,7 @@ extern const char *_vsc_cli_name;
 extern const char *_vsc_cli_help;
 extern const struct VscCliOptionInfo *_vsc_cli_option_infos;
 extern const struct VscCliCommandInfo **_vsc_cli_command_infos;
+extern int _vsc_cli_interactive;
 
 static void
 _help (struct VscError *error, const struct VscCliOption *option_list,
@@ -117,45 +118,50 @@ _help (struct VscError *error, const struct VscCliOption *option_list,
                        }
                }
        } else {
-               printf ("\033[1mNAME\033[0m\n");
-               printf ("       %s - %s\n", _vsc_cli_name, _vsc_cli_help);
-               printf ("\n");
+               if (! _vsc_cli_interactive) {
+                       printf ("\033[1mNAME\033[0m\n");
+                       printf ("       %s - %s\n", _vsc_cli_name, _vsc_cli_help);
+                       printf ("\n");
 
-               printf ("\033[1mSYNOPSIS\033[0m\n");
-               printf ("       %s", _vsc_cli_name);
+                       printf ("\033[1mSYNOPSIS\033[0m\n");
+                       printf ("       %s", _vsc_cli_name);
 
-               for (i = 0; _vsc_cli_option_infos[i].long_name != NULL; ++i) {
-                       option_info = &_vsc_cli_option_infos[i];
+                       for (i = 0; _vsc_cli_option_infos[i].long_name != NULL; ++i) {
+                               option_info = &_vsc_cli_option_infos[i];
 
-                       if (option_info->required) {
-                               printf (" %s", _vsc_cli_option_syntax (option_info, TRUE));
-                       } else {
-                               printf (" [%s]", _vsc_cli_option_syntax (option_info, TRUE));
+                               if (option_info->required) {
+                                       printf (" %s", _vsc_cli_option_syntax (option_info, TRUE));
+                               } else {
+                                       printf (" [%s]", _vsc_cli_option_syntax (option_info, TRUE));
+                               }
                        }
-               }
 
-               printf (" [<command>[, <command>]...]\n");
+                       printf (" [<command>[, <command>]...]\n");
 
-               if (_vsc_cli_option_infos[0].long_name != NULL) {
-                       printf ("\n");
-                       printf ("\033[1mOPTIONS\033[0m\n");
+                       if (_vsc_cli_option_infos[0].long_name != NULL) {
+                               printf ("\n");
+                               printf ("\033[1mOPTIONS\033[0m\n");
 
-                       for (i = 0; _vsc_cli_option_infos[i].long_name != NULL; ++i) {
-                               option_info = &_vsc_cli_option_infos[i];
+                               for (i = 0; _vsc_cli_option_infos[i].long_name != NULL; ++i) {
+                                       option_info = &_vsc_cli_option_infos[i];
 
-                               printf ("       %s\n"
-                                       "              %s\n",
-                                       _vsc_cli_option_syntax (option_info, FALSE),
-                                       option_info->help);
+                                       printf ("       %s\n"
+                                               "              %s\n",
+                                               _vsc_cli_option_syntax (option_info, FALSE),
+                                               option_info->help);
 
-                               if (_vsc_cli_option_infos[i + 1].long_name != NULL) {
-                                       printf ("\n");
+                                       if (_vsc_cli_option_infos[i + 1].long_name != NULL) {
+                                               printf ("\n");
+                                       }
                                }
                        }
                }
 
                if (_vsc_cli_command_infos[0]->name != NULL) {
-                       printf ("\n");
+                       if (! _vsc_cli_interactive) {
+                               printf ("\n");
+                       }
+
                        printf ("\033[1mCOMMANDS\033[0m\n");
 
                        for (i = 0; _vsc_cli_command_infos[i] != NULL; ++i) {
index 7c8b130..077bb22 100644 (file)
@@ -27,6 +27,8 @@
 extern "C" {
 #endif
 
+extern const struct VscCliCommandInfo vsc_cli_quit_command_info;
+
 void
 vsc_cli_init (struct VscError *error,
               const char *name, const char *help,
@@ -52,6 +54,11 @@ vsc_cli_run_command_list (struct VscError *error,
                           const struct VscCliCommand *command_list,
                           void *user_data);
 
+void
+vsc_cli_enter_interactive (VscCliErrorFunction error_function,
+                           VscCliPromptFunction prompt_function,
+                           void *user_data);
+
 #ifdef __cplusplus
 }
 #endif
index 7cf95ef..7fa7837 100644 (file)
@@ -34,6 +34,19 @@ enum VscCliOptionType {
        VSC_CLI__OPTION_TYPE__STRING,
 };
 
+struct VscCliOption;
+struct VscCliCommand;
+
+typedef void (*VscCliCommandFunction) (struct VscError *error,
+                                       const struct VscCliOption *option_list,
+                                       void *user_data);
+
+typedef void (*VscCliErrorFunction) (struct VscError *error,
+                                     void *user_data);
+
+typedef void (*VscCliPromptFunction) (char *prompt, size_t size,
+                                      void *user_data);
+
 struct VscCliOptionInfo {
        const char short_name;
        const char* long_name;
@@ -49,10 +62,6 @@ struct VscCliOption {
        int number;
 };
 
-typedef void (*VscCliCommandFunction) (struct VscError *error,
-                                       const struct VscCliOption *option_list,
-                                       void *user_data);
-
 struct VscCliCommandInfo {
        const char* name;
        const char* help;