summaryrefslogtreecommitdiff
path: root/cli/src/connections.c
diff options
context:
space:
mode:
authorJiří Klimeš <jklimes@redhat.com>2014-05-13 15:50:38 +0200
committerJiří Klimeš <jklimes@redhat.com>2014-06-04 09:47:37 +0200
commit03be41d4093c109af88a93321049829713b40d03 (patch)
tree52a12a6a495c0431c088ecaf0f6948a33a9bec39 /cli/src/connections.c
parentfd93fb9fb966038390053627b1ca86d65c6db399 (diff)
downloadNetworkManager-03be41d4093c109af88a93321049829713b40d03.tar.gz
cli/build: make libreadline a build-time dependency (bgo #729846)
and link nmcli against it. This simplifies code, makes sure that line editing capability is supported, and will allow using readline on other places too. https://bugzilla.gnome.org/show_bug.cgi?id=729846 https://bugzilla.redhat.com/show_bug.cgi?id=1007365
Diffstat (limited to 'cli/src/connections.c')
-rw-r--r--cli/src/connections.c256
1 files changed, 56 insertions, 200 deletions
diff --git a/cli/src/connections.c b/cli/src/connections.c
index 1129755b37..835a9728e7 100644
--- a/cli/src/connections.c
+++ b/cli/src/connections.c
@@ -30,6 +30,8 @@
#include <errno.h>
#include <signal.h>
#include <netinet/ether.h>
+#include <readline/readline.h>
+#include <readline/history.h>
#include <nm-client.h>
#include <nm-device-ethernet.h>
@@ -245,7 +247,7 @@ extern GMainLoop *loop;
static ArgsInfo args_info;
static guint progress_id = 0; /* ID of event source for displaying progress */
-/* for readline TAB completion */
+/* for readline TAB completion in editor */
typedef struct {
NmCli *nmc;
char *con_type;
@@ -5215,46 +5217,7 @@ error:
/*----------------------------------------------------------------------------*/
-
-typedef char *CPFunction ();
-typedef char **CPPFunction ();
-/* History entry struct copied from libreadline's history.h */
-typedef struct _hist_entry {
- char *line;
- char *timestamp;
- char *data;
-} HIST_ENTRY;
-
-typedef char * (*ReadLineFunc) (const char *);
-typedef void (*AddHistoryFunc) (const char *);
-typedef HIST_ENTRY** (*HistoryListFunc) (void);
-typedef int (*RlInsertTextFunc) (char *);
-typedef char ** (*RlCompletionMatchesFunc) (char *, CPFunction *);
-
-typedef struct {
- ReadLineFunc readline_func;
- AddHistoryFunc add_history_func;
- HistoryListFunc history_list_func;
- RlInsertTextFunc rl_insert_text_func;
- void **rl_startup_hook_x;
- RlCompletionMatchesFunc completion_matches_func;
- void **rl_attempted_completion_function_x;
- void **rl_completion_entry_function_x;
- char **rl_line_buffer_x;
- char **rl_prompt_x;
- int *rl_attempted_completion_over_x;
- int *rl_complete_with_tilde_expansion_x;
- int *rl_completion_append_character_x;
- const char **rl_completer_word_break_characters_x;
- void (*rl_free_line_state_func) (void);
- void (*rl_cleanup_after_signal_func) (void);
- void **rl_completion_display_matches_hook_x;
- void (*rl_display_match_list_func) (char **, int, int);
- void (*rl_forced_update_display_func) (void);
-} EditLibSymbols;
-
-static EditLibSymbols edit_lib_symbols;
-static char *pre_input_deftext;
+/* Functions for readline TAB completion in editor */
static void
uuid_display_hook (char **array, int len, int max_len)
@@ -5275,20 +5238,19 @@ uuid_display_hook (char **array, int len, int max_len)
max = strlen (id);
}
}
- edit_lib_symbols.rl_display_match_list_func (array, len, max_len + max + 3);
- edit_lib_symbols.rl_forced_update_display_func ();
+ rl_display_match_list (array, len, max_len + max + 3);
+ rl_forced_update_display ();
}
+static char *pre_input_deftext;
static int
set_deftext (void)
{
- if ( pre_input_deftext
- && edit_lib_symbols.rl_insert_text_func
- && edit_lib_symbols.rl_startup_hook_x) {
- edit_lib_symbols.rl_insert_text_func (pre_input_deftext);
+ if (pre_input_deftext && rl_startup_hook) {
+ rl_insert_text (pre_input_deftext);
g_free (pre_input_deftext);
pre_input_deftext = NULL;
- *edit_lib_symbols.rl_startup_hook_x = NULL;
+ rl_startup_hook = NULL;
}
return 0;
}
@@ -5433,7 +5395,7 @@ gen_property_names (char *text, int state)
NMSetting *setting = NULL;
char **valid_props = NULL;
char *ret = NULL;
- char *line = g_strdup (*edit_lib_symbols.rl_line_buffer_x);
+ const char *line = rl_line_buffer;
const char *setting_name;
char **strv = NULL;
const NameItem *valid_settings_arr;
@@ -5460,7 +5422,6 @@ gen_property_names (char *text, int state)
ret = gen_func_basic (text, state, (const char **) valid_props);
}
- g_free (line);
g_strfreev (strv);
g_strfreev (valid_props);
if (setting)
@@ -5707,6 +5668,9 @@ should_complete_vpn_uuids (const char *prompt, const char *line)
return found;
}
+/* from readline */
+extern int rl_complete_with_tilde_expansion;
+
/*
* Attempt to complete on the contents of TEXT. START and END show the
* region of TEXT that contains the word to complete. We can use the
@@ -5717,8 +5681,8 @@ static char **
nmcli_editor_tab_completion (char *text, int start, int end)
{
char **match_array = NULL;
- const char *line = *edit_lib_symbols.rl_line_buffer_x;
- const char *prompt = *edit_lib_symbols.rl_prompt_x;
+ const char *line = rl_line_buffer;
+ const char *prompt = rl_prompt;
CPFunction *generator_func = NULL;
gboolean copy_char;
const char *p1;
@@ -5728,16 +5692,16 @@ nmcli_editor_tab_completion (char *text, int start, int end)
int num;
/* Restore standard append character to space */
- *edit_lib_symbols.rl_completion_append_character_x = ' ';
+ rl_completion_append_character = ' ';
/* Restore standard function for displaying matches */
- *edit_lib_symbols.rl_completion_display_matches_hook_x = NULL;
+ rl_completion_display_matches_hook = NULL;
/* Disable default filename completion */
- *edit_lib_symbols.rl_attempted_completion_over_x = 1;
+ rl_attempted_completion_over = 1;
/* Enable tilde expansion when filenames are completed */
- *edit_lib_symbols.rl_complete_with_tilde_expansion_x = 1;
+ rl_complete_with_tilde_expansion = 1;
/* Filter out possible ANSI color escape sequences */
p1 = prompt;
@@ -5782,14 +5746,14 @@ nmcli_editor_tab_completion (char *text, int start, int end)
if (num < 3) {
if (level == 0 && (!dot || dot >= line + end)) {
generator_func = gen_setting_names;
- *edit_lib_symbols.rl_completion_append_character_x = '.';
+ rl_completion_append_character = '.';
} else
generator_func = gen_property_names;
} else if (num >= 3) {
if (num == 3 && should_complete_files (NULL, line))
- *edit_lib_symbols.rl_attempted_completion_over_x = 0;
+ rl_attempted_completion_over = 0;
if (should_complete_vpn_uuids (NULL, line)) {
- *edit_lib_symbols.rl_completion_display_matches_hook_x = uuid_display_hook;
+ rl_completion_display_matches_hook = uuid_display_hook;
generator_func = gen_vpn_uuids;
}
}
@@ -5798,7 +5762,7 @@ nmcli_editor_tab_completion (char *text, int start, int end)
&& num <= 2) {
if (level == 0 && (!dot || dot >= line + end)) {
generator_func = gen_setting_names;
- *edit_lib_symbols.rl_completion_append_character_x = '.';
+ rl_completion_append_character = '.';
} else
generator_func = gen_property_names;
} else if (should_complete_cmd (line, end, "nmcli", &num, &word)) {
@@ -5825,9 +5789,9 @@ nmcli_editor_tab_completion (char *text, int start, int end)
if ( should_complete_cmd (line, end, "add", &num, NULL)
|| should_complete_cmd (line, end, "set", &num, NULL)) {
if (num <= 2 && should_complete_files (prompt_tmp, line))
- *edit_lib_symbols.rl_attempted_completion_over_x = 0;
+ rl_attempted_completion_over = 0;
else if (should_complete_vpn_uuids (prompt_tmp, line)) {
- *edit_lib_symbols.rl_completion_display_matches_hook_x = uuid_display_hook;
+ rl_completion_display_matches_hook = uuid_display_hook;
generator_func = gen_vpn_uuids;
}
}
@@ -5840,129 +5804,39 @@ nmcli_editor_tab_completion (char *text, int start, int end)
}
if (generator_func)
- match_array = edit_lib_symbols.completion_matches_func (text, generator_func);
+ match_array = rl_completion_matches (text, generator_func);
g_free (prompt_tmp);
g_free (word);
return match_array;
}
-static GModule *
-load_cmd_line_edit_lib (void)
-{
- GModule *module = NULL;
- char *lib_path;
- int i;
- static const char * const edit_lib_table[] = {
- "libreadline.so.6", /* GNU Readline library version 6 - latest */
- "libreadline.so.5", /* GNU Readline library version 5 - previous */
- "libedit.so.0", /* NetBSD Editline library port (http://www.thrysoee.dk/editline/) */
- };
-
- /* Try to load a library for line editing */
- for (i = 0; i < G_N_ELEMENTS (edit_lib_table); i++) {
- lib_path = g_module_build_path (NULL, edit_lib_table[i]);
- module = g_module_open (lib_path, G_MODULE_BIND_LOCAL);
- g_free (lib_path);
- if (module)
- break;
- }
- if (!module)
- return NULL;
-
- if (!g_module_symbol (module, "readline", (gpointer) (&edit_lib_symbols.readline_func)))
- goto error;
- if (!g_module_symbol (module, "add_history", (gpointer) (&edit_lib_symbols.add_history_func)))
- goto error;
- if (!g_module_symbol (module, "history_list", (gpointer) (&edit_lib_symbols.history_list_func)))
- goto error;
- if (!g_module_symbol (module, "rl_insert_text", (gpointer) (&edit_lib_symbols.rl_insert_text_func)))
- goto error;
- if (!g_module_symbol (module, "rl_startup_hook", (gpointer) (&edit_lib_symbols.rl_startup_hook_x)))
- goto error;
- if (!g_module_symbol (module, "rl_attempted_completion_function",
- (gpointer) (&edit_lib_symbols.rl_attempted_completion_function_x)))
- goto error;
- if (!g_module_symbol (module, "completion_matches",
- (gpointer) (&edit_lib_symbols.completion_matches_func)))
- goto error;
- if (!g_module_symbol (module, "rl_line_buffer",
- (gpointer) (&edit_lib_symbols.rl_line_buffer_x)))
- goto error;
- if (!g_module_symbol (module, "rl_prompt",
- (gpointer) (&edit_lib_symbols.rl_prompt_x)))
- goto error;
- if (!g_module_symbol (module, "rl_attempted_completion_over",
- (gpointer) (&edit_lib_symbols.rl_attempted_completion_over_x)))
- goto error;
- if (!g_module_symbol (module, "rl_complete_with_tilde_expansion",
- (gpointer) (&edit_lib_symbols.rl_complete_with_tilde_expansion_x)))
- goto error;
- if (!g_module_symbol (module, "rl_completion_append_character",
- (gpointer) (&edit_lib_symbols.rl_completion_append_character_x)))
- goto error;
- if (!g_module_symbol (module, "rl_completer_word_break_characters",
- (gpointer) (&edit_lib_symbols.rl_completer_word_break_characters_x)))
- goto error;
- if (!g_module_symbol (module, "rl_free_line_state",
- (gpointer) (&edit_lib_symbols.rl_free_line_state_func)))
- goto error;
- if (!g_module_symbol (module, "rl_cleanup_after_signal",
- (gpointer) (&edit_lib_symbols.rl_cleanup_after_signal_func)))
- goto error;
- if (!g_module_symbol (module, "rl_completion_display_matches_hook",
- (gpointer) (&edit_lib_symbols.rl_completion_display_matches_hook_x)))
- goto error;
- if (!g_module_symbol (module, "rl_display_match_list",
- (gpointer) (&edit_lib_symbols.rl_display_match_list_func)))
- goto error;
- if (!g_module_symbol (module, "rl_forced_update_display",
- (gpointer) (&edit_lib_symbols.rl_forced_update_display_func)))
- goto error;
-
- /* Set a pointer to an alternative function to create matches */
- *edit_lib_symbols.rl_attempted_completion_function_x = (CPPFunction *) nmcli_editor_tab_completion;
-
- /* Use ' ' and '.' as word break characters */
- *edit_lib_symbols.rl_completer_word_break_characters_x = ". ";
-
- return module;
-error:
- g_module_close (module);
- return NULL;
-}
-
void
nmc_cleanup_readline (void)
{
- if (edit_lib_symbols.rl_free_line_state_func)
- edit_lib_symbols.rl_free_line_state_func ();
- if (edit_lib_symbols.rl_cleanup_after_signal_func)
- edit_lib_symbols.rl_cleanup_after_signal_func ();
+ rl_free_line_state ();
+ rl_cleanup_after_signal ();
}
+/* Reads data from user and adds it to history */
static char *
-readline_x (const char *prompt)
+readline_x (const char *prompt, gboolean add_to_history)
{
char *str;
- if (edit_lib_symbols.readline_func) {
- str = edit_lib_symbols.readline_func (prompt);
- /* Return NULL, not empty string */
- if (str && *str == '\0') {
- g_free (str);
- str = NULL;
- }
- } else
- str = nmc_get_user_input (prompt);
+ str = readline (prompt);
+ /* Return NULL, not empty string */
+ if (str && *str == '\0') {
+ g_free (str);
+ str = NULL;
+ }
- if (edit_lib_symbols.add_history_func && str && *str)
- edit_lib_symbols.add_history_func (str);
+ if (add_to_history && str && *str)
+ add_history (str);
return str;
}
-
#define NMCLI_EDITOR_HISTORY ".nmcli-history"
static void
@@ -5975,10 +5849,6 @@ load_history_cmds (const char *uuid)
size_t i;
GError *err = NULL;
- /* Nothing to do if readline library is not used */
- if (!edit_lib_symbols.add_history_func)
- return;
-
filename = g_build_filename (g_get_home_dir (), NMCLI_EDITOR_HISTORY, NULL);
kf = g_key_file_new ();
if (!g_key_file_load_from_file (kf, filename, G_KEY_FILE_KEEP_COMMENTS, &err)) {
@@ -5992,7 +5862,7 @@ load_history_cmds (const char *uuid)
for (i = 0; keys && keys[i]; i++) {
line = g_key_file_get_string (kf, uuid, keys[i], NULL);
if (line && *line)
- edit_lib_symbols.add_history_func (line);
+ add_history (line);
g_free (line);
}
g_strfreev (keys);
@@ -6012,9 +5882,7 @@ save_history_cmds (const char *uuid)
gsize len = 0;
GError *err = NULL;
- if (edit_lib_symbols.history_list_func)
- hist = edit_lib_symbols.history_list_func();
-
+ hist = history_list ();
if (hist) {
filename = g_build_filename (g_get_home_dir (), NMCLI_EDITOR_HISTORY, NULL);
kf = g_key_file_new ();
@@ -6645,7 +6513,7 @@ property_edit_submenu (NmCli *nmc,
if (nmc->editor_status_line)
editor_show_status_line (connection, dirty, temp_changes);
- cmd_property_user = readline_x (prompt);
+ cmd_property_user = readline_x (prompt, TRUE);
if (!cmd_property_user || *cmd_property_user == '\0')
continue;
cmdsub = parse_editor_sub_cmd (g_strstrip (cmd_property_user), &cmd_property_arg);
@@ -6659,7 +6527,7 @@ property_edit_submenu (NmCli *nmc,
*/
if (!cmd_property_arg) {
tmp_prompt = g_strdup_printf (_("Enter '%s' value: "), prop_name);
- prop_val_user = readline_x (tmp_prompt);
+ prop_val_user = readline_x (tmp_prompt, TRUE);
g_free (tmp_prompt);
} else
prop_val_user = g_strdup (cmd_property_arg);
@@ -6685,10 +6553,10 @@ property_edit_submenu (NmCli *nmc,
break;
case NMC_EDITOR_SUB_CMD_CHANGE:
- *edit_lib_symbols.rl_startup_hook_x = set_deftext;
+ rl_startup_hook = set_deftext;
pre_input_deftext = nmc_setting_get_property_out2in (curr_setting, prop_name, NULL);
tmp_prompt = g_strdup_printf (_("Edit '%s' value: "), prop_name);
- prop_val_user = readline_x (tmp_prompt);
+ prop_val_user = readline_x (tmp_prompt, TRUE);
nmc_property_get_gvalue (curr_setting, prop_name, &prop_g_value);
nmc_property_set_default_value (curr_setting, prop_name);
@@ -6876,7 +6744,7 @@ ask_check_setting (const char *arg,
if (!arg) {
printf (_("Available settings: %s\n"), valid_settings_str);
- setting_name_user = nmc_get_user_input (EDITOR_PROMPT_SETTING);
+ setting_name_user = readline_x (EDITOR_PROMPT_SETTING, TRUE);
} else
setting_name_user = g_strdup (arg);
@@ -6902,7 +6770,7 @@ ask_check_property (const char *arg,
if (!arg) {
printf (_("Available properties: %s\n"), valid_props_str);
- prop_name_user = readline_x (EDITOR_PROMPT_PROPERTY);
+ prop_name_user = readline_x (EDITOR_PROMPT_PROPERTY, TRUE);
if (prop_name_user)
g_strstrip (prop_name_user);
} else
@@ -7046,7 +6914,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
editor_show_status_line (connection, dirty, temp_changes);
/* Read user input */
- cmd_user = readline_x (menu_ctx.main_prompt);
+ cmd_user = readline_x (menu_ctx.main_prompt, TRUE);
/* Get the remote connection again, it may have disapeared */
removed = refresh_remote_connection (&weak, &rem_con);
@@ -7084,7 +6952,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
printf (_("Allowed values for '%s' property: %s\n"), prop_name, avals);
tmp_prompt = g_strdup_printf (_("Enter '%s' value: "), prop_name);
- prop_val_user = readline_x (tmp_prompt);
+ prop_val_user = readline_x (tmp_prompt, TRUE);
g_free (tmp_prompt);
/* Set property value */
@@ -7142,7 +7010,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
printf (_("Allowed values for '%s' property: %s\n"), prop_name, avals);
tmp_prompt = g_strdup_printf (_("Enter '%s' value: "), prop_name);
- cmd_arg_v = readline_x (tmp_prompt);
+ cmd_arg_v = readline_x (tmp_prompt, TRUE);
g_free (tmp_prompt);
}
@@ -7833,7 +7701,6 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
char *tmp_str;
GError *error = NULL;
GError *err1 = NULL;
- GModule *edit_lib_module = NULL;
nmc_arg_t exp_args[] = { {"type", TRUE, &type, FALSE},
{"con-name", TRUE, &con_name, FALSE},
{"id", TRUE, &con_id, FALSE},
@@ -7854,19 +7721,11 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
}
}
- /* Load line editing library */
- if (!(edit_lib_module = load_cmd_line_edit_lib ())) {
- printf (_(">>> Command-line editing is not available. "
- "Consider installing a line editing library to enable the feature. <<<\n"
- "Supported libraries are:\n"
- " - GNU Readline (libreadline) http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html\n"
- " - NetBSD Editline (libedit) http://www.thrysoee.dk/editline/\n"));
- edit_lib_symbols.readline_func = NULL;
- edit_lib_symbols.add_history_func = NULL;
- edit_lib_symbols.history_list_func = NULL;
- edit_lib_symbols.rl_insert_text_func = NULL;
- edit_lib_symbols.rl_startup_hook_x = NULL;
- }
+ /* Setup some readline completion stuff */
+ /* Set a pointer to an alternative function to create matches */
+ rl_attempted_completion_function = (CPPFunction *) nmcli_editor_tab_completion;
+ /* Use ' ' and '.' as word break characters */
+ rl_completer_word_break_characters = ". ";
if (!con) {
if (con_id && !con_uuid && !con_path) {
@@ -7931,7 +7790,7 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
printf (_("Error: invalid connection type; %s\n"), err1->message);
g_clear_error (&err1);
- type_ask = readline_x (EDITOR_PROMPT_CON_TYPE);
+ type_ask = readline_x (EDITOR_PROMPT_CON_TYPE, TRUE);
type = type_ask = type_ask ? g_strstrip (type_ask) : NULL;
connection_type = check_valid_name (type_ask, nmc_valid_connection_types, &err1);
g_free (type_ask);
@@ -7984,9 +7843,6 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
/* Run menu loop */
editor_menu_main (nmc, connection, connection_type);
- if (edit_lib_module)
- g_module_close (edit_lib_module);
-
if (connection)
g_object_unref (connection);
g_free (nmc_tab_completion.con_type);