2017-10-31 11:24:21 +03:00
/*
* virsh - completer . c : virsh completer callbacks
*
* Copyright ( C ) 2017 Red Hat , Inc .
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library 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
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library . If not , see
* < http : //www.gnu.org/licenses/>.
*/
# include <config.h>
# include "virsh-completer.h"
# include "viralloc.h"
# include "virstring.h"
2019-01-22 14:23:07 +03:00
/**
* A completer callback is a function that accepts three arguments :
*
* @ ctl : virsh control structure
* @ cmd : parsed input
* @ flags : optional flags to alter completer ' s behaviour
*
* The @ ctl contains connection to the daemon ( should the
* completer need it ) . Any completer that requires a connection
* must check whether connection is still alive .
*
* The @ cmd contains parsed user input which might be missing
* some arguments ( if user is still typing the command ) , but may
* already contain important data . For instance if the completer
* needs domain XML it may inspect @ cmd to find - - domain . Using
* existing wrappers is advised . If @ cmd does not contain all
* necessary bits , completer might return sensible defaults ( i . e .
* generic values not tailored to specific use case ) or return
* NULL ( i . e . no strings are offered to the user for completion ) .
*
* The @ flags contains a . completer_flags value defined for each
* use or 0 if no . completer_flags were specified . If a completer
2019-03-28 19:42:23 +03:00
* is generic enough @ flags can be used to alter its behaviour .
2019-01-22 14:23:07 +03:00
* For instance , a completer to fetch names of domains can use
* @ flags to return names of only domains in a particular state
* that the command accepts .
*
* Under no circumstances should a completer output anything .
* Neither to stdout nor to stderr . This would harm the user
* experience .
*/
2022-03-12 07:37:50 +03:00
/**
* virshEnumComplete :
* @ last : The number of element in enum ( pass VIR_XXX_LAST )
* @ intToStr : integer to string conversion ( pass virXXXTypeToString )
*
* Convenient function to generate completions across all values
* of given enum . The enum , or values we want to generate , must
* start at 0 and be continuous until @ last .
*
* Returns : string list of completions .
*/
char * *
virshEnumComplete ( unsigned int last ,
const char * ( * intToStr ) ( int ) )
{
char * * ret = NULL ;
size_t i ;
ret = g_new0 ( char * , last + 1 ) ;
for ( i = 0 ; i < last ; i + + )
ret [ i ] = g_strdup ( intToStr ( i ) ) ;
return ret ;
}
2019-06-18 13:16:17 +03:00
/**
* virshCommaStringListComplete :
* @ input : user input so far
* @ options : ALL options available for argument
*
* Some arguments to our commands accept the following form :
*
* virsh command - - arg str1 , str2 , str3
*
2020-10-02 17:07:27 +03:00
* This does not play nicely with our completer functions , because
2019-06-18 13:16:17 +03:00
* they have to return strings prepended with user ' s input . For
* instance :
*
* str1 , str2 , str3 , strA
* str1 , str2 , str3 , strB
* str1 , str2 , str3 , strC
*
* This helper function takes care of that . In this specific case
* it would be called as follows :
*
* virshCommaStringListComplete ( " str1,str2,str3 " ,
* { " strA " , " strB " , " strC " , NULL } ) ;
*
* Returns : string list of completions on success ,
* NULL otherwise .
*/
2019-07-18 18:18:28 +03:00
char * *
2019-06-18 13:16:17 +03:00
virshCommaStringListComplete ( const char * input ,
const char * * options )
{
2021-02-05 20:03:26 +03:00
const size_t optionsLen = g_strv_length ( ( char * * ) options ) ;
2019-10-15 16:16:31 +03:00
g_autofree char * inputCopy = NULL ;
2020-12-01 11:21:32 +03:00
g_auto ( GStrv ) inputList = NULL ;
g_auto ( GStrv ) ret = NULL ;
2019-06-18 13:16:17 +03:00
size_t nret = 0 ;
size_t i ;
if ( STREQ_NULLABLE ( input , " " ) )
input = NULL ;
if ( input ) {
char * comma = NULL ;
2019-10-20 14:49:46 +03:00
inputCopy = g_strdup ( input ) ;
2019-06-18 13:16:17 +03:00
if ( ( comma = strrchr ( inputCopy , ' , ' ) ) )
* comma = ' \0 ' ;
else
2020-09-14 17:05:52 +03:00
g_clear_pointer ( & inputCopy , g_free ) ;
2019-06-18 13:16:17 +03:00
}
2021-02-05 20:35:07 +03:00
if ( inputCopy & & ! ( inputList = g_strsplit ( inputCopy , " , " , 0 ) ) )
2019-06-18 13:16:17 +03:00
return NULL ;
2020-09-14 17:24:44 +03:00
ret = g_new0 ( char * , optionsLen + 1 ) ;
2019-06-18 13:16:17 +03:00
for ( i = 0 ; i < optionsLen ; i + + ) {
2021-02-03 20:39:47 +03:00
if ( inputList & &
g_strv_contains ( ( const char * * ) inputList , options [ i ] ) )
2019-06-18 13:16:17 +03:00
continue ;
2019-10-22 16:26:14 +03:00
if ( inputCopy )
ret [ nret ] = g_strdup_printf ( " %s,%s " , inputCopy , options [ i ] ) ;
else
2019-10-20 14:49:46 +03:00
ret [ nret ] = g_strdup ( options [ i ] ) ;
2019-06-18 13:16:17 +03:00
nret + + ;
}
2019-10-16 14:35:54 +03:00
return g_steal_pointer ( & ret ) ;
2019-06-18 13:16:17 +03:00
}
2021-09-15 18:08:37 +03:00
/**
* virshCompletePathLocalExisting :
*
* Complete a path to a existing file used as input . The file is used as input
* for virsh so only local files are considered .
*
* Note : For now this is a no - op . Readline does the correct thing .
*/
char * *
virshCompletePathLocalExisting ( vshControl * ctl G_GNUC_UNUSED ,
const vshCmd * cmd G_GNUC_UNUSED ,
unsigned int completerflags G_GNUC_UNUSED )
{
return NULL ;
}
2021-09-15 18:42:08 +03:00
/**
* virshCompleteEmpty :
*
* Complete nothing . For cases where an user input is required and we can ' t
* suggest anything .
*
* TODO : This is currently just an annotation , readline still completes local
* file list .
*/
char * *
virshCompleteEmpty ( vshControl * ctl G_GNUC_UNUSED ,
const vshCmd * cmd G_GNUC_UNUSED ,
unsigned int completerflags G_GNUC_UNUSED )
{
return NULL ;
}