mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-06 00:20:16 +01:00
cli: implement new nmc_print() command to generically output cli data
We already have
- data sources (nm_cli, connections or settings)
- meta data information how to access the data sources (NMMetaAbstractInfo,
NmcMetaGenericInfo, NMMetaPropertyInfo)
Add now a generic way to output cli data using nmc_print(). It gets a
list of data-sources (@targets) and a list of available fields (meta
data). It also gets cli configuration (NmcConfig) and field selector
strings (@field_str).
Based on that, it should output the desired data.
This is intended to replaces the previous approach, where functions like
show_nm_status() have full knowledge about how to access the data and
create an intermediate output format (NmcOutputData, NmcOutputField)
that was printed via print_data().
show_nm_status() contained both knowledge about the data itself (how to
print a value) and intimate knoweledge about the output intermediate
format. Also, the intermediate format is hard to understand. For
example, sometimes we put the field prefix in NmcOutputField at index 0
and via the NmcOfFlags we control how to output the data.
Clearly separate the responsibilities.
- The meta data (NmcMetaGenericInfo) is only concerned with converting
a data source to a string (or a color format).
- the field selection (@field_str) only cares about parsing the list
of NMMetaAbstractInfo.
- _print_fill() populates a table with output values and header
entries.
- _print_do() prints the previously prepared table.
The advantage is that if you want to change anything, you only need to
touch a particular part.
This is only a show-case for `nmcli general status`. Parts are still
un-implemented and will follow.
This changes behavior for --terse mode: the values are now no longer
translated:
$ LANG=de_DE.utf8 nmcli -t --mode multiline general
This commit is contained in:
parent
e79174ca89
commit
fdd40b6a68
7 changed files with 964 additions and 239 deletions
|
|
@ -1391,8 +1391,8 @@ split_required_fields_for_con_show (const char *input,
|
|||
else if (!strcasecmp (*iter, CON_SHOW_DETAIL_GROUP_ACTIVE))
|
||||
group_active = TRUE;
|
||||
else {
|
||||
char *allowed1 = nmc_get_allowed_fields ((const NMMetaAbstractInfo *const*) nm_meta_setting_infos_editor_p ());
|
||||
char *allowed2 = nmc_get_allowed_fields ((const NMMetaAbstractInfo *const*) nmc_fields_con_active_details_groups);
|
||||
char *allowed1 = nmc_get_allowed_fields ((const NMMetaAbstractInfo *const*) nm_meta_setting_infos_editor_p (), NULL);
|
||||
char *allowed2 = nmc_get_allowed_fields ((const NMMetaAbstractInfo *const*) nmc_fields_con_active_details_groups, NULL);
|
||||
g_set_error (error, NMCLI_ERROR, 0, _("invalid field '%s'; allowed fields: %s and %s, or %s,%s"),
|
||||
*iter, allowed1, allowed2, CON_SHOW_DETAIL_GROUP_PROFILE, CON_SHOW_DETAIL_GROUP_ACTIVE);
|
||||
g_free (allowed1);
|
||||
|
|
|
|||
|
|
@ -108,20 +108,107 @@ connectivity_to_color (NMConnectivityState connectivity)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static const NmcMetaGenericInfo *const nmc_fields_nm_status[] = {
|
||||
NMC_META_GENERIC ("RUNNING"), /* 0 */
|
||||
NMC_META_GENERIC ("VERSION"), /* 1 */
|
||||
NMC_META_GENERIC ("STATE"), /* 2 */
|
||||
NMC_META_GENERIC ("STARTUP"), /* 3 */
|
||||
NMC_META_GENERIC ("CONNECTIVITY"), /* 4 */
|
||||
NMC_META_GENERIC ("NETWORKING"), /* 5 */
|
||||
NMC_META_GENERIC ("WIFI-HW"), /* 6 */
|
||||
NMC_META_GENERIC ("WIFI"), /* 7 */
|
||||
NMC_META_GENERIC ("WWAN-HW"), /* 8 */
|
||||
NMC_META_GENERIC ("WWAN"), /* 9 */
|
||||
NMC_META_GENERIC ("WIMAX-HW"), /* 10 */
|
||||
NMC_META_GENERIC ("WIMAX"), /* 11 */
|
||||
NULL,
|
||||
static const NmcMetaGenericInfo *const metagen_general_status[];
|
||||
|
||||
static gconstpointer
|
||||
_metagen_general_status_get_fcn (const NMMetaEnvironment *environment,
|
||||
gpointer environment_user_data,
|
||||
const NmcMetaGenericInfo *info,
|
||||
gpointer target,
|
||||
NMMetaAccessorGetType get_type,
|
||||
NMMetaAccessorGetFlags get_flags,
|
||||
gpointer *out_to_free)
|
||||
{
|
||||
NmCli *nmc = target;
|
||||
const char *value;
|
||||
gboolean v_bool;
|
||||
NMState state;
|
||||
NMConnectivityState connectivity;
|
||||
|
||||
#define HANDLE_TERMFORMAT(color) \
|
||||
G_STMT_START { \
|
||||
if (get_type == NM_META_ACCESSOR_GET_TYPE_TERMFORMAT) \
|
||||
return nm_meta_termformat_pack ((color), NM_META_TERM_FORMAT_NORMAL); \
|
||||
} G_STMT_END
|
||||
|
||||
switch (info->info_type) {
|
||||
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_RUNNING:
|
||||
HANDLE_TERMFORMAT (NM_META_TERM_COLOR_NORMAL);
|
||||
value = N_("running");
|
||||
goto translate_and_out;
|
||||
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_VERSION:
|
||||
HANDLE_TERMFORMAT (NM_META_TERM_COLOR_NORMAL);
|
||||
value = nm_client_get_version (nmc->client);
|
||||
goto clone_and_out;
|
||||
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_STATE:
|
||||
state = nm_client_get_state (nmc->client);
|
||||
HANDLE_TERMFORMAT (state_to_color (state));
|
||||
value = nm_state_to_string_no_l10n (state);
|
||||
goto translate_and_out;
|
||||
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_STARTUP:
|
||||
v_bool = nm_client_get_startup (nmc->client);
|
||||
HANDLE_TERMFORMAT (v_bool ? NM_META_TERM_COLOR_YELLOW : NM_META_TERM_COLOR_GREEN);
|
||||
value = v_bool ? N_("starting") : N_("started");
|
||||
goto translate_and_out;
|
||||
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_CONNECTIVITY:
|
||||
connectivity = nm_client_get_connectivity (nmc->client);
|
||||
HANDLE_TERMFORMAT (connectivity_to_color (connectivity));
|
||||
value = nm_connectivity_to_string_no_l10n (connectivity);
|
||||
goto translate_and_out;
|
||||
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_NETWORKING:
|
||||
v_bool = nm_client_networking_get_enabled (nmc->client);
|
||||
goto enabled_out;
|
||||
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIFI_HW:
|
||||
v_bool = nm_client_wireless_hardware_get_enabled (nmc->client);
|
||||
goto enabled_out;
|
||||
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIFI:
|
||||
v_bool = nm_client_wireless_get_enabled (nmc->client);
|
||||
goto enabled_out;
|
||||
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WWAN_HW:
|
||||
v_bool = nm_client_wwan_hardware_get_enabled (nmc->client);
|
||||
goto enabled_out;
|
||||
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WWAN:
|
||||
v_bool = nm_client_wwan_get_enabled (nmc->client);
|
||||
goto enabled_out;
|
||||
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIMAX_HW:
|
||||
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIMAX:
|
||||
/* deprected fields. Don't return anything. */
|
||||
return NULL;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
g_return_val_if_reached (NULL);
|
||||
|
||||
enabled_out:
|
||||
HANDLE_TERMFORMAT (v_bool ? NM_META_TERM_COLOR_GREEN : NM_META_TERM_COLOR_RED);
|
||||
value = v_bool ? N_("enabled") : N_("disabled");
|
||||
goto translate_and_out;
|
||||
|
||||
clone_and_out:
|
||||
return (*out_to_free = g_strdup (value));
|
||||
|
||||
translate_and_out:
|
||||
if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY)
|
||||
return _(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
static const NmcMetaGenericInfo *const metagen_general_status[_NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_NUM + 1] = {
|
||||
#define _METAGEN_GENERAL_STATUS(type, name) \
|
||||
[type] = NMC_META_GENERIC(name, .info_type = type, .get_fcn = _metagen_general_status_get_fcn)
|
||||
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_RUNNING, "RUNNING"),
|
||||
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_VERSION, "VERSION"),
|
||||
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_STATE, "STATE"),
|
||||
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_STARTUP, "STARTUP"),
|
||||
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_CONNECTIVITY, "CONNECTIVITY"),
|
||||
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_NETWORKING, "NETWORKING"),
|
||||
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIFI_HW, "WIFI-HW"),
|
||||
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIFI, "WIFI"),
|
||||
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WWAN_HW, "WWAN-HW"),
|
||||
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WWAN, "WWAN"),
|
||||
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIMAX_HW, "WIMAX-HW"),
|
||||
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIMAX, "WIMAX"),
|
||||
};
|
||||
#define NMC_FIELDS_NM_STATUS_ALL "RUNNING,VERSION,STATE,STARTUP,CONNECTIVITY,NETWORKING,WIFI-HW,WIFI,WWAN-HW,WWAN"
|
||||
#define NMC_FIELDS_NM_STATUS_SWITCH "NETWORKING,WIFI-HW,WIFI,WWAN-HW,WWAN"
|
||||
|
|
@ -306,19 +393,10 @@ quit (void)
|
|||
static gboolean
|
||||
show_nm_status (NmCli *nmc, const char *pretty_header_name, const char *print_flds)
|
||||
{
|
||||
gboolean startup = FALSE;
|
||||
NMState state = NM_STATE_UNKNOWN;
|
||||
NMConnectivityState connectivity = NM_CONNECTIVITY_UNKNOWN;
|
||||
gboolean net_enabled;
|
||||
gboolean wireless_hw_enabled, wireless_enabled;
|
||||
gboolean wwan_hw_enabled, wwan_enabled;
|
||||
GError *error = NULL;
|
||||
gs_free_error GError *error = NULL;
|
||||
const char *fields_str;
|
||||
const char *fields_all = print_flds ? print_flds : NMC_FIELDS_NM_STATUS_ALL;
|
||||
const char *fields_common = print_flds ? print_flds : NMC_FIELDS_NM_STATUS_COMMON;
|
||||
const NMMetaAbstractInfo *const*tmpl;
|
||||
NmcOutputField *arr;
|
||||
NMC_OUTPUT_DATA_DEFINE_SCOPED (out);
|
||||
|
||||
if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
|
||||
fields_str = fields_common;
|
||||
|
|
@ -327,57 +405,16 @@ show_nm_status (NmCli *nmc, const char *pretty_header_name, const char *print_fl
|
|||
else
|
||||
fields_str = nmc->required_fields;
|
||||
|
||||
tmpl = (const NMMetaAbstractInfo *const*) nmc_fields_nm_status;
|
||||
out_indices = parse_output_fields (fields_str, tmpl, FALSE, NULL, &error);
|
||||
|
||||
if (error) {
|
||||
if (!nmc_print (&nmc->nmc_config,
|
||||
(gpointer[]) { nmc, NULL },
|
||||
pretty_header_name ?: N_("NetworkManager status"),
|
||||
(const NMMetaAbstractInfo *const*) metagen_general_status,
|
||||
fields_str,
|
||||
&error)) {
|
||||
g_string_printf (nmc->return_text, _("Error: only these fields are allowed: %s"), fields_all);
|
||||
g_error_free (error);
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
state = nm_client_get_state (nmc->client);
|
||||
startup = nm_client_get_startup (nmc->client);
|
||||
connectivity = nm_client_get_connectivity (nmc->client);
|
||||
net_enabled = nm_client_networking_get_enabled (nmc->client);
|
||||
wireless_hw_enabled = nm_client_wireless_hardware_get_enabled (nmc->client);
|
||||
wireless_enabled = nm_client_wireless_get_enabled (nmc->client);
|
||||
wwan_hw_enabled = nm_client_wwan_hardware_get_enabled (nmc->client);
|
||||
wwan_enabled = nm_client_wwan_get_enabled (nmc->client);
|
||||
|
||||
arr = nmc_dup_fields_array (tmpl, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES);
|
||||
g_ptr_array_add (out.output_data, arr);
|
||||
|
||||
arr = nmc_dup_fields_array (tmpl, 0);
|
||||
set_val_strc (arr, 0, _("running"));
|
||||
set_val_strc (arr, 1, nm_client_get_version (nmc->client));
|
||||
set_val_strc (arr, 2, nm_state_to_string (state));
|
||||
set_val_strc (arr, 3, startup ? _("starting") : _("started"));
|
||||
set_val_strc (arr, 4, nm_connectivity_to_string (connectivity));
|
||||
set_val_strc (arr, 5, net_enabled ? _("enabled") : _("disabled"));
|
||||
set_val_strc (arr, 6, wireless_hw_enabled ? _("enabled") : _("disabled"));
|
||||
set_val_strc (arr, 7, wireless_enabled ? _("enabled") : _("disabled"));
|
||||
set_val_strc (arr, 8, wwan_hw_enabled ? _("enabled") : _("disabled"));
|
||||
set_val_strc (arr, 9, wwan_enabled ? _("enabled") : _("disabled"));
|
||||
|
||||
/* Set colors */
|
||||
arr[2].color = state_to_color (state);
|
||||
arr[3].color = startup ? NM_META_TERM_COLOR_YELLOW : NM_META_TERM_COLOR_GREEN;
|
||||
arr[4].color = connectivity_to_color (connectivity);
|
||||
arr[5].color = net_enabled ? NM_META_TERM_COLOR_GREEN : NM_META_TERM_COLOR_RED;
|
||||
arr[6].color = wireless_hw_enabled ? NM_META_TERM_COLOR_GREEN : NM_META_TERM_COLOR_RED;
|
||||
arr[7].color = wireless_enabled ? NM_META_TERM_COLOR_GREEN : NM_META_TERM_COLOR_RED;
|
||||
arr[8].color = wwan_hw_enabled ? NM_META_TERM_COLOR_GREEN : NM_META_TERM_COLOR_RED;
|
||||
arr[9].color = wwan_enabled ? NM_META_TERM_COLOR_GREEN : NM_META_TERM_COLOR_RED;
|
||||
|
||||
g_ptr_array_add (out.output_data, arr);
|
||||
|
||||
print_data_prepare_width (out.output_data);
|
||||
print_data (&nmc->nmc_config, out_indices,
|
||||
pretty_header_name ?: _("NetworkManager status"),
|
||||
0, &out);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -860,7 +897,7 @@ do_networking_connectivity (NmCli *nmc, int argc, char **argv)
|
|||
|
||||
if (!argc) {
|
||||
/* no arguments -> get current state */
|
||||
nmc_switch_show (nmc, NMC_FIELDS_NM_CONNECTIVITY, _("Connectivity"));
|
||||
nmc_switch_show (nmc, NMC_FIELDS_NM_CONNECTIVITY, N_("Connectivity"));
|
||||
} else if (matches (*argv, "check")) {
|
||||
gs_free_error GError *error = NULL;
|
||||
|
||||
|
|
@ -872,7 +909,7 @@ do_networking_connectivity (NmCli *nmc, int argc, char **argv)
|
|||
g_string_printf (nmc->return_text, _("Error: %s."), error->message);
|
||||
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
|
||||
} else
|
||||
nmc_switch_show (nmc, NMC_FIELDS_NM_CONNECTIVITY, _("Connectivity"));
|
||||
nmc_switch_show (nmc, NMC_FIELDS_NM_CONNECTIVITY, N_("Connectivity"));
|
||||
} else {
|
||||
usage_networking ();
|
||||
g_string_printf (nmc->return_text, _("Error: 'networking' command '%s' is not valid."), *argv);
|
||||
|
|
@ -889,7 +926,7 @@ do_networking_show (NmCli *nmc, int argc, char **argv)
|
|||
if (nmc->complete)
|
||||
return nmc->return_value;
|
||||
|
||||
nmc_switch_show (nmc, NMC_FIELDS_NM_NETWORKING, _("Networking"));
|
||||
nmc_switch_show (nmc, NMC_FIELDS_NM_NETWORKING, N_("Networking"));
|
||||
|
||||
return nmc->return_value;
|
||||
}
|
||||
|
|
@ -924,7 +961,7 @@ do_radio_all (NmCli *nmc, int argc, char **argv)
|
|||
return nmc->return_value;
|
||||
|
||||
/* no argument, show all radio switches */
|
||||
show_nm_status (nmc, _("Radio switches"), NMC_FIELDS_NM_STATUS_RADIO);
|
||||
show_nm_status (nmc, N_("Radio switches"), NMC_FIELDS_NM_STATUS_RADIO);
|
||||
} else {
|
||||
if (nmc->complete) {
|
||||
if (argc == 1)
|
||||
|
|
@ -954,7 +991,7 @@ do_radio_wifi (NmCli *nmc, int argc, char **argv)
|
|||
return nmc->return_value;
|
||||
|
||||
/* no argument, show current WiFi state */
|
||||
nmc_switch_show (nmc, NMC_FIELDS_NM_WIFI, _("Wi-Fi radio switch"));
|
||||
nmc_switch_show (nmc, NMC_FIELDS_NM_WIFI, N_("Wi-Fi radio switch"));
|
||||
} else {
|
||||
if (nmc->complete) {
|
||||
if (argc == 1)
|
||||
|
|
@ -981,7 +1018,7 @@ do_radio_wwan (NmCli *nmc, int argc, char **argv)
|
|||
return nmc->return_value;
|
||||
|
||||
/* no argument, show current WWAN (mobile broadband) state */
|
||||
nmc_switch_show (nmc, NMC_FIELDS_NM_WWAN, _("WWAN radio switch"));
|
||||
nmc_switch_show (nmc, NMC_FIELDS_NM_WWAN, N_("WWAN radio switch"));
|
||||
} else {
|
||||
if (nmc->complete) {
|
||||
if (argc == 1)
|
||||
|
|
|
|||
|
|
@ -79,10 +79,19 @@ _meta_type_nmc_generic_info_get_fcn (const NMMetaEnvironment *environment,
|
|||
{
|
||||
const NmcMetaGenericInfo *info = (const NmcMetaGenericInfo *) abstract_info;
|
||||
|
||||
nm_assert (out_to_free && !*out_to_free);
|
||||
nm_assert (!out_to_free || !*out_to_free);
|
||||
|
||||
if (!info->get_fcn)
|
||||
g_return_val_if_reached (NULL);
|
||||
if (!NM_IN_SET (get_type,
|
||||
NM_META_ACCESSOR_GET_TYPE_PARSABLE,
|
||||
NM_META_ACCESSOR_GET_TYPE_PRETTY,
|
||||
NM_META_ACCESSOR_GET_TYPE_TERMFORMAT))
|
||||
g_return_val_if_reached (NULL);
|
||||
|
||||
/* omitting the out_to_free value is only allowed for TERMFORMAT. */
|
||||
nm_assert (out_to_free || NM_IN_SET (get_type, NM_META_ACCESSOR_GET_TYPE_TERMFORMAT));
|
||||
|
||||
return info->get_fcn (environment, environment_user_data,
|
||||
info, target,
|
||||
get_type, get_flags,
|
||||
|
|
@ -733,26 +742,185 @@ nmc_free_output_field_values (NmcOutputField fields_array[])
|
|||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
guint idx;
|
||||
gsize offset_plus_1;
|
||||
gsize self_offset_plus_1;
|
||||
gsize sub_offset_plus_1;
|
||||
} OutputSelectionItem;
|
||||
|
||||
NmcOutputSelection *
|
||||
nmc_output_selection_create (const NMMetaAbstractInfo *const* fields_array,
|
||||
const char *fields_str,
|
||||
GError **error)
|
||||
static NmcOutputSelection *
|
||||
_output_selection_pack (const NMMetaAbstractInfo *const* fields_array,
|
||||
GArray *array,
|
||||
GString *str)
|
||||
{
|
||||
NmcOutputSelection *result;
|
||||
guint i;
|
||||
guint len;
|
||||
|
||||
len = array ? array->len : 0;
|
||||
|
||||
/* re-organize the collected output data in one buffer that can be freed using
|
||||
* g_free(). This makes allocation more complicated, but saves us from special
|
||||
* handling for free. */
|
||||
result = g_malloc0 (sizeof (NmcOutputSelection) + (len * sizeof (NmcOutputSelectionItem)) + (str ? str->len : 0));
|
||||
*((guint *) &result->num) = len;
|
||||
if (len > 0) {
|
||||
char *pdata = &((char *) result)[sizeof (NmcOutputSelection) + (len * sizeof (NmcOutputSelectionItem))];
|
||||
|
||||
if (str)
|
||||
memcpy (pdata, str->str, str->len);
|
||||
for (i = 0; i < len; i++) {
|
||||
const OutputSelectionItem *a = &g_array_index (array, OutputSelectionItem, i);
|
||||
NmcOutputSelectionItem *p = (NmcOutputSelectionItem *) &result->items[i];
|
||||
|
||||
p->info = fields_array[a->idx];
|
||||
p->idx = a->idx;
|
||||
if (a->self_offset_plus_1 > 0)
|
||||
p->self_selection = &pdata[a->self_offset_plus_1 - 1];
|
||||
if (a->sub_offset_plus_1 > 0)
|
||||
p->sub_selection = &pdata[a->sub_offset_plus_1 - 1];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_output_selection_select_one (const NMMetaAbstractInfo *const* fields_array,
|
||||
const char *fields_prefix,
|
||||
const char *fields_str,
|
||||
gboolean validate_nested,
|
||||
GArray **p_array,
|
||||
GString **p_str,
|
||||
GError **error)
|
||||
{
|
||||
guint i, j;
|
||||
const char *i_name;
|
||||
const char *right;
|
||||
gboolean found = FALSE;
|
||||
const NMMetaAbstractInfo *fields_array_failure = NULL;
|
||||
gs_free char *fields_str_clone = NULL;
|
||||
|
||||
nm_assert (fields_str);
|
||||
nm_assert (p_array);
|
||||
nm_assert (p_str);
|
||||
nm_assert (!error || !*error);
|
||||
|
||||
right = strchr (fields_str, '.');
|
||||
if (right) {
|
||||
fields_str_clone = g_strdup (fields_str);
|
||||
fields_str_clone[right - fields_str] = '\0';
|
||||
i_name = fields_str_clone;
|
||||
right = &fields_str_clone[right - fields_str + 1];
|
||||
} else
|
||||
i_name = fields_str;
|
||||
|
||||
if (!fields_array)
|
||||
goto not_found;
|
||||
|
||||
for (i = 0; fields_array[i]; i++) {
|
||||
const NMMetaAbstractInfo *fi = fields_array[i];
|
||||
|
||||
if (g_ascii_strcasecmp (i_name, nm_meta_abstract_info_get_name (fi)) != 0)
|
||||
continue;
|
||||
|
||||
if (!right || !validate_nested) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (fi->meta_type == &nm_meta_type_setting_info_editor) {
|
||||
const NMMetaSettingInfoEditor *fi_s = &fi->as.setting_info;
|
||||
|
||||
for (j = 1; j < fi_s->properties_num; j++) {
|
||||
if (g_ascii_strcasecmp (right, fi_s->properties[j].property_name) == 0) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (fi->meta_type == &nmc_meta_type_generic_info) {
|
||||
const NmcMetaGenericInfo *fi_g = (const NmcMetaGenericInfo *) fi;
|
||||
|
||||
for (j = 0; fi_g->nested && fi_g->nested[j]; j++) {
|
||||
if (g_ascii_strcasecmp (right, nm_meta_abstract_info_get_name ((const NMMetaAbstractInfo *) fi_g->nested[j])) == 0) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fields_array_failure = fields_array[i];
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
not_found:
|
||||
if ( !right
|
||||
&& !fields_prefix
|
||||
&& ( !g_ascii_strcasecmp (i_name, "all")
|
||||
|| !g_ascii_strcasecmp (i_name, "common")))
|
||||
g_set_error (error, NMCLI_ERROR, 0, _("field '%s' has to be alone"), i_name);
|
||||
else {
|
||||
gs_free char *allowed_fields = NULL;
|
||||
|
||||
if (fields_array_failure) {
|
||||
gs_free char *p = NULL;
|
||||
|
||||
if (fields_prefix) {
|
||||
p = g_strdup_printf ("%s.%s", fields_prefix,
|
||||
nm_meta_abstract_info_get_name (fields_array_failure));
|
||||
}
|
||||
allowed_fields = nmc_get_allowed_fields_nested (fields_array_failure, p);
|
||||
} else
|
||||
allowed_fields = nmc_get_allowed_fields (fields_array, NULL);
|
||||
|
||||
g_set_error (error, NMCLI_ERROR, 1, _("invalid field '%s%s%s%s%s'; %s%s%s"),
|
||||
fields_prefix ?: "", fields_prefix ? "." : "",
|
||||
i_name, right ? "." : "", right ?: "",
|
||||
NM_PRINT_FMT_QUOTED (allowed_fields, "allowed fields: ", allowed_fields, "", "no fields"));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
{
|
||||
GString *str;
|
||||
OutputSelectionItem s = {
|
||||
.idx = i,
|
||||
};
|
||||
|
||||
if (!*p_str)
|
||||
*p_str = g_string_sized_new (64);
|
||||
str = *p_str;
|
||||
|
||||
s.self_offset_plus_1 = str->len + 1;
|
||||
if (fields_prefix) {
|
||||
g_string_append (str, fields_prefix);
|
||||
g_string_append_c (str, '.');
|
||||
}
|
||||
g_string_append_len (str, i_name, strlen (i_name) + 1);
|
||||
|
||||
if (right) {
|
||||
s.sub_offset_plus_1 = str->len + 1;
|
||||
g_string_append_len (str, right, strlen (right) + 1);
|
||||
}
|
||||
|
||||
if (!*p_array)
|
||||
*p_array = g_array_new (FALSE, FALSE, sizeof (OutputSelectionItem));
|
||||
g_array_append_val (*p_array, s);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static NmcOutputSelection *
|
||||
_output_selection_create_all (const NMMetaAbstractInfo *const* fields_array)
|
||||
{
|
||||
gs_unref_array GArray *array = NULL;
|
||||
nm_auto_free_gstring GString *str = NULL;
|
||||
guint i, j;
|
||||
NmcOutputSelection *result;
|
||||
guint i;
|
||||
|
||||
g_return_val_if_fail (!error || !*error, NULL);
|
||||
|
||||
array = g_array_new (FALSE, FALSE, sizeof (OutputSelectionItem));
|
||||
|
||||
if (!fields_str) {
|
||||
if (fields_array) {
|
||||
array = g_array_new (FALSE, FALSE, sizeof (OutputSelectionItem));
|
||||
for (i = 0; fields_array[i]; i++) {
|
||||
OutputSelectionItem s = {
|
||||
.idx = i,
|
||||
|
|
@ -760,131 +928,220 @@ nmc_output_selection_create (const NMMetaAbstractInfo *const* fields_array,
|
|||
|
||||
g_array_append_val (array, s);
|
||||
}
|
||||
} else {
|
||||
gs_free char *fields_str_clone = NULL;
|
||||
char *fields_str_cur;
|
||||
char *fields_str_next;
|
||||
|
||||
fields_str_clone = g_strdup (fields_str);
|
||||
for (fields_str_cur = fields_str_clone; fields_str_cur; fields_str_cur = fields_str_next) {
|
||||
const char *i_name;
|
||||
const char *right = NULL;
|
||||
gboolean found = FALSE;
|
||||
const NMMetaAbstractInfo *fields_array_failure = NULL;
|
||||
|
||||
fields_str_cur = nm_str_skip_leading_spaces (fields_str_cur);
|
||||
fields_str_next = strchr (fields_str_cur, ',');
|
||||
if (fields_str_next)
|
||||
*fields_str_next++ = '\0';
|
||||
|
||||
g_strchomp (fields_str_cur);
|
||||
if (!fields_str_cur[0])
|
||||
continue;
|
||||
|
||||
i_name = fields_str_cur;
|
||||
fields_str_cur = strchr (fields_str_cur, '.');
|
||||
if (fields_str_cur) {
|
||||
right = fields_str_cur + 1;
|
||||
*fields_str_cur = '\0';
|
||||
}
|
||||
|
||||
for (i = 0; fields_array[i]; i++) {
|
||||
const NMMetaAbstractInfo *fi = fields_array[i];
|
||||
|
||||
if (g_ascii_strcasecmp (i_name, nm_meta_abstract_info_get_name (fi)) != 0)
|
||||
continue;
|
||||
|
||||
if (!right)
|
||||
found = TRUE;
|
||||
else {
|
||||
found = FALSE;
|
||||
if (fi->meta_type == &nm_meta_type_setting_info_editor) {
|
||||
const NMMetaSettingInfoEditor *fi_s = &fi->as.setting_info;
|
||||
|
||||
for (j = 1; j < fi_s->properties_num; j++) {
|
||||
if (g_ascii_strcasecmp (right, fi_s->properties[j].property_name) == 0) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (fi->meta_type == &nmc_meta_type_generic_info) {
|
||||
const NmcMetaGenericInfo *fi_g = (const NmcMetaGenericInfo *) fi;
|
||||
|
||||
for (j = 0; fi_g->nested && fi_g->nested[j]; j++) {
|
||||
if (g_ascii_strcasecmp (right, nm_meta_abstract_info_get_name ((const NMMetaAbstractInfo *) fi_g->nested[j])) == 0) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
OutputSelectionItem s = {
|
||||
.idx = i,
|
||||
};
|
||||
|
||||
if (right) {
|
||||
if (!str)
|
||||
str = g_string_sized_new (32);
|
||||
|
||||
s.offset_plus_1 = str->len + 1;
|
||||
g_string_append_len (str, right, strlen (right) + 1);
|
||||
}
|
||||
|
||||
g_array_append_val (array, s);
|
||||
}
|
||||
|
||||
fields_array_failure = fields_array[i];
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
if ( !right
|
||||
&& ( !g_ascii_strcasecmp (i_name, "all")
|
||||
|| !g_ascii_strcasecmp (i_name, "common")))
|
||||
g_set_error (error, NMCLI_ERROR, 0, _("field '%s' has to be alone"), i_name);
|
||||
else {
|
||||
gs_free char *allowed_fields = NULL;
|
||||
|
||||
if (fields_array_failure)
|
||||
allowed_fields = nmc_get_allowed_fields_nested (fields_array_failure);
|
||||
else
|
||||
allowed_fields = nmc_get_allowed_fields (fields_array);
|
||||
|
||||
g_set_error (error, NMCLI_ERROR, 1, _("invalid field '%s%s%s'; allowed fields: %s"),
|
||||
i_name, right ? "." : "", right ?: "", allowed_fields);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* re-organize the collected output data in one buffer that can be freed using
|
||||
* g_free(). This makes allocation more complicated, but saves us from special
|
||||
* handling for free. */
|
||||
result = g_malloc0 (sizeof (NmcOutputSelection) + (array->len * sizeof (NmcOutputSelectionItem)) + (str ? str->len : 0));
|
||||
*((guint *) &result->num) = array->len;
|
||||
if (array->len > 0) {
|
||||
char *pdata = &((char *) result)[sizeof (NmcOutputSelection) + (array->len * sizeof (NmcOutputSelectionItem))];
|
||||
|
||||
if (str)
|
||||
memcpy (pdata, str->str, str->len);
|
||||
for (i = 0; i < array->len; i++) {
|
||||
const OutputSelectionItem *a = &g_array_index (array, OutputSelectionItem, i);
|
||||
NmcOutputSelectionItem *p = (NmcOutputSelectionItem *) &result->items[i];
|
||||
|
||||
p->info = fields_array[a->idx];
|
||||
p->idx = a->idx;
|
||||
if (a->offset_plus_1 > 0)
|
||||
p->sub_selection = &pdata[a->offset_plus_1 - 1];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return _output_selection_pack (fields_array, array, NULL);
|
||||
}
|
||||
|
||||
static NmcOutputSelection *
|
||||
_output_selection_create_one (const NMMetaAbstractInfo *const* fields_array,
|
||||
const char *fields_prefix,
|
||||
const char *fields_str, /* one field selector (contains not commas) and is alrady stripped of spaces. */
|
||||
gboolean validate_nested,
|
||||
GError **error)
|
||||
{
|
||||
gs_unref_array GArray *array = NULL;
|
||||
nm_auto_free_gstring GString *str = NULL;
|
||||
|
||||
g_return_val_if_fail (!error || !*error, NULL);
|
||||
nm_assert (fields_str && !strchr (fields_str, ','));
|
||||
|
||||
if (!_output_selection_select_one (fields_array,
|
||||
fields_prefix,
|
||||
fields_str,
|
||||
validate_nested,
|
||||
&array,
|
||||
&str,
|
||||
error))
|
||||
return NULL;
|
||||
return _output_selection_pack (fields_array, array, str);
|
||||
|
||||
}
|
||||
|
||||
#define PRINT_DATA_COL_PARENT_NIL (G_MAXUINT)
|
||||
|
||||
typedef struct {
|
||||
const NmcOutputSelectionItem *selection_item;
|
||||
guint parent_idx;
|
||||
guint self_idx;
|
||||
bool is_leaf;
|
||||
} PrintDataCol;
|
||||
|
||||
static gboolean
|
||||
_output_selection_append (GArray *cols,
|
||||
const char *fields_prefix,
|
||||
guint parent_idx,
|
||||
const NmcOutputSelectionItem *selection_item,
|
||||
GPtrArray *gfree_keeper,
|
||||
GError **error)
|
||||
{
|
||||
gs_free gpointer nested_to_free = NULL;
|
||||
guint col_idx;
|
||||
guint i;
|
||||
const NMMetaAbstractInfo *const*nested;
|
||||
NmcOutputSelection *selection;
|
||||
const NmcOutputSelectionItem *si;
|
||||
|
||||
col_idx = cols->len;
|
||||
|
||||
{
|
||||
PrintDataCol col = {
|
||||
.selection_item = selection_item,
|
||||
.parent_idx = parent_idx,
|
||||
.self_idx = col_idx,
|
||||
.is_leaf = TRUE,
|
||||
};
|
||||
g_array_append_val (cols, col);
|
||||
}
|
||||
|
||||
nested = nm_meta_abstract_info_get_nested (selection_item->info, NULL, &nested_to_free);
|
||||
|
||||
if (selection_item->sub_selection) {
|
||||
if (!nested) {
|
||||
gs_free char *allowed_fields = NULL;
|
||||
|
||||
if (parent_idx != PRINT_DATA_COL_PARENT_NIL) {
|
||||
si = g_array_index (cols, PrintDataCol, parent_idx).selection_item;
|
||||
allowed_fields = nmc_get_allowed_fields_nested (si->info, si->self_selection);
|
||||
}
|
||||
if (!allowed_fields) {
|
||||
g_set_error (error, NMCLI_ERROR, 1, _("invalid field '%s%s%s'; no such field"),
|
||||
selection_item->self_selection ?: "", selection_item->self_selection ? "." : "",
|
||||
selection_item->sub_selection);
|
||||
} else {
|
||||
g_set_error (error, NMCLI_ERROR, 1, _("invalid field '%s%s%s'; allowed fields: [%s]"),
|
||||
selection_item->self_selection ?: "", selection_item->self_selection ? "." : "",
|
||||
selection_item->sub_selection,
|
||||
allowed_fields);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
selection = _output_selection_create_one (nested, selection_item->self_selection,
|
||||
selection_item->sub_selection, FALSE, error);
|
||||
if (!selection)
|
||||
return FALSE;
|
||||
nm_assert (selection->num == 1);
|
||||
} else if (nested) {
|
||||
selection = _output_selection_create_all (nested);
|
||||
nm_assert (selection && selection->num > 0);
|
||||
} else
|
||||
selection = NULL;
|
||||
|
||||
if (selection) {
|
||||
g_ptr_array_add (gfree_keeper, selection);
|
||||
|
||||
for (i = 0; i < selection->num; i++) {
|
||||
si = &selection->items[i];
|
||||
if (!_output_selection_append (cols, si->self_selection, col_idx,
|
||||
si, gfree_keeper, error))
|
||||
return FALSE;
|
||||
}
|
||||
g_array_index (cols, PrintDataCol, col_idx).is_leaf = FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
NmcOutputSelection *
|
||||
nmc_output_selection_create (const NMMetaAbstractInfo *const* fields_array,
|
||||
const char *fields_prefix,
|
||||
const char *fields_str, /* a comma separated list of selectors */
|
||||
gboolean validate_nested,
|
||||
GError **error)
|
||||
{
|
||||
gs_unref_array GArray *array = NULL;
|
||||
nm_auto_free_gstring GString *str = NULL;
|
||||
gs_free char *fields_str_clone = NULL;
|
||||
char *fields_str_cur;
|
||||
char *fields_str_next;
|
||||
|
||||
g_return_val_if_fail (!error || !*error, NULL);
|
||||
|
||||
if (!fields_str)
|
||||
return _output_selection_create_all (fields_array);
|
||||
|
||||
fields_str_clone = g_strdup (fields_str);
|
||||
for (fields_str_cur = fields_str_clone; fields_str_cur; fields_str_cur = fields_str_next) {
|
||||
fields_str_cur = nm_str_skip_leading_spaces (fields_str_cur);
|
||||
fields_str_next = strchr (fields_str_cur, ',');
|
||||
if (fields_str_next)
|
||||
*fields_str_next++ = '\0';
|
||||
|
||||
g_strchomp (fields_str_cur);
|
||||
if (!fields_str_cur[0])
|
||||
continue;
|
||||
if (!_output_selection_select_one (fields_array,
|
||||
fields_prefix,
|
||||
fields_str_cur,
|
||||
validate_nested,
|
||||
&array,
|
||||
&str,
|
||||
error))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return _output_selection_pack (fields_array, array, str);
|
||||
}
|
||||
|
||||
/**
|
||||
* _output_selection_parse:
|
||||
* @fields: a %NULL terminated array of meta-data fields
|
||||
* @fields_str: a comma separated selector for fields. Nested fields
|
||||
* can be specified using '.' notation.
|
||||
* @out_cols: (transfer full): the result, parsed as an GArray of PrintDataCol items.
|
||||
* The order of the items is as specified by @fields_str. Meta data
|
||||
* items that contain nested elements are unpacked (note the is_leaf
|
||||
* and parent properties of PrintDataCol).
|
||||
* @out_gfree_keeper: (transfer full): an output GPtrArray that owns
|
||||
* strings to which @out_cols points to. The lifetime of @out_cols
|
||||
* and @out_gfree_keeper should correspond.
|
||||
* @error:
|
||||
*
|
||||
* Returns: %TRUE on success.
|
||||
*/
|
||||
static gboolean
|
||||
_output_selection_parse (const NMMetaAbstractInfo *const*fields,
|
||||
const char *fields_str,
|
||||
GArray **out_cols,
|
||||
GPtrArray **out_gfree_keeper,
|
||||
GError **error)
|
||||
{
|
||||
NmcOutputSelection *selection;
|
||||
gs_unref_ptrarray GPtrArray *gfree_keeper = NULL;
|
||||
gs_unref_array GArray *cols = NULL;
|
||||
guint i;
|
||||
|
||||
selection = nmc_output_selection_create (fields, NULL, fields_str, FALSE, error);
|
||||
if (!selection)
|
||||
return FALSE;
|
||||
|
||||
if (!selection->num) {
|
||||
g_set_error (error, NMCLI_ERROR, 1, _("failure to select field"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gfree_keeper = g_ptr_array_new_with_free_func (g_free);
|
||||
g_ptr_array_add (gfree_keeper, selection);
|
||||
|
||||
cols = g_array_new (FALSE, TRUE, sizeof (PrintDataCol));
|
||||
|
||||
for (i = 0; i < selection->num; i++) {
|
||||
const NmcOutputSelectionItem *si = &selection->items[i];
|
||||
|
||||
if (!_output_selection_append (cols, NULL, PRINT_DATA_COL_PARENT_NIL,
|
||||
si, gfree_keeper, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*out_cols = g_steal_pointer (&cols);
|
||||
*out_gfree_keeper = g_steal_pointer (&gfree_keeper);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* parse_output_fields:
|
||||
|
|
@ -921,7 +1178,7 @@ parse_output_fields (const char *fields_str,
|
|||
g_return_val_if_fail (!error || !*error, NULL);
|
||||
g_return_val_if_fail (!out_group_fields || !*out_group_fields, NULL);
|
||||
|
||||
selection = nmc_output_selection_create (fields_array, fields_str, error);
|
||||
selection = nmc_output_selection_create (fields_array, NULL, fields_str, TRUE, error);
|
||||
if (!selection)
|
||||
return NULL;
|
||||
|
||||
|
|
@ -943,40 +1200,46 @@ parse_output_fields (const char *fields_str,
|
|||
}
|
||||
|
||||
char *
|
||||
nmc_get_allowed_fields_nested (const NMMetaAbstractInfo *abstract_info)
|
||||
nmc_get_allowed_fields_nested (const NMMetaAbstractInfo *abstract_info, const char *name_prefix)
|
||||
{
|
||||
GString *allowed_fields = g_string_sized_new (256);
|
||||
int i;
|
||||
const char *name = nm_meta_abstract_info_get_name (abstract_info);
|
||||
gs_free gpointer nested_to_free = NULL;
|
||||
const NMMetaAbstractInfo *const*nested = NULL;
|
||||
guint i;
|
||||
const NMMetaAbstractInfo *const*nested;
|
||||
GString *allowed_fields;
|
||||
|
||||
nested = nm_meta_abstract_info_get_nested (abstract_info, NULL, &nested_to_free);
|
||||
if (nested) {
|
||||
for (i = 0; nested && nested[i]; i++) {
|
||||
g_string_append_printf (allowed_fields, "%s.%s,",
|
||||
name, nm_meta_abstract_info_get_name (nested[i]));
|
||||
}
|
||||
} else
|
||||
g_string_append_printf (allowed_fields, "%s,", name);
|
||||
if (!nested)
|
||||
return NULL;
|
||||
|
||||
allowed_fields = g_string_sized_new (256);
|
||||
|
||||
if (!name_prefix)
|
||||
name_prefix = nm_meta_abstract_info_get_name (abstract_info);
|
||||
|
||||
for (i = 0; nested[i]; i++) {
|
||||
g_string_append_printf (allowed_fields, "%s.%s,",
|
||||
name_prefix, nm_meta_abstract_info_get_name (nested[i]));
|
||||
}
|
||||
g_string_truncate (allowed_fields, allowed_fields->len - 1);
|
||||
|
||||
return g_string_free (allowed_fields, FALSE);
|
||||
}
|
||||
|
||||
char *
|
||||
nmc_get_allowed_fields (const NMMetaAbstractInfo *const*fields_array)
|
||||
nmc_get_allowed_fields (const NMMetaAbstractInfo *const*fields_array, const char *name_prefix)
|
||||
{
|
||||
GString *allowed_fields = g_string_sized_new (256);
|
||||
GString *allowed_fields;
|
||||
guint i;
|
||||
|
||||
for (i = 0; fields_array[i]; i++)
|
||||
if (!fields_array || !fields_array[0])
|
||||
return NULL;
|
||||
|
||||
allowed_fields = g_string_sized_new (256);
|
||||
for (i = 0; fields_array[i]; i++) {
|
||||
if (name_prefix)
|
||||
g_string_append_printf (allowed_fields, "%s.", name_prefix);
|
||||
g_string_append_printf (allowed_fields, "%s,", nm_meta_abstract_info_get_name (fields_array[i]));
|
||||
|
||||
if (allowed_fields->len)
|
||||
g_string_truncate (allowed_fields, allowed_fields->len - 1);
|
||||
|
||||
}
|
||||
g_string_truncate (allowed_fields, allowed_fields->len - 1);
|
||||
return g_string_free (allowed_fields, FALSE);
|
||||
}
|
||||
|
||||
|
|
@ -1012,6 +1275,343 @@ nmc_empty_output_fields (NmcOutputData *output_data)
|
|||
g_ptr_array_remove_range (output_data->output_data, 0, output_data->output_data->len);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
guint col_idx;
|
||||
const PrintDataCol *col;
|
||||
bool is_nested;
|
||||
const char *title;
|
||||
int width;
|
||||
} PrintDataHeaderCell;
|
||||
|
||||
typedef struct {
|
||||
guint row_idx;
|
||||
const PrintDataHeaderCell *header_cell;
|
||||
NMMetaTermColor term_color;
|
||||
NMMetaTermFormat term_format;
|
||||
const char *text;
|
||||
bool text_to_free:1;
|
||||
} PrintDataCell;
|
||||
|
||||
static void
|
||||
_print_data_header_cell_clear (gpointer cell_p)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
_print_data_cell_clear_text (PrintDataCell *cell)
|
||||
{
|
||||
if (cell->text_to_free) {
|
||||
g_free ((char *) cell->text);
|
||||
cell->text_to_free = FALSE;
|
||||
}
|
||||
cell->text = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_print_data_cell_clear (gpointer cell_p)
|
||||
{
|
||||
PrintDataCell *cell = cell_p;
|
||||
|
||||
_print_data_cell_clear_text (cell);
|
||||
}
|
||||
|
||||
static void
|
||||
_print_fill (const NmcConfig *nmc_config,
|
||||
gpointer const *targets,
|
||||
const PrintDataCol *cols,
|
||||
guint cols_len,
|
||||
GArray **out_header_row,
|
||||
GArray **out_cells)
|
||||
{
|
||||
GArray *cells;
|
||||
GArray *header_row;
|
||||
guint i_row, i_col;
|
||||
guint targets_len;
|
||||
gboolean pretty;
|
||||
NMMetaAccessorGetType text_get_type;
|
||||
|
||||
pretty = (nmc_config->print_output != NMC_PRINT_TERSE);
|
||||
|
||||
header_row = g_array_sized_new (FALSE, TRUE, sizeof (PrintDataHeaderCell), cols_len);
|
||||
g_array_set_clear_func (header_row, _print_data_header_cell_clear);
|
||||
|
||||
for (i_col = 0; i_col < cols_len; i_col++) {
|
||||
const PrintDataCol *col;
|
||||
PrintDataHeaderCell *header_cell;
|
||||
guint col_idx;
|
||||
|
||||
col = &cols[i_col];
|
||||
if (!col->is_leaf)
|
||||
continue;
|
||||
|
||||
col_idx = header_row->len;
|
||||
g_array_set_size (header_row, col_idx + 1);
|
||||
|
||||
header_cell = &g_array_index (header_row, PrintDataHeaderCell, col_idx);
|
||||
|
||||
header_cell->col_idx = col_idx;
|
||||
header_cell->col = col;
|
||||
header_cell->is_nested = FALSE;
|
||||
header_cell->title = nm_meta_abstract_info_get_name (col->selection_item->info);
|
||||
if (pretty)
|
||||
header_cell->title = _(header_cell->title);
|
||||
}
|
||||
|
||||
targets_len = NM_PTRARRAY_LEN (targets);
|
||||
|
||||
cells = g_array_sized_new (FALSE, TRUE, sizeof (PrintDataCell), targets_len * header_row->len);
|
||||
g_array_set_clear_func (cells, _print_data_cell_clear);
|
||||
g_array_set_size (cells, targets_len * header_row->len);
|
||||
|
||||
text_get_type = pretty
|
||||
? NM_META_ACCESSOR_GET_TYPE_PRETTY
|
||||
: NM_META_ACCESSOR_GET_TYPE_PARSABLE;
|
||||
|
||||
for (i_row = 0; i_row < targets_len; i_row++) {
|
||||
gpointer target = targets[i_row];
|
||||
PrintDataCell *cells_line = &g_array_index (cells, PrintDataCell, i_row * header_row->len);
|
||||
|
||||
for (i_col = 0; i_col < header_row->len; i_col++) {
|
||||
char *to_free = NULL;
|
||||
PrintDataCell *cell = &cells_line[i_col];
|
||||
const PrintDataHeaderCell *header_cell;
|
||||
const NMMetaAbstractInfo *info;
|
||||
|
||||
header_cell = &g_array_index (header_row, PrintDataHeaderCell, i_col);
|
||||
info = header_cell->col->selection_item->info;
|
||||
|
||||
cell->row_idx = i_row;
|
||||
cell->header_cell = header_cell;
|
||||
cell->text = nm_meta_abstract_info_get (info,
|
||||
NULL,
|
||||
NULL,
|
||||
target,
|
||||
text_get_type,
|
||||
NM_META_ACCESSOR_GET_FLAGS_NONE,
|
||||
(gpointer *) &to_free);
|
||||
cell->text_to_free = !!to_free;
|
||||
|
||||
nm_meta_termformat_unpack (nm_meta_abstract_info_get (info,
|
||||
NULL,
|
||||
NULL,
|
||||
target,
|
||||
NM_META_ACCESSOR_GET_TYPE_TERMFORMAT,
|
||||
NM_META_ACCESSOR_GET_FLAGS_NONE,
|
||||
NULL),
|
||||
&cell->term_color,
|
||||
&cell->term_format);
|
||||
|
||||
if (pretty && (!cell->text || !cell->text[0])) {
|
||||
_print_data_cell_clear_text (cell);
|
||||
cell->text = "--";
|
||||
} else if (!cell->text)
|
||||
cell->text = "";
|
||||
}
|
||||
}
|
||||
|
||||
for (i_col = 0; i_col < header_row->len; i_col++) {
|
||||
PrintDataHeaderCell *header_cell = &g_array_index (header_row, PrintDataHeaderCell, i_col);
|
||||
|
||||
header_cell->width = nmc_string_screen_width (header_cell->title, NULL);
|
||||
|
||||
for (i_row = 0; i_row < targets_len; i_row++) {
|
||||
const PrintDataCell *cell = &g_array_index (cells, PrintDataCell, i_row * cols_len + i_col);
|
||||
|
||||
if (header_cell->is_nested) {
|
||||
g_assert_not_reached (/*TODO*/);
|
||||
} else {
|
||||
header_cell->width = NM_MAX (header_cell->width,
|
||||
nmc_string_screen_width (cell->text, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
header_cell->width += 1;
|
||||
}
|
||||
|
||||
*out_header_row = header_row;
|
||||
*out_cells = cells;
|
||||
}
|
||||
|
||||
static void
|
||||
_print_do (const NmcConfig *nmc_config,
|
||||
const char *header_name_no_l10n,
|
||||
guint col_len,
|
||||
guint row_len,
|
||||
const PrintDataHeaderCell *header_row,
|
||||
const PrintDataCell *cells)
|
||||
{
|
||||
int width1, width2;
|
||||
int table_width = 0;
|
||||
gboolean pretty = (nmc_config->print_output == NMC_PRINT_PRETTY);
|
||||
gboolean terse = (nmc_config->print_output == NMC_PRINT_TERSE);
|
||||
gboolean multiline = nmc_config->multiline_output;
|
||||
guint i_row, i_col;
|
||||
nm_auto_free_gstring GString *str = NULL;
|
||||
|
||||
g_assert (col_len && row_len);
|
||||
|
||||
/* Main header */
|
||||
if (pretty) {
|
||||
gs_free char *line = NULL;
|
||||
int header_width;
|
||||
const char *header_name = _(header_name_no_l10n);
|
||||
|
||||
header_width = nmc_string_screen_width (header_name, NULL) + 4;
|
||||
|
||||
if (multiline) {
|
||||
table_width = NM_MAX (header_width, ML_HEADER_WIDTH);
|
||||
line = g_strnfill (ML_HEADER_WIDTH, '=');
|
||||
} else { /* tabular */
|
||||
table_width = NM_MAX (table_width, header_width);
|
||||
line = g_strnfill (table_width, '=');
|
||||
}
|
||||
|
||||
width1 = strlen (header_name);
|
||||
width2 = nmc_string_screen_width (header_name, NULL);
|
||||
g_print ("%s\n", line);
|
||||
g_print ("%*s\n", (table_width + width2)/2 + width1 - width2, header_name);
|
||||
g_print ("%s\n", line);
|
||||
}
|
||||
|
||||
str = !multiline
|
||||
? g_string_sized_new (100)
|
||||
: NULL;
|
||||
|
||||
/* print the header for the tabular form */
|
||||
if (!multiline && !terse) {
|
||||
for (i_col = 0; i_col < col_len; i_col++) {
|
||||
const PrintDataHeaderCell *header_cell = &header_row[i_col];
|
||||
const char *title;
|
||||
|
||||
title = header_cell->title;
|
||||
|
||||
width1 = strlen (title);
|
||||
width2 = nmc_string_screen_width (title, NULL); /* Width of the string (in screen colums) */
|
||||
g_string_append_printf (str, "%-*s", (int) (header_cell->width + width1 - width2), title);
|
||||
g_string_append_c (str, ' '); /* Column separator */
|
||||
table_width += header_cell->width + width1 - width2 + 1;
|
||||
}
|
||||
|
||||
if (str->len)
|
||||
g_string_truncate (str, str->len-1); /* Chop off last column separator */
|
||||
g_print ("%s\n", str->str);
|
||||
g_string_truncate (str, 0);
|
||||
|
||||
/* Print horizontal separator */
|
||||
if (pretty) {
|
||||
gs_free char *line = NULL;
|
||||
|
||||
g_print ("%s\n", (line = g_strnfill (table_width, '-')));
|
||||
}
|
||||
}
|
||||
|
||||
for (i_row = 0; i_row < row_len; i_row++) {
|
||||
const PrintDataCell *current_line = &cells[i_row * col_len];
|
||||
|
||||
for (i_col = 0; i_col < col_len; i_col++) {
|
||||
const PrintDataCell *cell = ¤t_line[i_col];
|
||||
gs_free char *text_to_free = NULL;
|
||||
const char *text;
|
||||
|
||||
if (cell->header_cell->is_nested) {
|
||||
g_assert_not_reached (/*TODO*/);
|
||||
} else {
|
||||
text = colorize_string (nmc_config->use_colors,
|
||||
cell->term_color, cell->term_format,
|
||||
cell->text, &text_to_free);
|
||||
}
|
||||
|
||||
if (multiline) {
|
||||
gs_free char *prefix = NULL;
|
||||
|
||||
prefix = g_strdup_printf ("%s:", cell->header_cell->title);
|
||||
width1 = strlen (prefix);
|
||||
width2 = nmc_string_screen_width (prefix, NULL);
|
||||
g_print ("%-*s%s\n", (int) (terse ? 0 : ML_VALUE_INDENT+width1-width2), prefix, text);
|
||||
} else {
|
||||
nm_assert (str);
|
||||
if (terse) {
|
||||
if (nmc_config->escape_values) {
|
||||
const char *p = text;
|
||||
while (*p) {
|
||||
if (*p == ':' || *p == '\\')
|
||||
g_string_append_c (str, '\\'); /* Escaping by '\' */
|
||||
g_string_append_c (str, *p);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
else
|
||||
g_string_append_printf (str, "%s", text);
|
||||
g_string_append_c (str, ':'); /* Column separator */
|
||||
} else {
|
||||
const PrintDataHeaderCell *header_cell = &header_row[i_col];
|
||||
|
||||
width1 = strlen (text);
|
||||
width2 = nmc_string_screen_width (text, NULL); /* Width of the string (in screen colums) */
|
||||
g_string_append_printf (str, "%-*s", (int) (header_cell->width + width1 - width2), text);
|
||||
g_string_append_c (str, ' '); /* Column separator */
|
||||
table_width += header_cell->width + width1 - width2 + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!multiline) {
|
||||
if (str->len)
|
||||
g_string_truncate (str, str->len-1); /* Chop off last column separator */
|
||||
g_print ("%s\n", str->str);
|
||||
|
||||
g_string_truncate (str, 0);
|
||||
}
|
||||
|
||||
if ( pretty
|
||||
&& ( i_row < row_len - 1
|
||||
|| multiline)) {
|
||||
gs_free char *line = NULL;
|
||||
|
||||
g_print ("%s\n", (line = g_strnfill (ML_HEADER_WIDTH, '-')));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
nmc_print (const NmcConfig *nmc_config,
|
||||
gpointer const *targets,
|
||||
const char *header_name_no_l10n,
|
||||
const NMMetaAbstractInfo *const*fields,
|
||||
const char *fields_str,
|
||||
GError **error)
|
||||
{
|
||||
gs_unref_ptrarray GPtrArray *gfree_keeper = NULL;
|
||||
gs_unref_array GArray *cols = NULL;
|
||||
gs_unref_array GArray *header_row = NULL;
|
||||
gs_unref_array GArray *cells = NULL;
|
||||
|
||||
if (!_output_selection_parse (fields, fields_str,
|
||||
&cols, &gfree_keeper,
|
||||
error))
|
||||
return FALSE;
|
||||
|
||||
_print_fill (nmc_config,
|
||||
targets,
|
||||
&g_array_index (cols, PrintDataCol, 0),
|
||||
cols->len,
|
||||
&header_row,
|
||||
&cells);
|
||||
|
||||
_print_do (nmc_config,
|
||||
header_name_no_l10n,
|
||||
header_row->len,
|
||||
cells->len / header_row->len,
|
||||
&g_array_index (header_row, PrintDataHeaderCell, 0),
|
||||
&g_array_index (cells, PrintDataCell, 0));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static const char *
|
||||
get_value_to_print (NmcColorOption color_option,
|
||||
const NmcOutputField *field,
|
||||
|
|
@ -1139,7 +1739,7 @@ print_required_fields (const NmcConfig *nmc_config,
|
|||
j);
|
||||
width1 = strlen (tmp);
|
||||
width2 = nmc_string_screen_width (tmp, NULL);
|
||||
g_print ("%-*s%s\n", terse ? 0 : ML_VALUE_INDENT+width1-width2, tmp, print_val);
|
||||
g_print ("%-*s%s\n", (int) (terse ? 0 : ML_VALUE_INDENT+width1-width2), tmp, print_val);
|
||||
}
|
||||
} else {
|
||||
gs_free char *val_to_free = NULL;
|
||||
|
|
@ -1159,7 +1759,7 @@ print_required_fields (const NmcConfig *nmc_config,
|
|||
_(nm_meta_abstract_info_get_name (field_values[idx].info)));
|
||||
width1 = strlen (tmp);
|
||||
width2 = nmc_string_screen_width (tmp, NULL);
|
||||
g_print ("%-*s%s\n", terse ? 0 : ML_VALUE_INDENT+width1-width2, tmp, print_val);
|
||||
g_print ("%-*s%s\n", (int) (terse ? 0 : ML_VALUE_INDENT+width1-width2), tmp, print_val);
|
||||
}
|
||||
}
|
||||
if (pretty) {
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ void nmc_free_output_field_values (NmcOutputField fields_array[]);
|
|||
|
||||
typedef struct {
|
||||
const NMMetaAbstractInfo *info;
|
||||
const char *self_selection;
|
||||
const char *sub_selection;
|
||||
guint idx;
|
||||
} NmcOutputSelectionItem;
|
||||
|
|
@ -73,7 +74,9 @@ typedef struct {
|
|||
} NmcOutputSelection;
|
||||
|
||||
NmcOutputSelection *nmc_output_selection_create (const NMMetaAbstractInfo *const* fields_array,
|
||||
const char *fields_prefix,
|
||||
const char *fields_str,
|
||||
gboolean validate_nested,
|
||||
GError **error);
|
||||
|
||||
GArray *parse_output_fields (const char *fields_str,
|
||||
|
|
@ -81,8 +84,8 @@ GArray *parse_output_fields (const char *fields_str,
|
|||
gboolean parse_groups,
|
||||
GPtrArray **group_fields,
|
||||
GError **error);
|
||||
char *nmc_get_allowed_fields_nested (const NMMetaAbstractInfo *abstract_info);
|
||||
char *nmc_get_allowed_fields (const NMMetaAbstractInfo *const*fields_array);
|
||||
char *nmc_get_allowed_fields_nested (const NMMetaAbstractInfo *abstract_info, const char *name_prefix);
|
||||
char *nmc_get_allowed_fields (const NMMetaAbstractInfo *const*fields_array, const char *name_prefix);
|
||||
NmcOutputField *nmc_dup_fields_array (const NMMetaAbstractInfo *const*fields, NmcOfFlags flags);
|
||||
void nmc_empty_output_fields (NmcOutputData *output_data);
|
||||
void print_required_fields (const NmcConfig *nmc_config,
|
||||
|
|
@ -100,8 +103,25 @@ void print_data (const NmcConfig *nmc_config,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef enum {
|
||||
NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_RUNNING = 0,
|
||||
NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_VERSION,
|
||||
NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_STATE,
|
||||
NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_STARTUP,
|
||||
NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_CONNECTIVITY,
|
||||
NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_NETWORKING,
|
||||
NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIFI_HW,
|
||||
NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIFI,
|
||||
NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WWAN_HW,
|
||||
NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WWAN,
|
||||
NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIMAX_HW,
|
||||
NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIMAX,
|
||||
_NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_NUM,
|
||||
} NmcGenericInfoType;
|
||||
|
||||
struct _NmcMetaGenericInfo {
|
||||
const NMMetaType *meta_type;
|
||||
NmcGenericInfoType info_type;
|
||||
const char *name;
|
||||
const NmcMetaGenericInfo *const*nested;
|
||||
gconstpointer (*get_fcn) (const NMMetaEnvironment *environment,
|
||||
|
|
@ -125,4 +145,13 @@ struct _NmcMetaGenericInfo {
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
gboolean nmc_print (const NmcConfig *nmc_config,
|
||||
gpointer const *targets,
|
||||
const char *header_name_no_l10n,
|
||||
const NMMetaAbstractInfo *const*fields,
|
||||
const char *fields_str,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#endif /* NMC_UTILS_H */
|
||||
|
|
|
|||
|
|
@ -223,3 +223,27 @@ nm_meta_abstract_info_get_nested (const NMMetaAbstractInfo *abstract_info,
|
|||
NM_SET_OUT (out_len, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gconstpointer
|
||||
nm_meta_abstract_info_get (const NMMetaAbstractInfo *abstract_info,
|
||||
const NMMetaEnvironment *environment,
|
||||
gpointer environment_user_data,
|
||||
gpointer target,
|
||||
NMMetaAccessorGetType get_type,
|
||||
NMMetaAccessorGetFlags get_flags,
|
||||
gpointer *out_to_free)
|
||||
{
|
||||
nm_assert (abstract_info);
|
||||
nm_assert (abstract_info->meta_type);
|
||||
nm_assert (!out_to_free || !*out_to_free);
|
||||
|
||||
if (!abstract_info->meta_type->get_fcn)
|
||||
g_return_val_if_reached (NULL);
|
||||
|
||||
return abstract_info->meta_type->get_fcn (environment, environment_user_data,
|
||||
abstract_info,
|
||||
target,
|
||||
get_type,
|
||||
get_flags,
|
||||
out_to_free);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,14 @@ const NMMetaAbstractInfo *const*nm_meta_abstract_info_get_nested (const NMMetaAb
|
|||
guint *out_len,
|
||||
gpointer *nested_to_free);
|
||||
|
||||
gconstpointer nm_meta_abstract_info_get (const NMMetaAbstractInfo *abstract_info,
|
||||
const NMMetaEnvironment *environment,
|
||||
gpointer environment_user_data,
|
||||
gpointer target,
|
||||
NMMetaAccessorGetType get_type,
|
||||
NMMetaAccessorGetFlags get_flags,
|
||||
gpointer *out_to_free);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#endif /* _NM_META_SETTING_ACCESS_H__ */
|
||||
|
|
|
|||
|
|
@ -49,8 +49,35 @@ typedef enum {
|
|||
typedef enum {
|
||||
NM_META_ACCESSOR_GET_TYPE_PRETTY,
|
||||
NM_META_ACCESSOR_GET_TYPE_PARSABLE,
|
||||
NM_META_ACCESSOR_GET_TYPE_TERMFORMAT,
|
||||
} NMMetaAccessorGetType;
|
||||
|
||||
static inline void
|
||||
nm_meta_termformat_unpack (gconstpointer value, NMMetaTermColor *out_color, NMMetaTermFormat *out_format)
|
||||
{
|
||||
/* get_fcn() with NM_META_ACCESSOR_GET_TYPE_TERMFORMAT returns a pointer
|
||||
* that encodes NMMetaTermColor and NMMetaTermFormat. Unpack it. */
|
||||
if (!value) {
|
||||
/* by default, objects that don't support NM_META_ACCESSOR_GET_TYPE_TERMFORMAT
|
||||
* return NULL. This allows for an explicit fallback value here... */
|
||||
NM_SET_OUT (out_color, NM_META_TERM_COLOR_NORMAL);
|
||||
NM_SET_OUT (out_format, NM_META_TERM_FORMAT_NORMAL);
|
||||
} else {
|
||||
NM_SET_OUT (out_color, GPOINTER_TO_UINT (value) & 0xFF);
|
||||
NM_SET_OUT (out_format, (GPOINTER_TO_UINT (value) & 0xFF00) >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
static inline gconstpointer
|
||||
nm_meta_termformat_pack (NMMetaTermColor color, NMMetaTermFormat format)
|
||||
{
|
||||
/* get_fcn() with NM_META_ACCESSOR_GET_TYPE_TERMFORMAT returns a pointer
|
||||
* that encodes NMMetaTermColor and NMMetaTermFormat. Pack it. */
|
||||
return GUINT_TO_POINTER (((guint) 0x10000) | (((guint) color) & 0xFFu) | ((((guint) format) & 0xFFu) << 8));
|
||||
}
|
||||
|
||||
#define NM_META_TERMFORMAT_DEFAULT() (nm_meta_termformat_pack (NM_META_TERM_COLOR_NORMAL, NM_META_TERM_FORMAT_NORMAL))
|
||||
|
||||
typedef enum {
|
||||
NM_META_ACCESSOR_GET_FLAGS_NONE = 0,
|
||||
NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS = (1LL << 0),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue