Commit 55949277 authored by Jiří Klimeš's avatar Jiří Klimeš

cli: changing nmcli output to better fit both computer and human needs

The output is basically tabular with fields (columns) presenting specific pieces of info.
Each line represents a single object. It's possible to switch to multiline output using
'--multiline' option. In that mode single object is presented on more lines - each field
on its line.
Terse mode now uses ':' as field separator. It also escapes all occurences of ':' and '\'
inside field values to ease parsing. The escaping behaviour can be controlled through
'--escape' option. By default, escaping is switched on in tabular mode. When using terse
mode ('--terse'), '--fields' option is mandatory for specifying required fields. That helps
for flexibility and backwards compatibility.
Not all output is converted yet.
parent 15351042
......@@ -53,6 +53,37 @@
#include "connections.h"
/* Available field for 'con status' */
static NmcOutputField nmc_fields_con_status[] = {
{"NAME", N_("NAME"), 25, NULL, 0}, /* 0 */
{"UUID", N_("UUID"), 38, NULL, 0}, /* 1 */
{"DEVICES", N_("DEVICES"), 10, NULL, 0}, /* 2 */
{"SCOPE", N_("SCOPE"), 8, NULL, 0}, /* 3 */
{"DEFAULT", N_("DEFAULT"), 8, NULL, 0}, /* 4 */
{"DBUS-SERVICE", N_("DBUS-SERVICE"), 45, NULL, 0}, /* 5 */
{"SPEC-OBJECT", N_("SPEC-OBJECT"), 10, NULL, 0}, /* 6 */
{"VPN", N_("VPN"), 5, NULL, 0}, /* 7 */
{NULL, NULL, 0, NULL, 0}
};
#define NMC_FIELDS_CON_STATUS_ALL "NAME,UUID,DEVICES,SCOPE,DEFAULT,VPN,DBUS-SERVICE,SPEC-OBJECT"
#define NMC_FIELDS_CON_STATUS_COMMON "NAME,UUID,DEVICES,SCOPE,DEFAULT,VPN"
/* Available field for 'con list' */
static NmcOutputField nmc_fields_con_list[] = {
{"NAME", N_("NAME"), 25, NULL, 0}, /* 0 */
{"UUID", N_("UUID"), 38, NULL, 0}, /* 1 */
{"TYPE", N_("TYPE"), 17, NULL, 0}, /* 2 */
{"SCOPE", N_("SCOPE"), 8, NULL, 0}, /* 3 */
{"TIMESTAMP", N_("TIMESTAMP"), 12, NULL, 0}, /* 4 */
{"TIMESTAMP-REAL", N_("TIMESTAMP-REAL"), 34, NULL, 0}, /* 5 */
{"AUTOCONNECT", N_("AUTOCONNECT"), 13, NULL, 0}, /* 6 */
{"READONLY", N_("READONLY"), 10, NULL, 0}, /* 7 */
{NULL, NULL, 0, NULL, 0}
};
#define NMC_FIELDS_CON_LIST_ALL "NAME,UUID,TYPE,SCOPE,TIMESTAMP,TIMESTAMP-REAL,AUTOCONNECT,READONLY"
#define NMC_FIELDS_CON_LIST_COMMON "NAME,UUID,TYPE,SCOPE,TIMESTAMP-REAL"
typedef struct {
NmCli *nmc;
int argc;
......@@ -102,17 +133,31 @@ static void
show_connection (NMConnection *data, gpointer user_data)
{
NMConnection *connection = (NMConnection *) data;
NmCli *nmc = (NmCli *) user_data;
NMSettingConnection *s_con;
const char *id;
const char *uuid;
const char *con_type;
guint64 timestamp;
char *timestamp_str;
char timestamp_real_str[64];
s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
if (s_con) {
id = nm_setting_connection_get_id (s_con);
uuid = nm_setting_connection_get_uuid (s_con);
con_type = nm_setting_connection_get_connection_type (s_con);
print_table_line (0, con_type, 17, uuid, 38, id, 0, NULL);
/* Obtain field values */
timestamp = nm_setting_connection_get_timestamp (s_con);
timestamp_str = g_strdup_printf ("%ld", timestamp);
strftime (timestamp_real_str, sizeof (timestamp_real_str), "%c", localtime ((time_t *) &timestamp));
nmc->allowed_fields[0].value = nm_setting_connection_get_id (s_con);
nmc->allowed_fields[1].value = nm_setting_connection_get_uuid (s_con);
nmc->allowed_fields[2].value = nm_setting_connection_get_connection_type (s_con);
nmc->allowed_fields[3].value = nm_connection_get_scope (connection) == NM_CONNECTION_SCOPE_SYSTEM ? _("system") : _("user");
nmc->allowed_fields[4].value = timestamp_str;
nmc->allowed_fields[5].value = timestamp ? timestamp_real_str : _("never");
nmc->allowed_fields[6].value = nm_setting_connection_get_autoconnect (s_con) ? _("yes") : _("no");
nmc->allowed_fields[7].value = nm_setting_connection_get_read_only (s_con) ? _("yes") : _("no");
nmc->print_fields.flags &= ~NMC_PF_FLAG_HEADER; /* Clear HEADER flag */
print_fields (nmc->print_fields, nmc->allowed_fields);
g_free (timestamp_str);
}
}
......@@ -148,24 +193,46 @@ find_connection (GSList *list, const char *filter_type, const char *filter_val)
static NMCResultCode
do_connections_list (NmCli *nmc, int argc, char **argv)
{
GError *error = NULL;
char *fields_str;
char *fields_all = NMC_FIELDS_CON_LIST_ALL;
char *fields_common = NMC_FIELDS_CON_LIST_COMMON;
guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
gboolean valid_param_specified = FALSE;
nmc->should_wait = FALSE;
if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
fields_str = fields_common;
else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0)
fields_str = fields_all;
else
fields_str = nmc->required_fields;
nmc->allowed_fields = nmc_fields_con_list;
nmc->print_fields.indices = parse_output_fields (fields_str, nmc->allowed_fields, &error);
if (error) {
g_string_printf (nmc->return_text, error->message);
g_error_free (error);
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
goto error;
}
if (argc == 0) {
valid_param_specified = TRUE;
if (nmc->print_output == NMC_PRINT_PRETTY)
print_table_header (_("Connections"), _("Type"), 17, _("UUID"), 38, _("Name"), 20, NULL);
else if (nmc->print_output == NMC_PRINT_NORMAL)
print_table_line (0, _("Type"), 17, _("UUID"), 38, _("Name"), 0, NULL);
if (nmc->print_output > NMC_PRINT_TERSE)
printf (_("System connections:\n"));
g_slist_foreach (nmc->system_connections, (GFunc) show_connection, NULL);
if (nmc->print_output > NMC_PRINT_TERSE)
printf (_("User connections:\n"));
g_slist_foreach (nmc->user_connections, (GFunc) show_connection, NULL);
nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_HEADER;
nmc->print_fields.header_name = _("System connections");
print_fields (nmc->print_fields, nmc->allowed_fields);
g_slist_foreach (nmc->system_connections, (GFunc) show_connection, nmc);
nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_HEADER;
nmc->print_fields.header_name = _("User connections");
print_fields (nmc->print_fields, nmc->allowed_fields);
g_slist_foreach (nmc->user_connections, (GFunc) show_connection, nmc);
}
else {
while (argc > 0) {
......@@ -189,24 +256,25 @@ do_connections_list (NmCli *nmc, int argc, char **argv)
g_string_printf (nmc->return_text, _("Error: %s - no such connection."), *argv);
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
}
break;
}
else if (strcmp (*argv, "system") == 0) {
valid_param_specified = TRUE;
if (nmc->print_output == NMC_PRINT_PRETTY)
print_table_header (_("System-wide connections"), _("Type"), 17, _("UUID"), 38, _("Name"), 20, NULL);
else if (nmc->print_output == NMC_PRINT_NORMAL)
print_table_line (0, _("Type"), 17, _("UUID"), 38, _("Name"), 0, NULL);
g_slist_foreach (nmc->system_connections, (GFunc) show_connection, NULL);
nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_HEADER;
nmc->print_fields.header_name = _("System connections");
print_fields (nmc->print_fields, nmc->allowed_fields);
g_slist_foreach (nmc->system_connections, (GFunc) show_connection, nmc);
break;
}
else if (strcmp (*argv, "user") == 0) {
valid_param_specified = TRUE;
if (nmc->print_output == NMC_PRINT_PRETTY)
print_table_header (_("User connections"), _("Type"), 17, _("UUID"), 38, _("Name"), 20, NULL);
else if (nmc->print_output == NMC_PRINT_NORMAL)
print_table_line (0, _("Type"), 17, _("UUID"), 38, _("Name"), 0, NULL);
g_slist_foreach (nmc->user_connections, (GFunc) show_connection, NULL);
nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_HEADER;
nmc->print_fields.header_name = _("User connections");
print_fields (nmc->print_fields, nmc->allowed_fields);
g_slist_foreach (nmc->user_connections, (GFunc) show_connection, nmc);
break;
}
else {
fprintf (stderr, _("Unknown parameter: %s\n"), *argv);
......@@ -226,12 +294,17 @@ error:
return nmc->return_value;
}
typedef struct {
NmCli *nmc;
NMConnectionScope scope;
} StatusInfo;
static void
show_active_connection (gpointer data, gpointer user_data)
{
NMActiveConnection *active = NM_ACTIVE_CONNECTION (data);
GSList *con_list = (GSList *) user_data;
GSList *iter;
StatusInfo *info = (StatusInfo *) user_data;
GSList *con_list, *iter;
const char *active_path;
NMConnectionScope active_service_scope;
NMSettingConnection *s_con;
......@@ -239,12 +312,14 @@ show_active_connection (gpointer data, gpointer user_data)
GString *dev_str;
int i;
dev_str = g_string_new (NULL);
active_path = nm_active_connection_get_connection (active);
active_service_scope = nm_active_connection_get_scope (active);
if (active_service_scope != info->scope)
return;
/* Get devices of the active connection */
dev_str = g_string_new (NULL);
devices = nm_active_connection_get_devices (active);
for (i = 0; devices && (i < devices->len); i++) {
NMDevice *device = g_ptr_array_index (devices, i);
......@@ -255,24 +330,29 @@ show_active_connection (gpointer data, gpointer user_data)
if (dev_str->len > 0)
g_string_truncate (dev_str, dev_str->len - 1); /* Cut off last ',' */
con_list = (info->scope == NM_CONNECTION_SCOPE_SYSTEM) ? info->nmc->system_connections : info->nmc->user_connections;
for (iter = con_list; iter; iter = g_slist_next (iter)) {
NMConnection *connection = (NMConnection *) iter->data;
const char *con_path = nm_connection_get_path (connection);
NMConnectionScope con_scope = nm_connection_get_scope (connection);
if (!strcmp (active_path, con_path) && active_service_scope == con_scope) {
/* this connection is active */
if (!strcmp (active_path, con_path)) {
/* This connection is active */
s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
g_assert (s_con != NULL);
// FIXME: Fix the output
print_table_line (0, nm_active_connection_get_default (active) ? _("yes") : _("no"), 8,
nm_active_connection_get_service_name (active), 45,
// nm_active_connection_get_specific_object (active), 0,
// nm_active_connection_get_connection (active), 0,
dev_str->str, 10,
nm_setting_connection_get_uuid (s_con), 38,
nm_setting_connection_get_id (s_con), 0, NULL);
/* Obtain field values */
info->nmc->allowed_fields[0].value = nm_setting_connection_get_id (s_con);
info->nmc->allowed_fields[1].value = nm_setting_connection_get_uuid (s_con);
info->nmc->allowed_fields[2].value = dev_str->str;
info->nmc->allowed_fields[3].value = active_service_scope == NM_CONNECTION_SCOPE_SYSTEM ? _("system") : _("user");
info->nmc->allowed_fields[4].value = nm_active_connection_get_default (active) ? _("yes") : _("no");
info->nmc->allowed_fields[5].value = nm_active_connection_get_service_name (active);
info->nmc->allowed_fields[6].value = nm_active_connection_get_specific_object (active);
info->nmc->allowed_fields[7].value = NM_IS_VPN_CONNECTION (active) ? _("yes") : _("no");
info->nmc->print_fields.flags &= ~NMC_PF_FLAG_HEADER; /* Clear HEADER flag */
print_fields (info->nmc->print_fields, info->nmc->allowed_fields);
break;
}
}
......@@ -283,6 +363,14 @@ static NMCResultCode
do_connections_status (NmCli *nmc, int argc, char **argv)
{
const GPtrArray *active_cons;
GError *error = NULL;
StatusInfo *info;
char *fields_str;
char *fields_all = NMC_FIELDS_CON_STATUS_ALL;
char *fields_common = NMC_FIELDS_CON_STATUS_COMMON;
guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
nmc->should_wait = FALSE;
......@@ -292,18 +380,40 @@ do_connections_status (NmCli *nmc, int argc, char **argv)
active_cons = nm_client_get_active_connections (nmc->client);
// FIXME: Fix the output
if (nmc->print_output == NMC_PRINT_PRETTY)
print_table_header (_("Active connections"), _("Default"), 8, _("Service"), 45, _("Devices"), 10, _("UUID"), 38, _("Name"), 20, NULL);
else if (nmc->print_output == NMC_PRINT_NORMAL)
print_table_line (0, _("Default"), 8, _("Service"), 45, _("Devices"), 10, _("UUID"), 38, _("Name"), 0, NULL);
if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
fields_str = fields_common;
else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0)
fields_str = fields_all;
else
fields_str = nmc->required_fields;
nmc->allowed_fields = nmc_fields_con_status;
nmc->print_fields.indices = parse_output_fields (fields_str, nmc->allowed_fields, &error);
if (error) {
g_string_printf (nmc->return_text, error->message);
g_error_free (error);
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
goto error;
}
nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_HEADER;
nmc->print_fields.header_name = _("Active connections");
print_fields (nmc->print_fields, nmc->allowed_fields);
if (active_cons && active_cons->len) {
g_ptr_array_foreach ((GPtrArray *) active_cons, show_active_connection, (gpointer) nmc->system_connections);
g_ptr_array_foreach ((GPtrArray *) active_cons, show_active_connection, (gpointer) nmc->user_connections);
info = g_malloc0 (sizeof (StatusInfo));
info->nmc = nmc;
info->scope = NM_CONNECTION_SCOPE_SYSTEM;
g_ptr_array_foreach ((GPtrArray *) active_cons, show_active_connection, (gpointer) info);
info->scope = NM_CONNECTION_SCOPE_USER;
g_ptr_array_foreach ((GPtrArray *) active_cons, show_active_connection, (gpointer) info);
g_free (info);
}
return NMC_RESULT_SUCCESS;
error:
return nmc->return_value;
}
/* --------------------
......
This diff is collapsed.
......@@ -45,7 +45,7 @@
#include "devices.h"
#include "network-manager.h"
#define NMCLI_VERSION "0.1"
#define NMCLI_VERSION "0.2"
typedef struct {
......@@ -64,10 +64,13 @@ usage (const char *prog_name)
fprintf (stderr,
_("Usage: %s [OPTIONS] OBJECT { COMMAND | help }\n\n"
"OPTIONS\n"
" -t[erse] terse output\n"
" -p[retty] pretty output\n"
" -v[ersion] show program version\n"
" -h[elp] print this help\n\n"
" -t[erse] terse output\n"
" -p[retty] pretty output\n"
" -m[ultiline] multiline output\n"
" -f[ields] <field1,field2,...>|all|common specify fields to output\n"
" -e[scape] yes|no escape columns separators in values\n"
" -v[ersion] show program version\n"
" -h[elp] print this help\n\n"
"OBJECT\n"
" nm NetworkManager status\n"
" con NetworkManager connections\n"
......@@ -132,9 +135,57 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
if (opt[1] == '-')
opt++;
if (matches (opt, "-terse") == 0) {
nmc->print_output = NMC_PRINT_TERSE;
if (nmc->print_output == NMC_PRINT_TERSE) {
g_string_printf (nmc->return_text, _("Option '--terse' is specified the second time."));
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
return nmc->return_value;
}
else if (nmc->print_output == NMC_PRINT_PRETTY) {
g_string_printf (nmc->return_text, _("Option '--terse' is mutually exclusive with '--pretty'."));
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
return nmc->return_value;
}
else
nmc->print_output = NMC_PRINT_TERSE;
} else if (matches (opt, "-pretty") == 0) {
nmc->print_output = NMC_PRINT_PRETTY;
if (nmc->print_output == NMC_PRINT_PRETTY) {
g_string_printf (nmc->return_text, _("Option '--pretty' is specified the second time."));
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
return nmc->return_value;
}
else if (nmc->print_output == NMC_PRINT_TERSE) {
g_string_printf (nmc->return_text, _("Option '--pretty' is mutually exclusive with '--terse'."));
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
return nmc->return_value;
}
else
nmc->print_output = NMC_PRINT_PRETTY;
} else if (matches (opt, "-multiline") == 0) {
nmc->multiline_output = TRUE;
} else if (matches (opt, "-escape") == 0) {
next_arg (&argc, &argv);
if (argc <= 1) {
g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt);
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
return nmc->return_value;
}
if (!strcmp (argv[1], "yes"))
nmc->escape_values = TRUE;
else if (!strcmp (argv[1], "no"))
nmc->escape_values = FALSE;
else {
g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), argv[1], opt);
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
return nmc->return_value;
}
} else if (matches (opt, "-fields") == 0) {
next_arg (&argc, &argv);
if (argc <= 1) {
g_string_printf (nmc->return_text, _("Error: fields for '%s' options are missing."), opt);
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
return nmc->return_value;
}
nmc->required_fields = g_strdup (argv[1]);
} else if (matches (opt, "-version") == 0) {
printf (_("nmcli tool, version %s\n"), NMCLI_VERSION);
return NMC_RESULT_SUCCESS;
......@@ -150,6 +201,20 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
argv++;
}
/* Some validity options checks */
if (nmc->print_output == NMC_PRINT_TERSE) {
if (!nmc->required_fields) {
g_string_printf (nmc->return_text, _("Option '--terse' requires specifying '--fields'."));
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
return nmc->return_value;
} else if ( !strcasecmp (nmc->required_fields, "all")
|| !strcasecmp (nmc->required_fields, "common")) {
g_string_printf (nmc->return_text, _("Option '--terse' requires specific '--fields' option, not 'all' or 'common'."));
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
return nmc->return_value;
}
}
if (argc > 1)
return do_cmd (nmc, argv[1], argc-1, argv+1);
......@@ -217,6 +282,11 @@ nmc_init (NmCli *nmc)
nmc->should_wait = FALSE;
nmc->print_output = NMC_PRINT_NORMAL;
nmc->multiline_output = FALSE;
nmc->escape_values = TRUE;
nmc->required_fields = NULL;
nmc->allowed_fields = NULL;
memset (&nmc->print_fields, '\0', sizeof (NmcPrintFields));
}
static void
......@@ -231,6 +301,10 @@ nmc_cleanup (NmCli *nmc)
g_slist_free (nmc->system_connections);
g_slist_free (nmc->user_connections);
g_free (nmc->required_fields);
if (nmc->print_fields.indices)
g_array_free (nmc->print_fields.indices, TRUE);
}
static gboolean
......
......@@ -20,10 +20,12 @@
#ifndef NMC_NMCLI_H
#define NMC_NMCLI_H
#include <glib.h>
#include <nm-client.h>
#include <nm-remote-settings.h>
#include <nm-remote-settings-system.h>
/* nmcli exit codes */
typedef enum {
/* Indicates successful execution */
......@@ -51,27 +53,55 @@ typedef enum {
NMC_PRINT_PRETTY
} NMCPrintOutput;
/* === Output fields === */
typedef struct {
const char *name; /* Field's name */
const char *name_l10n; /* Field's name for translation */
int width; /* Width in screen columns */
const char *value; /* Value of current field */
guint32 flags; /* Flags */
} NmcOutputField;
/* Flags for NmcPrintFields */
#define NMC_PF_FLAG_MULTILINE 0x00000001 /* Multiline output instead of tabular*/
#define NMC_PF_FLAG_TERSE 0x00000002 /* Terse outpud mode */
#define NMC_PF_FLAG_PRETTY 0x00000004 /* Pretty output mode */
#define NMC_PF_FLAG_HEADER 0x00000008 /* Print headers instead of values */
#define NMC_PF_FLAG_ESCAPE 0x00000010 /* Escape column separator and '\' */
typedef struct {
GArray *indices; /* Array of field indices to the array of allowed fields */
char *header_name; /* Name of the output */
int indent; /* Indent by this number of spaces */
guint32 flags; /* Various flags for controlling output: see NMC_PF_FLAG_* values */
} NmcPrintFields;
/* NmCli - main structure */
typedef struct _NmCli {
NMClient *client;
NMClient *(*get_client) (struct _NmCli *nmc);
NMClient *client; /* Pointer to NMClient of libnm-glib */
NMClient *(*get_client) (struct _NmCli *nmc); /* Pointer to function for creating NMClient */
NMCResultCode return_value;
GString *return_text;
NMCResultCode return_value; /* Return code of nmcli */
GString *return_text; /* Reason text */
int timeout;
int timeout; /* Operation timeout */
NMRemoteSettingsSystem *system_settings;
NMRemoteSettings *user_settings;
NMRemoteSettingsSystem *system_settings; /* System settings */
NMRemoteSettings *user_settings; /* User settings */
gboolean system_settings_running;
gboolean user_settings_running;
gboolean system_settings_running; /* Is system settings service running? */
gboolean user_settings_running; /* Is user settings service running? */
GSList *system_connections;
GSList *user_connections;
GSList *system_connections; /* List of system connections */
GSList *user_connections; /* List of user connections */
gboolean should_wait;
NMCPrintOutput print_output;
gboolean should_wait; /* Indication that nmcli should not end yet */
NMCPrintOutput print_output; /* Output mode */
gboolean multiline_output; /* Multiline output instead of default tabular */
gboolean escape_values; /* Whether to escape ':' and '\' in terse tabular mode */
char *required_fields; /* Required fields in output: '--fields' option */
NmcOutputField *allowed_fields; /* Array of allowed fields for particular commands */
NmcPrintFields print_fields; /* Structure with field indices to print */
} NmCli;
#endif /* NMC_NMCLI_H */
......@@ -21,6 +21,7 @@
#include <string.h>
#include <glib.h>
#include <glib/gi18n.h>
#include "utils.h"
......@@ -46,6 +47,171 @@ next_arg (int *argc, char ***argv)
return 0;
}
/*
* Parse comma separated fields in 'fields_str' according to 'fields_array'.
* IN: 'field_str': comma-separated fields names
* 'fields_array': array of allowed fields
* RETURN: GArray with indices representing fields in 'fields_array'.
*/
GArray *
parse_output_fields (const char *fields_str, const NmcOutputField fields_array[], GError **error)
{
char **fields, **iter;
GArray *array;
int i;
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
array = g_array_new (FALSE, FALSE, sizeof (int));
/* Split supplied fields string */
fields = g_strsplit_set (fields_str, ",", -1);
for (iter = fields; iter && *iter; iter++) {
for (i = 0; fields_array[i].name; i++) {
if (strcasecmp (*iter, fields_array[i].name) == 0) {
g_array_append_val (array, i);
break;
}
}
if (fields_array[i].name == NULL) {
if (!strcasecmp (*iter, "all") || !strcasecmp (*iter, "common"))
g_set_error (error, 0, 0, _("Error: 'con status': field '%s' has to be alone."), *iter);
else
g_set_error (error, 0, 0, _("Error: 'con status': invalid field '%s'."), *iter);
g_array_free (array, TRUE);
array = NULL;
goto done;
}
}
done:
return array;
}
void
print_fields (const NmcPrintFields fields, const NmcOutputField field_values[])
{
GString *str;
int width1, width2;
int table_width = 0;
char *line = NULL;
char *indent_str;
const char *value;
int i, idx;
gboolean multiline = fields.flags & NMC_PF_FLAG_MULTILINE;
gboolean terse = fields.flags & NMC_PF_FLAG_TERSE;
gboolean pretty = fields.flags & NMC_PF_FLAG_PRETTY;
gboolean header = fields.flags & NMC_PF_FLAG_HEADER;
gboolean escape = fields.flags & NMC_PF_FLAG_ESCAPE;
/* Headers are not printed in terse mode */
if (header && terse)
return;
if (multiline) {
/* --- Multiline mode --- */
if (header && pretty) {
/* Print the table header */
table_width = g_utf8_strlen (fields.header_name, -1) + 4;
line = g_strnfill (79, '=');
width1 = strlen (fields.header_name);
width2 = g_utf8_strlen (fields.header_name, -1);
printf ("%s\n", line);
printf ("%*s\n", (table_width + width2)/2 + width1 - width2, fields.header_name);
printf ("%s\n", line);
g_free (line);
}
/* Print values */
if (!header) {
for (i = 0; i < fields.indices->len; i++) {
char *tmp;
idx = g_array_index (fields.indices, int, i);
tmp = g_strdup_printf ("%s:", _(field_values[idx].name_l10n));
printf ("%-*s%s\n", terse ? 0 : 20, tmp, field_values[idx].value);
g_free (tmp);
}
if (pretty) {
line = g_strnfill (79, '-');
printf ("%s\n", line);
g_free (line);
}
}
return;
}