2010-02-25 09:52:30 -08:00
/* nmcli - command-line tool to control NetworkManager
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*
2015-02-13 13:25:16 +01:00
* Copyright 2010 - 2015 Red Hat , Inc .
2010-02-25 09:52:30 -08:00
*/
2011-02-16 17:36:50 +01:00
/* Generated configuration file */
# include "config.h"
2010-02-25 09:52:30 -08:00
# include <stdio.h>
# include <string.h>
2013-01-16 12:28:37 +01:00
# include <stdlib.h>
# include <errno.h>
2010-02-25 09:52:30 -08:00
2012-01-05 16:30:22 +01:00
# include <sys/socket.h>
# include <netinet/in.h>
# include <arpa/inet.h>
2010-02-25 09:52:30 -08:00
# include <glib.h>
2010-03-18 15:39:15 +01:00
# include <glib/gi18n.h>
2010-02-25 09:52:30 -08:00
# include "utils.h"
int
matches ( const char * cmd , const char * pattern )
{
2013-11-11 14:43:50 +01:00
size_t len = strlen ( cmd ) ;
if ( ! len | | len > strlen ( pattern ) )
2010-02-25 09:52:30 -08:00
return - 1 ;
return memcmp ( pattern , cmd , len ) ;
}
int
next_arg ( int * argc , char * * * argv )
{
2012-11-16 22:43:29 +01:00
int arg_num = * argc ;
if ( arg_num > 0 ) {
2010-02-25 09:52:30 -08:00
( * argc ) - - ;
( * argv ) + + ;
}
2012-11-16 22:43:29 +01:00
if ( arg_num < = 1 )
return - 1 ;
2010-02-25 09:52:30 -08:00
return 0 ;
}
2013-04-18 11:25:49 +02:00
gboolean
nmc_arg_is_help ( const char * arg )
{
2013-04-18 12:42:54 +02:00
if ( ! arg )
return FALSE ;
2013-04-18 11:25:49 +02:00
if ( matches ( arg , " help " ) = = 0
| | ( g_str_has_prefix ( arg , " - " ) & & matches ( arg + 1 , " help " ) = = 0 )
| | ( g_str_has_prefix ( arg , " -- " ) & & matches ( arg + 2 , " help " ) = = 0 ) ) {
return TRUE ;
}
return FALSE ;
}
2013-11-07 14:47:12 +01:00
gboolean
nmc_arg_is_option ( const char * str , const char * opt_name )
{
const char * p ;
if ( ! str | | ! * str )
return FALSE ;
if ( str [ 0 ] ! = ' - ' )
return FALSE ;
p = ( str [ 1 ] = = ' - ' ) ? str + 2 : str + 1 ;
return ( * p ? ( matches ( p , opt_name ) = = 0 ) : FALSE ) ;
}
2013-01-16 12:26:45 +01:00
/*
* Helper function to parse command - line arguments .
* arg_arr : description of arguments to look for
* last : whether these are last expected arguments
* argc : command - line argument array
* argv : command - line argument array size
* error : error set on a failure ( when FALSE is returned )
* Returns : TRUE on success , FALSE on an error and sets ' error '
*/
gboolean
nmc_parse_args ( nmc_arg_t * arg_arr , gboolean last , int * argc , char * * * argv , GError * * error )
{
nmc_arg_t * p ;
gboolean found ;
gboolean have_mandatory ;
g_return_val_if_fail ( arg_arr ! = NULL , FALSE ) ;
g_return_val_if_fail ( error = = NULL | | * error = = NULL , FALSE ) ;
while ( * argc > 0 ) {
found = FALSE ;
for ( p = arg_arr ; p - > name ; p + + ) {
if ( strcmp ( * * argv , p - > name ) = = 0 ) {
if ( p - > found ) {
/* Don't allow repeated arguments, because the argument of the same
* name could be used later on the line for another purpose . Assume
* that ' s the case and return .
*/
return TRUE ;
}
if ( p - > has_value ) {
if ( next_arg ( argc , argv ) ! = 0 ) {
g_set_error ( error , NMCLI_ERROR , NMC_RESULT_ERROR_USER_INPUT ,
_ ( " Error: value for '%s' argument is required. " ) , * ( * argv - 1 ) ) ;
return FALSE ;
}
* ( p - > value ) = * * argv ;
}
p - > found = TRUE ;
found = TRUE ;
break ;
}
}
if ( ! found ) {
have_mandatory = TRUE ;
for ( p = arg_arr ; p - > name ; p + + ) {
if ( p - > mandatory & & ! p - > found ) {
have_mandatory = FALSE ;
break ;
}
}
if ( have_mandatory & & ! last )
return TRUE ;
2013-10-31 14:13:33 +01:00
if ( p - > name )
2013-01-16 12:26:45 +01:00
g_set_error ( error , NMCLI_ERROR , NMC_RESULT_ERROR_USER_INPUT ,
_ ( " Error: Argument '%s' was expected, but '%s' provided. " ) , p - > name , * * argv ) ;
else
g_set_error ( error , NMCLI_ERROR , NMC_RESULT_ERROR_USER_INPUT ,
_ ( " Error: Unexpected argument '%s' " ) , * * argv ) ;
return FALSE ;
}
next_arg ( argc , argv ) ;
}
return TRUE ;
}
2010-03-24 23:28:00 +01:00
/*
2013-05-16 16:26:15 +02:00
* Convert SSID to a hex string representation .
2010-03-24 23:28:00 +01:00
* Caller has to free the returned string using g_free ( )
*/
char *
2013-05-16 16:26:15 +02:00
ssid_to_hex ( const char * str , gsize len )
2010-03-24 23:28:00 +01:00
{
GString * printable ;
char * printable_str ;
int i ;
if ( str = = NULL | | len = = 0 )
2012-04-28 22:54:02 +02:00
return NULL ;
2010-03-24 23:28:00 +01:00
printable = g_string_new ( NULL ) ;
for ( i = 0 ; i < len ; i + + ) {
g_string_append_printf ( printable , " %02X " , ( unsigned char ) str [ i ] ) ;
}
printable_str = g_string_free ( printable , FALSE ) ;
return printable_str ;
}
2012-01-05 16:30:22 +01:00
/*
* Converts IPv4 address from guint32 in network - byte order to text representation .
* Returns : text form of the IP or NULL ( then error is set )
*/
char *
nmc_ip4_address_as_string ( guint32 ip , GError * * error )
{
2013-07-31 23:59:50 +02:00
guint32 tmp_addr ;
2012-01-05 16:30:22 +01:00
char buf [ INET_ADDRSTRLEN ] ;
g_return_val_if_fail ( error = = NULL | | * error = = NULL , NULL ) ;
memset ( & buf , ' \0 ' , sizeof ( buf ) ) ;
2013-07-31 23:59:50 +02:00
tmp_addr = ip ;
2012-01-05 16:30:22 +01:00
if ( inet_ntop ( AF_INET , & tmp_addr , buf , INET_ADDRSTRLEN ) ) {
return g_strdup ( buf ) ;
} else {
2012-07-25 13:57:45 +02:00
g_set_error ( error , NMCLI_ERROR , 0 , _ ( " Error converting IP4 address '0x%X' to text form " ) ,
2013-07-31 23:59:50 +02:00
ntohl ( tmp_addr ) ) ;
2012-01-05 16:30:22 +01:00
return NULL ;
}
}
/*
* Converts IPv6 address in in6_addr structure to text representation .
* Returns : text form of the IP or NULL ( then error is set )
*/
char *
nmc_ip6_address_as_string ( const struct in6_addr * ip , GError * * error )
{
char buf [ INET6_ADDRSTRLEN ] ;
g_return_val_if_fail ( error = = NULL | | * error = = NULL , NULL ) ;
memset ( & buf , ' \0 ' , sizeof ( buf ) ) ;
if ( inet_ntop ( AF_INET6 , ip , buf , INET6_ADDRSTRLEN ) ) {
return g_strdup ( buf ) ;
} else {
if ( error ) {
int j ;
GString * ip6_str = g_string_new ( NULL ) ;
g_string_append_printf ( ip6_str , " %02X " , ip - > s6_addr [ 0 ] ) ;
for ( j = 1 ; j < 16 ; j + + )
g_string_append_printf ( ip6_str , " %02X " , ip - > s6_addr [ j ] ) ;
2012-07-25 13:57:45 +02:00
g_set_error ( error , NMCLI_ERROR , 0 , _ ( " Error converting IP6 address '%s' to text form " ) ,
2012-01-05 16:30:22 +01:00
ip6_str - > str ) ;
g_string_free ( ip6_str , TRUE ) ;
}
return NULL ;
}
}
2012-04-28 22:32:21 +01:00
/*
* Erase terminal line using ANSI escape sequences .
* It prints < ESC > [ 2 K sequence to erase the line and then \ r to return back
* to the beginning of the line .
*
* http : //www.termsys.demon.co.uk/vtansi.htm
*/
void
nmc_terminal_erase_line ( void )
{
2014-09-19 16:04:40 -04:00
/* We intentionally use printf(), not g_print() here, to ensure that
* GLib doesn ' t mistakenly try to convert the string .
*/
2012-04-28 22:32:21 +01:00
printf ( " \33 [2K \r " ) ;
fflush ( stdout ) ;
}
/*
* Print animated progress for an operation .
* Repeated calls of the function will show rotating slash in terminal followed
* by the string passed in ' str ' argument .
*/
void
nmc_terminal_show_progress ( const char * str )
{
static int idx = 0 ;
const char slashes [ 4 ] = { ' | ' , ' / ' , ' - ' , ' \\ ' } ;
nmc_terminal_erase_line ( ) ;
2014-09-19 16:04:40 -04:00
g_print ( " %c %s " , slashes [ idx + + ] , str ? str : " " ) ;
2012-04-28 22:32:21 +01:00
fflush ( stdout ) ;
if ( idx = = 4 )
idx = 0 ;
}
2013-04-05 23:42:56 +02:00
const char *
nmc_term_color_sequence ( NmcTermColor color )
{
switch ( color ) {
case NMC_TERM_COLOR_BLACK :
return " \33 [30m " ;
break ;
case NMC_TERM_COLOR_RED :
return " \33 [31m " ;
break ;
case NMC_TERM_COLOR_GREEN :
return " \33 [32m " ;
break ;
case NMC_TERM_COLOR_YELLOW :
return " \33 [33m " ;
break ;
case NMC_TERM_COLOR_BLUE :
return " \33 [34m " ;
break ;
case NMC_TERM_COLOR_MAGENTA :
return " \33 [35m " ;
break ;
case NMC_TERM_COLOR_CYAN :
return " \33 [36m " ;
break ;
case NMC_TERM_COLOR_WHITE :
return " \33 [37m " ;
break ;
default :
return " " ;
break ;
}
}
2015-02-17 13:20:37 +01:00
const char *
nmc_term_format_sequence ( NmcTermFormat format )
{
switch ( format ) {
case NMC_TERM_FORMAT_BOLD :
return " \33 [1m " ;
break ;
case NMC_TERM_FORMAT_DIM :
return " \33 [2m " ;
break ;
case NMC_TERM_FORMAT_UNDERLINE :
return " \33 [4m " ;
break ;
case NMC_TERM_FORMAT_BLINK :
return " \33 [5m " ;
break ;
case NMC_TERM_FORMAT_REVERSE :
return " \33 [7m " ;
break ;
case NMC_TERM_FORMAT_HIDDEN :
return " \33 [8m " ;
break ;
default :
return " " ;
break ;
}
}
2013-04-05 23:42:56 +02:00
char *
2015-02-17 13:20:37 +01:00
nmc_colorize ( NmcTermColor color , NmcTermFormat format , const char * fmt , . . . )
2013-04-05 23:42:56 +02:00
{
va_list args ;
2014-06-04 08:55:35 +02:00
char * str , * colored ;
2015-02-17 13:20:37 +01:00
const char * ansi_color , * color_end , * ansi_fmt , * format_end ;
static const char * end_seq = " \33 [0m " ;
2013-04-05 23:42:56 +02:00
va_start ( args , fmt ) ;
str = g_strdup_vprintf ( fmt , args ) ;
va_end ( args ) ;
ansi_color = nmc_term_color_sequence ( color ) ;
2015-02-17 13:20:37 +01:00
ansi_fmt = nmc_term_format_sequence ( format ) ;
color_end = * ansi_color ? end_seq : " " ;
format_end = * ansi_fmt ? end_seq : " " ;
2013-04-05 23:42:56 +02:00
2015-02-17 13:20:37 +01:00
colored = g_strdup_printf ( " %s%s%s%s%s " , ansi_fmt , ansi_color , str , color_end , format_end ) ;
2014-06-04 08:55:35 +02:00
g_free ( str ) ;
return colored ;
2013-04-05 23:42:56 +02:00
}
2015-02-13 22:05:55 +01:00
/*
* Count characters belonging to terminal color escape sequences .
* @ start points to beginning of the string , @ end points to the end ,
* or NULL if the string is nul - terminated .
*/
static int
nmc_count_color_escape_chars ( const char * start , const char * end )
{
int num = 0 ;
gboolean inside = FALSE ;
if ( end = = NULL )
end = start + strlen ( start ) ;
while ( start < end ) {
if ( * start = = ' \33 ' & & * ( start + 1 ) = = ' [ ' )
inside = TRUE ;
if ( inside )
num + + ;
if ( * start = = ' m ' )
inside = FALSE ;
start + + ;
}
return num ;
}
2015-02-13 13:25:16 +01:00
/* Filter out possible ANSI color escape sequences */
/* It directly modifies the passed string @str. */
void
nmc_filter_out_colors_inplace ( char * str )
{
const char * p1 ;
char * p2 ;
gboolean copy_char = TRUE ;
if ( ! str )
return ;
p1 = p2 = str ;
while ( * p1 ) {
if ( * p1 = = ' \33 ' & & * ( p1 + 1 ) = = ' [ ' )
copy_char = FALSE ;
if ( copy_char )
* p2 + + = * p1 ;
if ( ! copy_char & & * p1 = = ' m ' )
copy_char = TRUE ;
p1 + + ;
}
* p2 = ' \0 ' ;
}
/* Filter out possible ANSI color escape sequences */
char *
nmc_filter_out_colors ( const char * str )
{
char * filtered ;
if ( ! str )
return NULL ;
filtered = g_strdup ( str ) ;
nmc_filter_out_colors_inplace ( filtered ) ;
return filtered ;
}
2013-01-16 12:28:37 +01:00
/*
* Convert string to signed integer .
* If required , the resulting number is checked to be in the < min , max > range .
*/
gboolean
nmc_string_to_int_base ( const char * str ,
int base ,
gboolean range_check ,
long int min ,
long int max ,
long int * value )
{
char * end ;
long int tmp ;
errno = 0 ;
tmp = strtol ( str , & end , base ) ;
if ( errno | | * end ! = ' \0 ' | | ( range_check & & ( tmp < min | | tmp > max ) ) ) {
return FALSE ;
}
* value = tmp ;
return TRUE ;
}
/*
* Convert string to unsigned integer .
* If required , the resulting number is checked to be in the < min , max > range .
*/
gboolean
nmc_string_to_uint_base ( const char * str ,
int base ,
gboolean range_check ,
unsigned long int min ,
unsigned long int max ,
unsigned long int * value )
{
char * end ;
unsigned long int tmp ;
errno = 0 ;
tmp = strtoul ( str , & end , base ) ;
if ( errno | | * end ! = ' \0 ' | | ( range_check & & ( tmp < min | | tmp > max ) ) ) {
return FALSE ;
}
* value = tmp ;
return TRUE ;
}
gboolean
nmc_string_to_int ( const char * str ,
gboolean range_check ,
long int min ,
long int max ,
long int * value )
{
return nmc_string_to_int_base ( str , 10 , range_check , min , max , value ) ;
}
gboolean
nmc_string_to_uint ( const char * str ,
gboolean range_check ,
unsigned long int min ,
unsigned long int max ,
unsigned long int * value )
{
return nmc_string_to_uint_base ( str , 10 , range_check , min , max , value ) ;
}
2013-04-06 23:25:38 +02:00
gboolean
nmc_string_to_bool ( const char * str , gboolean * val_bool , GError * * error )
{
const char * s_true [ ] = { " true " , " yes " , " on " , NULL } ;
const char * s_false [ ] = { " false " , " no " , " off " , NULL } ;
g_return_val_if_fail ( error = = NULL | | * error = = NULL , FALSE ) ;
2014-05-14 16:33:28 +02:00
if ( g_strcmp0 ( str , " o " ) = = 0 ) {
g_set_error ( error , 1 , 0 ,
_ ( " '%s' is ambiguous (on x off) " ) , str ) ;
return FALSE ;
}
2013-04-06 23:25:38 +02:00
if ( nmc_string_is_valid ( str , s_true , NULL ) )
* val_bool = TRUE ;
else if ( nmc_string_is_valid ( str , s_false , NULL ) )
* val_bool = FALSE ;
else {
g_set_error ( error , 1 , 0 ,
_ ( " '%s' is not valid; use [%s] or [%s] " ) ,
str , " true, yes, on " , " false, no, off " ) ;
return FALSE ;
}
return TRUE ;
}
2012-11-21 16:53:23 +01:00
/*
* Ask user for input and return the string .
* The caller is responsible for freeing the returned string .
*/
char *
nmc_get_user_input ( const char * ask_str )
{
char * line = NULL ;
size_t line_ln = 0 ;
2013-04-15 13:40:14 +02:00
ssize_t num ;
2012-11-21 16:53:23 +01:00
2014-09-19 16:04:40 -04:00
g_print ( " %s " , ask_str ) ;
2013-04-15 13:40:14 +02:00
num = getline ( & line , & line_ln , stdin ) ;
2012-11-21 16:53:23 +01:00
/* Remove newline from the string */
2013-04-15 13:40:14 +02:00
if ( num < 1 | | ( num = = 1 & & line [ 0 ] = = ' \n ' ) ) {
2012-11-21 16:53:23 +01:00
g_free ( line ) ;
line = NULL ;
} else {
2013-04-15 13:40:14 +02:00
if ( line [ num - 1 ] = = ' \n ' )
line [ num - 1 ] = ' \0 ' ;
2012-11-21 16:53:23 +01:00
}
return line ;
}
2012-11-22 11:56:06 +01:00
/*
* Split string in ' line ' according to ' delim ' to ( argument ) array .
*/
int
2015-03-12 14:11:18 +01:00
nmc_string_to_arg_array ( const char * line , const char * delim , gboolean unquote ,
char * * * argv , int * argc )
2012-11-22 11:56:06 +01:00
{
char * * arr ;
2015-03-12 14:11:18 +01:00
arr = nmc_strsplit_set ( line ? line : " " , delim ? delim : " \t " , 0 ) ;
if ( unquote ) {
int i = 0 ;
char * s ;
size_t l ;
const char * quotes = " \" ' " ;
while ( arr & & arr [ i ] ) {
s = arr [ i ] ;
l = strlen ( s ) ;
if ( l > = 2 ) {
if ( strchr ( quotes , s [ 0 ] ) & & s [ l - 1 ] = = s [ 0 ] ) {
memmove ( s , s + 1 , l - 2 ) ;
s [ l - 2 ] = ' \0 ' ;
}
}
i + + ;
}
}
2012-11-22 11:56:06 +01:00
* argv = arr ;
2015-03-12 14:11:18 +01:00
* argc = g_strv_length ( arr ) ;
2012-11-22 11:56:06 +01:00
return 0 ;
}
2013-04-08 09:25:44 +02:00
/*
* Check whether ' input ' is contained in ' allowed ' array . It performs case
* insensitive comparison and supports shortcut strings if they are unique .
* Returns : a pointer to found string in allowed array on success or NULL .
* On failure : error - > code : 0 - string not found ; 1 - string is ambiguous
*/
const char *
nmc_string_is_valid ( const char * input , const char * * allowed , GError * * error )
{
const char * * p ;
size_t input_ln , p_len ;
gboolean prev_match = FALSE ;
const char * ret = NULL ;
g_return_val_if_fail ( error = = NULL | | * error = = NULL , NULL ) ;
if ( ! input | | ! * input )
goto finish ;
input_ln = strlen ( input ) ;
for ( p = allowed ; p & & * p ; p + + ) {
p_len = strlen ( * p ) ;
if ( g_ascii_strncasecmp ( input , * p , input_ln ) = = 0 ) {
if ( input_ln = = p_len ) {
ret = * p ;
break ;
}
if ( ! prev_match )
ret = * p ;
else {
g_set_error ( error , 1 , 1 , _ ( " '%s' is ambiguous (%s x %s) " ) ,
input , ret , * p ) ;
return NULL ;
}
prev_match = TRUE ;
}
}
finish :
if ( ret = = NULL ) {
char * valid_vals = g_strjoinv ( " , " , ( char * * ) allowed ) ;
2014-12-12 21:38:37 +01:00
if ( ! input | | ! * input )
g_set_error ( error , 1 , 0 , _ ( " missing name, try one of [%s] " ) , valid_vals ) ;
else
g_set_error ( error , 1 , 0 , _ ( " '%s' not among [%s] " ) , input , valid_vals ) ;
2013-09-05 19:16:12 +02:00
2013-04-08 09:25:44 +02:00
g_free ( valid_vals ) ;
}
return ret ;
}
2013-01-18 15:21:00 +01:00
/*
* Convert string array ( char * * ) to GSList .
*
* Returns : pointer to newly created GSList . Caller should free it .
*/
GSList *
nmc_util_strv_to_slist ( char * * strv )
{
GSList * list = NULL ;
guint i = 0 ;
while ( strv & & strv [ i ] )
list = g_slist_prepend ( list , g_strdup ( strv [ i + + ] ) ) ;
return g_slist_reverse ( list ) ;
}
2014-10-04 17:07:42 +02:00
/*
* Convert string array ( char * * ) to description string in the form of :
* " [string1, string2, ] "
*
* Returns : a newly allocated string . Caller must free it with g_free ( ) .
*/
char *
nmc_util_strv_for_display ( const char * * strv )
{
GString * result ;
guint i = 0 ;
result = g_string_sized_new ( 150 ) ;
g_string_append_c ( result , ' [ ' ) ;
while ( strv & & strv [ i ] ) {
if ( result - > len > 1 )
g_string_append ( result , " , " ) ;
g_string_append ( result , strv [ i ] ) ;
i + + ;
}
g_string_append_c ( result , ' ] ' ) ;
return g_string_free ( result , FALSE ) ;
}
2013-01-18 15:21:00 +01:00
/*
* Wrapper function for g_strsplit_set ( ) that removes empty strings
* from the vector as they are not useful in most cases .
*/
char * *
nmc_strsplit_set ( const char * str , const char * delimiter , int max_tokens )
{
char * * result ;
uint i ;
uint j ;
result = g_strsplit_set ( str , delimiter , max_tokens ) ;
/* remove empty strings */
for ( i = 0 ; result & & result [ i ] ; i + + ) {
if ( * ( result [ i ] ) = = ' \0 ' ) {
g_free ( result [ i ] ) ;
for ( j = i ; result [ j ] ; j + + )
result [ j ] = result [ j + 1 ] ;
i - - ;
}
}
return result ;
}
2010-04-26 17:32:18 +02:00
/*
2015-02-13 22:05:55 +01:00
* Find out how many columns an UTF - 8 string occupies on the screen .
2010-04-26 17:32:18 +02:00
*/
int
nmc_string_screen_width ( const char * start , const char * end )
{
int width = 0 ;
2015-02-13 22:05:55 +01:00
const char * p = start ;
2010-04-26 17:32:18 +02:00
if ( end = = NULL )
end = start + strlen ( start ) ;
2015-02-13 22:05:55 +01:00
while ( p < end ) {
width + = g_unichar_iswide ( g_utf8_get_char ( p ) ) ? 2 : g_unichar_iszerowidth ( g_utf8_get_char ( p ) ) ? 0 : 1 ;
p = g_utf8_next_char ( p ) ;
2010-04-26 17:32:18 +02:00
}
2015-02-13 22:05:55 +01:00
/* Subtract color escape sequences as they don't occupy space. */
return width - nmc_count_color_escape_chars ( start , NULL ) ;
2010-04-26 17:32:18 +02:00
}
2012-01-03 15:07:17 +01:00
void
2013-03-05 15:50:11 +01:00
set_val_str ( NmcOutputField fields_array [ ] , guint32 idx , char * value )
2012-01-03 15:07:17 +01:00
{
fields_array [ idx ] . value = value ;
2013-05-22 08:36:09 +02:00
fields_array [ idx ] . value_is_array = FALSE ;
fields_array [ idx ] . free_value = TRUE ;
}
void
set_val_strc ( NmcOutputField fields_array [ ] , guint32 idx , const char * value )
{
fields_array [ idx ] . value = ( char * ) value ;
fields_array [ idx ] . value_is_array = FALSE ;
fields_array [ idx ] . free_value = FALSE ;
2012-01-03 15:07:17 +01:00
}
void
2013-03-05 15:50:11 +01:00
set_val_arr ( NmcOutputField fields_array [ ] , guint32 idx , char * * value )
2012-01-03 15:07:17 +01:00
{
fields_array [ idx ] . value = value ;
2013-05-22 08:36:09 +02:00
fields_array [ idx ] . value_is_array = TRUE ;
fields_array [ idx ] . free_value = TRUE ;
}
void
set_val_arrc ( NmcOutputField fields_array [ ] , guint32 idx , const char * * value )
{
fields_array [ idx ] . value = ( char * * ) value ;
fields_array [ idx ] . value_is_array = TRUE ;
fields_array [ idx ] . free_value = FALSE ;
2012-01-03 15:07:17 +01:00
}
2015-02-13 08:54:32 +01:00
void
set_val_color_all ( NmcOutputField fields_array [ ] , NmcTermColor color )
{
int i ;
for ( i = 0 ; fields_array [ i ] . name ; i + + ) {
fields_array [ i ] . color = color ;
}
}
2015-02-17 13:20:37 +01:00
void
set_val_color_fmt_all ( NmcOutputField fields_array [ ] , NmcTermFormat format )
{
int i ;
for ( i = 0 ; fields_array [ i ] . name ; i + + ) {
fields_array [ i ] . color_fmt = format ;
}
}
2013-03-25 10:44:15 -04:00
/*
* Free ' value ' members in array of NmcOutputField
*/
void
nmc_free_output_field_values ( NmcOutputField fields_array [ ] )
{
2013-05-22 08:36:09 +02:00
NmcOutputField * iter = fields_array ;
while ( iter & & iter - > name ) {
if ( iter - > free_value ) {
if ( iter - > value_is_array )
g_strfreev ( ( char * * ) iter - > value ) ;
else
g_free ( ( char * ) iter - > value ) ;
iter - > value = NULL ;
}
iter + + ;
2013-03-25 10:44:15 -04:00
}
}
2013-12-10 12:00:53 +01:00
/**
* parse_output_fields :
* @ field_str : comma - separated field names to parse
* @ fields_array : array of allowed fields
* @ parse_groups : whether the fields can contain group prefix ( e . g . general . driver )
* @ group_fields : ( out ) ( allow - none ) : array of field names for particular groups
* @ error : ( out ) ( allow - none ) : location to store error , or % NULL
*
* Parses comma separated fields in @ fields_str according to @ fields_array .
* When @ parse_groups is % TRUE , fields can be in the form ' group . field ' . Then
* @ group_fields will be filled with the required field for particular group .
* @ group_fields array corresponds to the returned array .
* Examples :
* @ field_str : " type,name,uuid " | " ip4,general.device " | " ip4.address,ip6 "
* returned array : 2 0 1 | 7 0 | 7 9
* @ group_fields : NULL NULL NULL | NULL " device " | " address " NULL
*
* Returns : # GArray with indices representing fields in @ fields_array .
* Caller is responsible for freeing the array .
2010-03-18 15:39:15 +01:00
*/
GArray *
2013-12-10 12:00:53 +01:00
parse_output_fields ( const char * fields_str ,
const NmcOutputField fields_array [ ] ,
gboolean parse_groups ,
GPtrArray * * group_fields ,
GError * * error )
2010-03-18 15:39:15 +01:00
{
char * * fields , * * iter ;
GArray * array ;
2013-12-10 12:00:53 +01:00
int i , j ;
2010-03-18 15:39:15 +01:00
g_return_val_if_fail ( error = = NULL | | * error = = NULL , NULL ) ;
2013-12-10 12:00:53 +01:00
g_return_val_if_fail ( group_fields = = NULL | | * group_fields = = NULL , NULL ) ;
2010-03-18 15:39:15 +01:00
array = g_array_new ( FALSE , FALSE , sizeof ( int ) ) ;
2013-12-10 12:00:53 +01:00
if ( parse_groups & & group_fields )
* group_fields = g_ptr_array_new_full ( 20 , ( GDestroyNotify ) g_free ) ;
2010-03-18 15:39:15 +01:00
/* Split supplied fields string */
fields = g_strsplit_set ( fields_str , " , " , - 1 ) ;
for ( iter = fields ; iter & & * iter ; iter + + ) {
2013-12-10 12:00:53 +01:00
int idx = - 1 ;
g_strstrip ( * iter ) ;
if ( parse_groups ) {
/* e.g. "general.device,general.driver,ip4,ip6" */
gboolean found = FALSE ;
char * left = * iter ;
char * right = strchr ( * iter , ' . ' ) ;
if ( right )
* right + + = ' \0 ' ;
for ( i = 0 ; fields_array [ i ] . name ; i + + ) {
if ( strcasecmp ( left , fields_array [ i ] . name ) = = 0 ) {
NmcOutputField * valid_names = fields_array [ i ] . group ;
idx = i ;
if ( ! right & & ! valid_names ) {
found = TRUE ;
break ;
}
for ( j = 0 ; valid_names & & valid_names [ j ] . name ; j + + ) {
if ( ! right | | strcasecmp ( right , valid_names [ j ] . name ) = = 0 ) {
found = TRUE ;
break ;
}
}
2014-07-27 02:49:40 +02:00
if ( found )
break ;
2013-12-10 12:00:53 +01:00
}
}
if ( found ) {
/* Add index to array, and field name (or NULL) to group_fields array */
g_array_append_val ( array , idx ) ;
2014-04-15 16:54:38 +02:00
if ( group_fields & & * group_fields )
2013-12-10 12:00:53 +01:00
g_ptr_array_add ( * group_fields , g_strdup ( right ) ) ;
}
if ( right )
* ( right - 1 ) = ' . ' ; /* Restore the original string */
} else {
/* e.g. "general,ip4,ip6" */
for ( i = 0 ; fields_array [ i ] . name ; i + + ) {
if ( strcasecmp ( * iter , fields_array [ i ] . name ) = = 0 ) {
g_array_append_val ( array , i ) ;
break ;
}
2010-03-18 15:39:15 +01:00
}
}
2013-12-10 12:00:53 +01:00
/* Field was not found - error case */
2010-03-18 15:39:15 +01:00
if ( fields_array [ i ] . name = = NULL ) {
2013-12-10 12:00:53 +01:00
/* Set GError */
2010-03-18 15:39:15 +01:00
if ( ! strcasecmp ( * iter , " all " ) | | ! strcasecmp ( * iter , " common " ) )
2012-07-25 13:57:45 +02:00
g_set_error ( error , NMCLI_ERROR , 0 , _ ( " field '%s' has to be alone " ) , * iter ) ;
2013-11-07 14:47:12 +01:00
else {
char * allowed_fields = nmc_get_allowed_fields ( fields_array , idx ) ;
2013-12-10 12:00:53 +01:00
g_set_error ( error , NMCLI_ERROR , 1 , _ ( " invalid field '%s'; allowed fields: %s " ) ,
2013-11-07 14:47:12 +01:00
* iter , allowed_fields ) ;
g_free ( allowed_fields ) ;
}
2013-12-10 12:00:53 +01:00
/* Free arrays on error */
2010-03-18 15:39:15 +01:00
g_array_free ( array , TRUE ) ;
array = NULL ;
2013-12-10 12:00:53 +01:00
if ( group_fields & & * group_fields ) {
g_ptr_array_free ( * group_fields , TRUE ) ;
* group_fields = NULL ;
}
2010-03-18 15:39:15 +01:00
goto done ;
}
}
done :
2010-03-19 15:46:25 +01:00
if ( fields )
g_strfreev ( fields ) ;
2010-03-18 15:39:15 +01:00
return array ;
}
2013-11-07 14:47:12 +01:00
/**
* nmc_get_allowed_fields :
* @ fields_array : array of fields
* @ group_idx : index to the array ( for second - level array in ' group ' member ) ,
* or - 1
*
* Returns : string of allowed fields names .
* Caller is responsible for freeing the array .
*/
char *
nmc_get_allowed_fields ( const NmcOutputField fields_array [ ] , int group_idx )
{
GString * allowed_fields = g_string_sized_new ( 256 ) ;
int i ;
if ( group_idx ! = - 1 & & fields_array [ group_idx ] . group ) {
NmcOutputField * second_level = fields_array [ group_idx ] . group ;
for ( i = 0 ; second_level [ i ] . name ; i + + )
g_string_append_printf ( allowed_fields , " %s.%s, " ,
fields_array [ group_idx ] . name , second_level [ i ] . name ) ;
} else {
for ( i = 0 ; fields_array [ i ] . name ; i + + )
g_string_append_printf ( allowed_fields , " %s, " , fields_array [ i ] . name ) ;
}
g_string_truncate ( allowed_fields , allowed_fields - > len - 1 ) ;
return g_string_free ( allowed_fields , FALSE ) ;
}
2010-03-22 18:43:28 +01:00
gboolean
nmc_terse_option_check ( NMCPrintOutput print_output , const char * fields , GError * * error )
{
g_return_val_if_fail ( error = = NULL | | * error = = NULL , FALSE ) ;
if ( print_output = = NMC_PRINT_TERSE ) {
if ( ! fields ) {
2012-07-25 13:57:45 +02:00
g_set_error_literal ( error , NMCLI_ERROR , 0 , _ ( " Option '--terse' requires specifying '--fields' " ) ) ;
2010-03-22 18:43:28 +01:00
return FALSE ;
} else if ( ! strcasecmp ( fields , " all " )
| | ! strcasecmp ( fields , " common " ) ) {
2012-07-25 13:57:45 +02:00
g_set_error ( error , NMCLI_ERROR , 0 , _ ( " Option '--terse' requires specific '--fields' option values , not '%s' " ) , fields ) ;
2010-03-22 18:43:28 +01:00
return FALSE ;
}
}
return TRUE ;
}
2013-05-22 08:36:09 +02:00
NmcOutputField *
nmc_dup_fields_array ( NmcOutputField fields [ ] , size_t size , guint32 flags )
{
NmcOutputField * row ;
row = g_malloc0 ( size ) ;
memcpy ( row , fields , size ) ;
row [ 0 ] . flags = flags ;
return row ;
}
void
nmc_empty_output_fields ( NmCli * nmc )
{
guint i ;
/* Free values in field structure */
for ( i = 0 ; i < nmc - > output_data - > len ; i + + ) {
NmcOutputField * fld_arr = g_ptr_array_index ( nmc - > output_data , i ) ;
nmc_free_output_field_values ( fld_arr ) ;
}
/* Empty output_data array */
if ( nmc - > output_data - > len > 0 )
g_ptr_array_remove_range ( nmc - > output_data , 0 , nmc - > output_data - > len ) ;
2013-10-03 10:08:22 -04:00
if ( nmc - > print_fields . indices ) {
g_array_free ( nmc - > print_fields . indices , TRUE ) ;
nmc - > print_fields . indices = NULL ;
}
2013-05-22 08:36:09 +02:00
}
static char *
2015-02-13 08:54:32 +01:00
colorize_string ( gboolean colorize ,
NmcTermColor color ,
2015-02-17 13:20:37 +01:00
NmcTermFormat color_fmt ,
2015-02-13 08:54:32 +01:00
const char * str ,
gboolean * dealloc )
{
char * out ;
if ( colorize
2015-02-17 13:20:37 +01:00
& & ( color ! = NMC_TERM_COLOR_NORMAL | | color_fmt ! = NMC_TERM_FORMAT_NORMAL ) ) {
out = nmc_colorize ( color , color_fmt , str ) ;
2015-02-13 08:54:32 +01:00
* dealloc = TRUE ;
} else {
out = ( char * ) str ;
* dealloc = FALSE ;
}
return out ;
}
static char *
get_value_to_print ( NmcOutputField * field ,
2013-05-22 08:36:09 +02:00
gboolean field_name ,
const char * not_set_str ,
2015-02-13 08:54:32 +01:00
gboolean * dealloc ,
gboolean colorize )
2013-05-22 08:36:09 +02:00
{
2015-02-13 08:54:32 +01:00
gboolean is_array = field - > value_is_array ;
char * value , * out ;
gboolean free_value , free_out ;
2013-05-22 08:36:09 +02:00
if ( field_name )
2015-02-13 08:54:32 +01:00
value = _ ( field - > name_l10n ) ;
2013-05-22 08:36:09 +02:00
else
2015-02-13 08:54:32 +01:00
value = field - > value ?
( is_array ? g_strjoinv ( " | " , ( char * * ) field - > value ) :
( char * ) field - > value ) :
2013-05-22 08:36:09 +02:00
( char * ) not_set_str ;
2015-02-13 08:54:32 +01:00
free_value = field - > value & & is_array & & ! field_name ;
/* colorize the value */
2015-02-17 13:20:37 +01:00
out = colorize_string ( colorize , field - > color , field - > color_fmt , value , & free_out ) ;
2015-02-13 08:54:32 +01:00
if ( free_out ) {
if ( free_value )
g_free ( value ) ;
* dealloc = TRUE ;
} else
* dealloc = free_value ;
return out ;
2013-05-22 08:36:09 +02:00
}
2010-03-20 14:08:06 +01:00
/*
* Print both headers or values of ' field_values ' array .
2013-05-22 08:36:09 +02:00
* Entries to print and their order are specified via indices in
* ' nmc - > print_fields . indices ' array .
* Various flags influencing the output of fields are set up in the first item
* of ' field_values ' array .
2010-03-20 14:08:06 +01:00
*/
2010-03-18 15:39:15 +01:00
void
2013-05-22 08:36:09 +02:00
print_required_fields ( NmCli * nmc , const NmcOutputField field_values [ ] )
2010-03-18 15:39:15 +01:00
{
GString * str ;
int width1 , width2 ;
int table_width = 0 ;
char * line = NULL ;
char * indent_str ;
2012-06-04 12:25:43 +02:00
const char * not_set_str = " -- " ;
2012-01-03 15:07:17 +01:00
int i ;
2013-05-22 08:36:09 +02:00
const NmcPrintFields fields = nmc - > print_fields ;
gboolean multiline = nmc - > multiline_output ;
gboolean terse = ( nmc - > print_output = = NMC_PRINT_TERSE ) ;
gboolean pretty = ( nmc - > print_output = = NMC_PRINT_PRETTY ) ;
gboolean escape = nmc - > escape_values ;
gboolean main_header_add = field_values [ 0 ] . flags & NMC_OF_FLAG_MAIN_HEADER_ADD ;
gboolean main_header_only = field_values [ 0 ] . flags & NMC_OF_FLAG_MAIN_HEADER_ONLY ;
gboolean field_names = field_values [ 0 ] . flags & NMC_OF_FLAG_FIELD_NAMES ;
gboolean section_prefix = field_values [ 0 ] . flags & NMC_OF_FLAG_SECTION_PREFIX ;
2010-03-24 19:05:35 +01:00
gboolean main_header = main_header_add | | main_header_only ;
2015-02-13 08:54:32 +01:00
gboolean colorize ;
2010-03-18 15:39:15 +01:00
2010-03-20 14:08:06 +01:00
/* No headers are printed in terse mode:
2010-03-22 18:43:28 +01:00
* - neither main header nor field ( column ) names
2010-03-20 14:08:06 +01:00
*/
2010-03-24 19:05:35 +01:00
if ( ( main_header_only | | field_names ) & & terse )
2010-03-18 15:39:15 +01:00
return ;
2015-02-13 08:54:32 +01:00
/* Only show colors if the output is a terminal */
2015-02-16 12:18:42 +01:00
colorize = nmc - > use_colors = = NMC_USE_COLOR_YES ? TRUE :
nmc - > use_colors = = NMC_USE_COLOR_NO ? FALSE :
isatty ( fileno ( stdout ) ) ;
2015-02-13 08:54:32 +01:00
2010-03-18 15:39:15 +01:00
if ( multiline ) {
/* --- Multiline mode --- */
2010-03-20 14:08:06 +01:00
enum { ML_HEADER_WIDTH = 79 } ;
2011-09-07 12:20:56 +02:00
enum { ML_VALUE_INDENT = 40 } ;
2010-03-22 18:43:28 +01:00
if ( main_header & & pretty ) {
/* Print the main header */
2010-04-26 17:32:18 +02:00
int header_width = nmc_string_screen_width ( fields . header_name , NULL ) + 4 ;
2010-03-20 14:08:06 +01:00
table_width = header_width < ML_HEADER_WIDTH ? ML_HEADER_WIDTH : header_width ;
line = g_strnfill ( ML_HEADER_WIDTH , ' = ' ) ;
2010-03-18 15:39:15 +01:00
width1 = strlen ( fields . header_name ) ;
2010-04-26 17:32:18 +02:00
width2 = nmc_string_screen_width ( fields . header_name , NULL ) ;
2014-09-19 16:04:40 -04:00
g_print ( " %s \n " , line ) ;
g_print ( " %*s \n " , ( table_width + width2 ) / 2 + width1 - width2 , fields . header_name ) ;
g_print ( " %s \n " , line ) ;
2010-03-18 15:39:15 +01:00
g_free ( line ) ;
}
/* Print values */
2010-03-24 19:05:35 +01:00
if ( ! main_header_only & & ! field_names ) {
2010-03-18 15:39:15 +01:00
for ( i = 0 ; i < fields . indices - > len ; i + + ) {
char * tmp ;
2015-02-13 08:54:32 +01:00
gboolean free_print_val ;
2012-01-03 15:07:17 +01:00
int idx = g_array_index ( fields . indices , int , i ) ;
2013-05-22 08:36:09 +02:00
gboolean is_array = field_values [ idx ] . value_is_array ;
2012-01-03 15:07:17 +01:00
/* section prefix can't be an array */
2013-05-22 08:36:09 +02:00
g_assert ( ! is_array | | ! section_prefix | | idx ! = 0 ) ;
2012-01-03 15:07:17 +01:00
2010-03-24 19:05:35 +01:00
if ( section_prefix & & idx = = 0 ) /* The first field is section prefix */
continue ;
2012-01-03 15:07:17 +01:00
2013-05-22 08:36:09 +02:00
if ( is_array ) {
2012-01-03 15:07:17 +01:00
/* value is a null-terminated string array */
2015-02-13 08:54:32 +01:00
const char * * p , * val ;
char * print_val ;
2012-01-03 15:07:17 +01:00
int j ;
for ( p = ( const char * * ) field_values [ idx ] . value , j = 1 ; p & & * p ; p + + , j + + ) {
2015-02-13 08:54:32 +01:00
val = * p ? * p : not_set_str ;
2015-02-17 13:20:37 +01:00
print_val = colorize_string ( colorize , field_values [ idx ] . color , field_values [ idx ] . color_fmt ,
2015-02-13 08:54:32 +01:00
val , & free_print_val ) ;
2013-05-22 08:36:09 +02:00
tmp = g_strdup_printf ( " %s%s%s[%d]: " ,
section_prefix ? ( const char * ) field_values [ 0 ] . value : " " ,
section_prefix ? " . " : " " ,
_ ( field_values [ idx ] . name_l10n ) ,
j ) ;
2013-05-28 09:21:02 +02:00
width1 = strlen ( tmp ) ;
width2 = nmc_string_screen_width ( tmp , NULL ) ;
2015-02-13 08:54:32 +01:00
g_print ( " %-*s%s \n " , terse ? 0 : ML_VALUE_INDENT + width1 - width2 , tmp , print_val ) ;
2012-01-03 15:07:17 +01:00
g_free ( tmp ) ;
2015-02-13 08:54:32 +01:00
if ( free_print_val )
g_free ( print_val ) ;
2012-01-03 15:07:17 +01:00
}
} else {
/* value is a string */
const char * hdr_name = ( const char * ) field_values [ 0 ] . value ;
const char * val = ( const char * ) field_values [ idx ] . value ;
2015-02-13 08:54:32 +01:00
char * print_val ;
2012-01-03 15:07:17 +01:00
2015-02-13 08:54:32 +01:00
val = val ? val : not_set_str ;
2015-02-17 13:20:37 +01:00
print_val = colorize_string ( colorize , field_values [ idx ] . color , field_values [ idx ] . color_fmt ,
2015-02-13 08:54:32 +01:00
val , & free_print_val ) ;
2013-05-22 08:36:09 +02:00
tmp = g_strdup_printf ( " %s%s%s: " ,
section_prefix ? hdr_name : " " ,
section_prefix ? " . " : " " ,
_ ( field_values [ idx ] . name_l10n ) ) ;
2013-05-28 09:21:02 +02:00
width1 = strlen ( tmp ) ;
width2 = nmc_string_screen_width ( tmp , NULL ) ;
2015-02-13 08:54:32 +01:00
g_print ( " %-*s%s \n " , terse ? 0 : ML_VALUE_INDENT + width1 - width2 , tmp , print_val ) ;
2012-01-03 15:07:17 +01:00
g_free ( tmp ) ;
2015-02-13 08:54:32 +01:00
if ( free_print_val )
g_free ( print_val ) ;
2012-01-03 15:07:17 +01:00
}
2010-03-18 15:39:15 +01:00
}
if ( pretty ) {
2010-03-20 14:08:06 +01:00
line = g_strnfill ( ML_HEADER_WIDTH , ' - ' ) ;
2014-09-19 16:04:40 -04:00
g_print ( " %s \n " , line ) ;
2010-03-18 15:39:15 +01:00
g_free ( line ) ;
}
}
return ;
}
/* --- Tabular mode: each line = one object --- */
str = g_string_new ( NULL ) ;
for ( i = 0 ; i < fields . indices - > len ; i + + ) {
2012-01-03 15:07:17 +01:00
int idx = g_array_index ( fields . indices , int , i ) ;
2013-05-22 08:36:09 +02:00
gboolean dealloc ;
2015-02-13 08:54:32 +01:00
char * value = get_value_to_print ( ( NmcOutputField * ) field_values + idx , field_names ,
not_set_str , & dealloc , colorize ) ;
2012-01-03 15:07:17 +01:00
2010-03-18 15:39:15 +01:00
if ( terse ) {
if ( escape ) {
const char * p = value ;
while ( * p ) {
if ( * p = = ' : ' | | * p = = ' \\ ' )
g_string_append_c ( str , ' \\ ' ) ; /* Escaping by '\' */
g_string_append_c ( str , * p ) ;
p + + ;
}
}
2012-01-03 15:07:17 +01:00
else
2010-03-18 15:39:15 +01:00
g_string_append_printf ( str , " %s " , value ) ;
g_string_append_c ( str , ' : ' ) ; /* Column separator */
} else {
width1 = strlen ( value ) ;
2010-04-26 17:32:18 +02:00
width2 = nmc_string_screen_width ( value , NULL ) ; /* Width of the string (in screen colums) */
2012-01-03 15:07:17 +01:00
g_string_append_printf ( str , " %-*s " , field_values [ idx ] . width + width1 - width2 , strlen ( value ) > 0 ? value : " -- " ) ;
2010-03-18 15:39:15 +01:00
g_string_append_c ( str , ' ' ) ; /* Column separator */
table_width + = field_values [ idx ] . width + width1 - width2 + 1 ;
}
2012-01-03 15:07:17 +01:00
2013-05-22 08:36:09 +02:00
if ( dealloc )
2012-01-03 15:07:17 +01:00
g_free ( value ) ;
2010-03-18 15:39:15 +01:00
}
2010-03-22 18:43:28 +01:00
/* Print the main table header */
if ( main_header & & pretty ) {
2010-04-26 17:32:18 +02:00
int header_width = nmc_string_screen_width ( fields . header_name , NULL ) + 4 ;
2010-03-20 14:08:06 +01:00
table_width = table_width < header_width ? header_width : table_width ;
2010-03-18 15:39:15 +01:00
line = g_strnfill ( table_width , ' = ' ) ;
width1 = strlen ( fields . header_name ) ;
2010-04-26 17:32:18 +02:00
width2 = nmc_string_screen_width ( fields . header_name , NULL ) ;
2014-09-19 16:04:40 -04:00
g_print ( " %s \n " , line ) ;
g_print ( " %*s \n " , ( table_width + width2 ) / 2 + width1 - width2 , fields . header_name ) ;
g_print ( " %s \n " , line ) ;
2010-03-18 15:39:15 +01:00
g_free ( line ) ;
}
2010-03-20 14:08:06 +01:00
/* Print actual values */
2010-03-24 19:05:35 +01:00
if ( ! main_header_only & & str - > len > 0 ) {
2010-03-18 15:39:15 +01:00
g_string_truncate ( str , str - > len - 1 ) ; /* Chop off last column separator */
if ( fields . indent > 0 ) {
indent_str = g_strnfill ( fields . indent , ' ' ) ;
2010-03-20 14:08:06 +01:00
g_string_prepend ( str , indent_str ) ;
2010-03-18 15:39:15 +01:00
g_free ( indent_str ) ;
}
2014-09-19 16:04:40 -04:00
g_print ( " %s \n " , str - > str ) ;
2010-03-18 15:39:15 +01:00
}
2010-03-20 14:08:06 +01:00
/* Print horizontal separator */
2010-03-24 19:05:35 +01:00
if ( ! main_header_only & & field_names & & pretty ) {
2010-03-18 15:39:15 +01:00
if ( str - > len > 0 ) {
line = g_strnfill ( table_width , ' - ' ) ;
2014-09-19 16:04:40 -04:00
g_print ( " %s \n " , line ) ;
2010-03-18 15:39:15 +01:00
g_free ( line ) ;
}
}
g_string_free ( str , TRUE ) ;
}
2013-05-22 08:36:09 +02:00
/*
* Print nmc - > output_data
*
* It first finds out maximal string length in columns and fill the value to
* ' width ' member of NmcOutputField , so that columns in tabular output are
* properly aligned . Then each object ( row in tabular ) is printed using
* print_required_fields ( ) function .
*/
void
print_data ( NmCli * nmc )
{
int i , j ;
size_t len ;
NmcOutputField * row ;
int num_fields = 0 ;
if ( ! nmc - > output_data | | nmc - > output_data - > len < 1 )
return ;
/* How many fields? */
row = g_ptr_array_index ( nmc - > output_data , 0 ) ;
while ( row - > name ) {
num_fields + + ;
row + + ;
}
/* Find out maximal string lengths */
for ( i = 0 ; i < num_fields ; i + + ) {
size_t max_width = 0 ;
for ( j = 0 ; j < nmc - > output_data - > len ; j + + ) {
gboolean field_names , dealloc ;
char * value ;
row = g_ptr_array_index ( nmc - > output_data , j ) ;
field_names = row [ 0 ] . flags & NMC_OF_FLAG_FIELD_NAMES ;
2015-02-13 08:54:32 +01:00
value = get_value_to_print ( row + i , field_names , " -- " , & dealloc , FALSE ) ;
2013-05-22 08:36:09 +02:00
len = nmc_string_screen_width ( value , NULL ) ;
max_width = len > max_width ? len : max_width ;
if ( dealloc )
g_free ( value ) ;
}
for ( j = 0 ; j < nmc - > output_data - > len ; j + + ) {
row = g_ptr_array_index ( nmc - > output_data , j ) ;
row [ i ] . width = max_width + 1 ;
}
}
/* Now we can print the data. */
for ( i = 0 ; i < nmc - > output_data - > len ; i + + ) {
row = g_ptr_array_index ( nmc - > output_data , i ) ;
print_required_fields ( nmc , row ) ;
}
}
2011-02-16 17:36:50 +01:00
/*
* Compare versions of nmcli and NM daemon .
* Return : TRUE - the versions match ( when only major and minor match , print a warning )
* FALSE - versions mismatch
*/
gboolean
nmc_versions_match ( NmCli * nmc )
{
const char * nm_ver = NULL ;
const char * dot ;
gboolean match = FALSE ;
g_return_val_if_fail ( nmc ! = NULL , FALSE ) ;
/* --nocheck option - don't compare the versions */
if ( nmc - > nocheck_ver )
return TRUE ;
nmc - > get_client ( nmc ) ;
nm_ver = nm_client_get_version ( nmc - > client ) ;
if ( nm_ver ) {
if ( ! strcmp ( nm_ver , VERSION ) )
match = TRUE ;
else {
dot = strchr ( nm_ver , ' . ' ) ;
if ( dot ) {
dot = strchr ( dot + 1 , ' . ' ) ;
if ( dot & & ! strncmp ( nm_ver , VERSION , dot - nm_ver ) ) {
2014-09-19 16:04:40 -04:00
g_printerr ( _ ( " Warning: nmcli (%s) and NetworkManager (%s) versions don't match. Use --nocheck to suppress the warning. \n " ) ,
VERSION , nm_ver ) ;
2011-02-16 17:36:50 +01:00
match = TRUE ;
}
}
}
}
if ( ! match ) {
g_string_printf ( nmc - > return_text , _ ( " Error: nmcli (%s) and NetworkManager (%s) versions don't match. Force execution using --nocheck, but the results are unpredictable. " ) ,
VERSION , nm_ver ? nm_ver : _ ( " unknown " ) ) ;
nmc - > return_value = NMC_RESULT_ERROR_VERSIONS_MISMATCH ;
}
return match ;
}