mirror of
https://github.com/davatorium/rofi.git
synced 2024-11-25 13:55:34 -05:00
[SSH] Add support for parsing port number from known hosts file.
* Store port number in history. * Parse the [host]:port format. * Update default ssh command to (optionally) add -p {port}. Fixes: #580
This commit is contained in:
parent
9af5cac65b
commit
f879062417
3 changed files with 98 additions and 77 deletions
|
@ -58,7 +58,7 @@ Settings config = {
|
||||||
.terminal_emulator = "rofi-sensible-terminal",
|
.terminal_emulator = "rofi-sensible-terminal",
|
||||||
.ssh_client = "ssh",
|
.ssh_client = "ssh",
|
||||||
/** Command when executing ssh. */
|
/** Command when executing ssh. */
|
||||||
.ssh_command = "{terminal} -e {ssh-client} {host}",
|
.ssh_command = "{terminal} -e {ssh-client} {host} [-p {port}]",
|
||||||
/** Command when running */
|
/** Command when running */
|
||||||
.run_command = "{cmd}",
|
.run_command = "{cmd}",
|
||||||
/** Command used to list executable commands. empty -> internal */
|
/** Command used to list executable commands. empty -> internal */
|
||||||
|
|
|
@ -67,6 +67,12 @@
|
||||||
*/
|
*/
|
||||||
#define SSH_TOKEN_DELIM "= \t\r\n"
|
#define SSH_TOKEN_DELIM "= \t\r\n"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _SshEntry {
|
||||||
|
char *hostname;
|
||||||
|
int port;
|
||||||
|
} SshEntry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param host The host to connect too
|
* @param host The host to connect too
|
||||||
*
|
*
|
||||||
|
@ -74,24 +80,31 @@
|
||||||
*
|
*
|
||||||
* @returns FALSE On failure, TRUE on success
|
* @returns FALSE On failure, TRUE on success
|
||||||
*/
|
*/
|
||||||
static int execshssh ( const char *host )
|
static int execshssh ( const SshEntry *entry)
|
||||||
{
|
{
|
||||||
char **args = NULL;
|
char **args = NULL;
|
||||||
int argsv = 0;
|
int argsv = 0;
|
||||||
|
gchar *portstr = NULL;
|
||||||
|
if ( entry->port > 0 ) {
|
||||||
|
portstr = g_strdup_printf("%d", entry->port);
|
||||||
|
}
|
||||||
|
helper_parse_setup ( config.ssh_command, &args, &argsv,
|
||||||
|
"{host}", entry->hostname,
|
||||||
|
"{port}", portstr,
|
||||||
|
(char *) 0 );
|
||||||
|
g_free ( portstr );
|
||||||
|
|
||||||
helper_parse_setup ( config.ssh_command, &args, &argsv, "{host}", host, (char *) 0 );
|
gsize l = strlen ( "Connecting to '' via rofi" ) + strlen ( entry->hostname ) + 1;
|
||||||
|
|
||||||
gsize l = strlen ( "Connecting to '' via rofi" ) + strlen ( host ) + 1;
|
|
||||||
gchar *desc = g_newa ( gchar, l );
|
gchar *desc = g_newa ( gchar, l );
|
||||||
|
|
||||||
g_snprintf ( desc, l, "Connecting to '%s' via rofi", host );
|
g_snprintf ( desc, l, "Connecting to '%s' via rofi", entry->hostname );
|
||||||
|
|
||||||
RofiHelperExecuteContext context = {
|
RofiHelperExecuteContext context = {
|
||||||
.name = "ssh",
|
.name = "ssh",
|
||||||
.description = desc,
|
.description = desc,
|
||||||
.command = "ssh",
|
.command = "ssh",
|
||||||
};
|
};
|
||||||
return helper_execute ( NULL, args, "ssh ", host, &context );
|
return helper_execute ( NULL, args, "ssh ", entry->hostname, &context );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,20 +112,27 @@ static int execshssh ( const char *host )
|
||||||
*
|
*
|
||||||
* SSH into the selected host, if successful update history.
|
* SSH into the selected host, if successful update history.
|
||||||
*/
|
*/
|
||||||
static void exec_ssh ( const char *host )
|
static void exec_ssh ( const SshEntry *entry )
|
||||||
{
|
{
|
||||||
if ( !host || !host[0] ) {
|
if ( !(entry->hostname )|| !(entry->hostname[0]) ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !execshssh ( host ) ) {
|
if ( !execshssh ( entry ) ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This happens in non-critical time (After launching app)
|
// This happens in non-critical time (After launching app)
|
||||||
// It is allowed to be a bit slower.
|
// It is allowed to be a bit slower.
|
||||||
char *path = g_build_filename ( cache_dir, SSH_CACHE_FILE, NULL );
|
char *path = g_build_filename ( cache_dir, SSH_CACHE_FILE, NULL );
|
||||||
history_set ( path, host );
|
// TODO update.
|
||||||
|
if ( entry->port > 0 ) {
|
||||||
|
char *store = g_strdup_printf("%s:%d", entry->hostname, entry->port );
|
||||||
|
history_set ( path, store );
|
||||||
|
g_free ( store );
|
||||||
|
} else {
|
||||||
|
history_set ( path, entry->hostname );
|
||||||
|
}
|
||||||
g_free ( path );
|
g_free ( path );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +159,7 @@ static void delete_ssh ( const char *host )
|
||||||
*
|
*
|
||||||
* @returns updated list of hosts.
|
* @returns updated list of hosts.
|
||||||
*/
|
*/
|
||||||
static char **read_known_hosts_file ( char ** retv, unsigned int *length )
|
static SshEntry *read_known_hosts_file ( SshEntry * retv, unsigned int *length )
|
||||||
{
|
{
|
||||||
char *path = g_build_filename ( g_get_home_dir (), ".ssh", "known_hosts", NULL );
|
char *path = g_build_filename ( g_get_home_dir (), ".ssh", "known_hosts", NULL );
|
||||||
FILE *fd = fopen ( path, "r" );
|
FILE *fd = fopen ( path, "r" );
|
||||||
|
@ -160,10 +180,6 @@ static char **read_known_hosts_file ( char ** retv, unsigned int *length )
|
||||||
// Skip hashed hostnames.
|
// Skip hashed hostnames.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ( *start == '[' ) {
|
|
||||||
// Don't support port versions yet, TODO
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Find end of hostname set.
|
// Find end of hostname set.
|
||||||
char *end = strstr ( start, " " );
|
char *end = strstr ( start, " " );
|
||||||
if ( end == NULL ) {
|
if ( end == NULL ) {
|
||||||
|
@ -175,11 +191,20 @@ static char **read_known_hosts_file ( char ** retv, unsigned int *length )
|
||||||
start = strsep(&sep,", " );
|
start = strsep(&sep,", " );
|
||||||
while ( start )
|
while ( start )
|
||||||
{
|
{
|
||||||
|
int port = 0;
|
||||||
|
if ( start[0] == '[' ) {
|
||||||
|
start++;
|
||||||
|
char *end = strchr ( start, ']');
|
||||||
|
if ( end[1] == ':' ){
|
||||||
|
*end = '\0';
|
||||||
|
port = atoi ( &(end[2]) );
|
||||||
|
}
|
||||||
|
}
|
||||||
// Is this host name already in the list?
|
// Is this host name already in the list?
|
||||||
// We often get duplicates in hosts file, so lets check this.
|
// We often get duplicates in hosts file, so lets check this.
|
||||||
int found = 0;
|
int found = 0;
|
||||||
for ( unsigned int j = 0; j < ( *length ); j++ ) {
|
for ( unsigned int j = 0; j < ( *length ); j++ ) {
|
||||||
if ( !g_ascii_strcasecmp ( start, retv[j] ) ) {
|
if ( !g_ascii_strcasecmp ( start, retv[j].hostname ) ) {
|
||||||
found = 1;
|
found = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -187,9 +212,11 @@ static char **read_known_hosts_file ( char ** retv, unsigned int *length )
|
||||||
|
|
||||||
if ( !found ) {
|
if ( !found ) {
|
||||||
// Add this host name to the list.
|
// Add this host name to the list.
|
||||||
retv = g_realloc ( retv, ( ( *length ) + 2 ) * sizeof ( char* ) );
|
retv = g_realloc ( retv, ( ( *length ) + 2 ) * sizeof ( SshEntry ) );
|
||||||
retv[( *length )] = g_strdup ( start );
|
retv[( *length )].hostname = g_strdup ( start );
|
||||||
retv[( *length ) + 1] = NULL;
|
retv[( *length )].port = port;
|
||||||
|
retv[( *length ) + 1].hostname = NULL;
|
||||||
|
retv[( *length ) + 1].port = 0;
|
||||||
( *length )++;
|
( *length )++;
|
||||||
}
|
}
|
||||||
start = strsep(&sep,", " );
|
start = strsep(&sep,", " );
|
||||||
|
@ -215,7 +242,7 @@ static char **read_known_hosts_file ( char ** retv, unsigned int *length )
|
||||||
*
|
*
|
||||||
* @returns an updated list with the added hosts.
|
* @returns an updated list with the added hosts.
|
||||||
*/
|
*/
|
||||||
static char **read_hosts_file ( char ** retv, unsigned int *length )
|
static SshEntry *read_hosts_file ( SshEntry * retv, unsigned int *length )
|
||||||
{
|
{
|
||||||
// Read the hosts file.
|
// Read the hosts file.
|
||||||
FILE *fd = fopen ( "/etc/hosts", "r" );
|
FILE *fd = fopen ( "/etc/hosts", "r" );
|
||||||
|
@ -243,7 +270,7 @@ static char **read_hosts_file ( char ** retv, unsigned int *length )
|
||||||
// We often get duplicates in hosts file, so lets check this.
|
// We often get duplicates in hosts file, so lets check this.
|
||||||
int found = 0;
|
int found = 0;
|
||||||
for ( unsigned int j = 0; j < ( *length ); j++ ) {
|
for ( unsigned int j = 0; j < ( *length ); j++ ) {
|
||||||
if ( !g_ascii_strcasecmp ( token, retv[j] ) ) {
|
if ( !g_ascii_strcasecmp ( token, retv[j].hostname ) ) {
|
||||||
found = 1;
|
found = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -253,8 +280,8 @@ static char **read_hosts_file ( char ** retv, unsigned int *length )
|
||||||
// Add this host name to the list.
|
// Add this host name to the list.
|
||||||
retv = g_realloc ( retv,
|
retv = g_realloc ( retv,
|
||||||
( ( *length ) + 2 ) * sizeof ( char* ) );
|
( ( *length ) + 2 ) * sizeof ( char* ) );
|
||||||
retv[( *length )] = g_strdup ( token );
|
retv[( *length )].hostname = g_strdup ( token );
|
||||||
retv[( *length ) + 1] = NULL;
|
retv[( *length ) + 1].hostname = NULL;
|
||||||
( *length )++;
|
( *length )++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -281,7 +308,7 @@ static char **read_hosts_file ( char ** retv, unsigned int *length )
|
||||||
return retv;
|
return retv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_ssh_config_file ( const char *filename, char ***retv, unsigned int *length, unsigned int num_favorites )
|
static void parse_ssh_config_file ( const char *filename, SshEntry **retv, unsigned int *length, unsigned int num_favorites )
|
||||||
{
|
{
|
||||||
FILE *fd = fopen ( filename, "r" );
|
FILE *fd = fopen ( filename, "r" );
|
||||||
|
|
||||||
|
@ -352,7 +379,7 @@ static void parse_ssh_config_file ( const char *filename, char ***retv, unsigned
|
||||||
// given num_favorites is max 25.
|
// given num_favorites is max 25.
|
||||||
int found = 0;
|
int found = 0;
|
||||||
for ( unsigned int j = 0; j < num_favorites; j++ ) {
|
for ( unsigned int j = 0; j < num_favorites; j++ ) {
|
||||||
if ( !g_ascii_strcasecmp ( token, ( *retv )[j] ) ) {
|
if ( !g_ascii_strcasecmp ( token, ( *retv )[j].hostname ) ) {
|
||||||
found = 1;
|
found = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -363,9 +390,9 @@ static void parse_ssh_config_file ( const char *filename, char ***retv, unsigned
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add this host name to the list.
|
// Add this host name to the list.
|
||||||
( *retv ) = g_realloc ( ( *retv ), ( ( *length ) + 2 ) * sizeof ( char* ) );
|
( *retv ) = g_realloc ( ( *retv ), ( ( *length ) + 2 ) * sizeof ( SshEntry ) );
|
||||||
( *retv )[( *length )] = g_strdup ( token );
|
( *retv )[( *length )].hostname = g_strdup ( token );
|
||||||
( *retv )[( *length ) + 1] = NULL;
|
( *retv )[( *length ) + 1].hostname = NULL;
|
||||||
( *length )++;
|
( *length )++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -387,9 +414,9 @@ static void parse_ssh_config_file ( const char *filename, char ***retv, unsigned
|
||||||
*
|
*
|
||||||
* @return an array of strings containing all the hosts.
|
* @return an array of strings containing all the hosts.
|
||||||
*/
|
*/
|
||||||
static char ** get_ssh ( unsigned int *length )
|
static SshEntry * get_ssh ( unsigned int *length )
|
||||||
{
|
{
|
||||||
char **retv = NULL;
|
SshEntry *retv = NULL;
|
||||||
unsigned int num_favorites = 0;
|
unsigned int num_favorites = 0;
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
|
@ -398,7 +425,21 @@ static char ** get_ssh ( unsigned int *length )
|
||||||
}
|
}
|
||||||
|
|
||||||
path = g_build_filename ( cache_dir, SSH_CACHE_FILE, NULL );
|
path = g_build_filename ( cache_dir, SSH_CACHE_FILE, NULL );
|
||||||
retv = history_get_list ( path, length );
|
char **h = history_get_list ( path, length );
|
||||||
|
|
||||||
|
retv = malloc ( (*length)*sizeof(SshEntry));
|
||||||
|
for ( unsigned int i = 0; i < (*length); i++ ){
|
||||||
|
int port = 0;
|
||||||
|
char *portstr = strchr ( h[i], ':' );
|
||||||
|
if ( portstr != NULL ) {
|
||||||
|
*portstr = '\0';
|
||||||
|
port = atoi ( &(portstr[1]) );
|
||||||
|
}
|
||||||
|
retv[i].hostname = h[i];
|
||||||
|
retv[i].port = port;
|
||||||
|
}
|
||||||
|
g_free (h);
|
||||||
|
|
||||||
g_free ( path );
|
g_free ( path );
|
||||||
num_favorites = ( *length );
|
num_favorites = ( *length );
|
||||||
|
|
||||||
|
@ -424,7 +465,7 @@ static char ** get_ssh ( unsigned int *length )
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
/** List if available ssh hosts.*/
|
/** List if available ssh hosts.*/
|
||||||
char **hosts_list;
|
SshEntry *hosts_list;
|
||||||
/** Length of the #hosts_list.*/
|
/** Length of the #hosts_list.*/
|
||||||
unsigned int hosts_list_length;
|
unsigned int hosts_list_length;
|
||||||
} SSHModePrivateData;
|
} SSHModePrivateData;
|
||||||
|
@ -466,7 +507,10 @@ static void ssh_mode_destroy ( Mode *sw )
|
||||||
{
|
{
|
||||||
SSHModePrivateData *rmpd = (SSHModePrivateData *) mode_get_private_data ( sw );
|
SSHModePrivateData *rmpd = (SSHModePrivateData *) mode_get_private_data ( sw );
|
||||||
if ( rmpd != NULL ) {
|
if ( rmpd != NULL ) {
|
||||||
g_strfreev ( rmpd->hosts_list );
|
for ( unsigned int i = 0; i < rmpd->hosts_list_length; i++ ){
|
||||||
|
g_free( rmpd->hosts_list[i].hostname );
|
||||||
|
}
|
||||||
|
g_free ( rmpd->hosts_list );
|
||||||
g_free ( rmpd );
|
g_free ( rmpd );
|
||||||
mode_set_private_data ( sw, NULL );
|
mode_set_private_data ( sw, NULL );
|
||||||
}
|
}
|
||||||
|
@ -495,14 +539,15 @@ static ModeMode ssh_mode_result ( Mode *sw, int mretv, char **input, unsigned in
|
||||||
else if ( mretv & MENU_QUICK_SWITCH ) {
|
else if ( mretv & MENU_QUICK_SWITCH ) {
|
||||||
retv = ( mretv & MENU_LOWER_MASK );
|
retv = ( mretv & MENU_LOWER_MASK );
|
||||||
}
|
}
|
||||||
else if ( ( mretv & MENU_OK ) && rmpd->hosts_list[selected_line] != NULL ) {
|
else if ( ( mretv & MENU_OK ) && rmpd->hosts_list[selected_line].hostname != NULL ) {
|
||||||
exec_ssh ( rmpd->hosts_list[selected_line] );
|
exec_ssh ( &(rmpd->hosts_list[selected_line]) );
|
||||||
}
|
}
|
||||||
else if ( ( mretv & MENU_CUSTOM_INPUT ) && *input != NULL && *input[0] != '\0' ) {
|
else if ( ( mretv & MENU_CUSTOM_INPUT ) && *input != NULL && *input[0] != '\0' ) {
|
||||||
exec_ssh ( *input );
|
SshEntry entry = { .hostname = *input, .port = 0 };
|
||||||
|
exec_ssh ( &entry );
|
||||||
}
|
}
|
||||||
else if ( ( mretv & MENU_ENTRY_DELETE ) && rmpd->hosts_list[selected_line] ) {
|
else if ( ( mretv & MENU_ENTRY_DELETE ) && rmpd->hosts_list[selected_line].hostname ) {
|
||||||
delete_ssh ( rmpd->hosts_list[selected_line] );
|
delete_ssh ( rmpd->hosts_list[selected_line].hostname );
|
||||||
// Stay
|
// Stay
|
||||||
retv = RELOAD_DIALOG;
|
retv = RELOAD_DIALOG;
|
||||||
ssh_mode_destroy ( sw );
|
ssh_mode_destroy ( sw );
|
||||||
|
@ -526,7 +571,7 @@ static ModeMode ssh_mode_result ( Mode *sw, int mretv, char **input, unsigned in
|
||||||
static char *_get_display_value ( const Mode *sw, unsigned int selected_line, G_GNUC_UNUSED int *state, G_GNUC_UNUSED GList **attr_list, int get_entry )
|
static char *_get_display_value ( const Mode *sw, unsigned int selected_line, G_GNUC_UNUSED int *state, G_GNUC_UNUSED GList **attr_list, int get_entry )
|
||||||
{
|
{
|
||||||
SSHModePrivateData *rmpd = (SSHModePrivateData *) mode_get_private_data ( sw );
|
SSHModePrivateData *rmpd = (SSHModePrivateData *) mode_get_private_data ( sw );
|
||||||
return get_entry ? g_strdup ( rmpd->hosts_list[selected_line] ) : NULL;
|
return get_entry ? g_strdup ( rmpd->hosts_list[selected_line].hostname ) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -541,7 +586,7 @@ static char *_get_display_value ( const Mode *sw, unsigned int selected_line, G_
|
||||||
static int ssh_token_match ( const Mode *sw, rofi_int_matcher **tokens, unsigned int index )
|
static int ssh_token_match ( const Mode *sw, rofi_int_matcher **tokens, unsigned int index )
|
||||||
{
|
{
|
||||||
SSHModePrivateData *rmpd = (SSHModePrivateData *) mode_get_private_data ( sw );
|
SSHModePrivateData *rmpd = (SSHModePrivateData *) mode_get_private_data ( sw );
|
||||||
return helper_token_match ( tokens, rmpd->hosts_list[index] );
|
return helper_token_match ( tokens, rmpd->hosts_list[index].hostname );
|
||||||
}
|
}
|
||||||
#include "mode-private.h"
|
#include "mode-private.h"
|
||||||
Mode ssh_mode =
|
Mode ssh_mode =
|
||||||
|
|
|
@ -71,39 +71,14 @@ static int stored_argc = 0;
|
||||||
/** copy of the argv pointer for use in the commandline argument parser */
|
/** copy of the argv pointer for use in the commandline argument parser */
|
||||||
static char **stored_argv = NULL;
|
static char **stored_argv = NULL;
|
||||||
|
|
||||||
|
char *helper_string_replace_if_exists_v ( char * string, GHashTable *h );
|
||||||
|
|
||||||
void cmd_set_arguments ( int argc, char **argv )
|
void cmd_set_arguments ( int argc, char **argv )
|
||||||
{
|
{
|
||||||
stored_argc = argc;
|
stored_argc = argc;
|
||||||
stored_argv = argv;
|
stored_argv = argv;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param info To Match information on.
|
|
||||||
* @param res The string being generated.
|
|
||||||
* @param data User data
|
|
||||||
*
|
|
||||||
* Replace the entries. This function gets called by g_regex_replace_eval.
|
|
||||||
*
|
|
||||||
* @returns TRUE to stop replacement, FALSE to continue
|
|
||||||
*/
|
|
||||||
static gboolean helper_eval_cb ( const GMatchInfo *info, GString *res, gpointer data )
|
|
||||||
{
|
|
||||||
gchar *match;
|
|
||||||
// Get the match
|
|
||||||
match = g_match_info_fetch ( info, 0 );
|
|
||||||
if ( match != NULL ) {
|
|
||||||
// Lookup the match, so we can replace it.
|
|
||||||
gchar *r = g_hash_table_lookup ( (GHashTable *) data, match );
|
|
||||||
if ( r != NULL ) {
|
|
||||||
// Append the replacement to the string.
|
|
||||||
g_string_append ( res, r );
|
|
||||||
}
|
|
||||||
// Free match.
|
|
||||||
g_free ( match );
|
|
||||||
}
|
|
||||||
// Continue replacement.
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int helper_parse_setup ( char * string, char ***output, int *length, ... )
|
int helper_parse_setup ( char * string, char ***output, int *length, ... )
|
||||||
{
|
{
|
||||||
|
@ -129,11 +104,7 @@ int helper_parse_setup ( char * string, char ***output, int *length, ... )
|
||||||
}
|
}
|
||||||
va_end ( ap );
|
va_end ( ap );
|
||||||
|
|
||||||
// Replace hits within {-\w+}.
|
char *res = helper_string_replace_if_exists_v ( string, h );
|
||||||
GRegex *reg = g_regex_new ( "{[-\\w]+}", 0, 0, NULL );
|
|
||||||
char *res = g_regex_replace_eval ( reg, string, -1, 0, 0, helper_eval_cb, h, NULL );
|
|
||||||
// Free regex.
|
|
||||||
g_regex_unref ( reg );
|
|
||||||
// Destroy key-value storage.
|
// Destroy key-value storage.
|
||||||
g_hash_table_destroy ( h );
|
g_hash_table_destroy ( h );
|
||||||
// Parse the string into shell arguments.
|
// Parse the string into shell arguments.
|
||||||
|
@ -1283,12 +1254,11 @@ static gboolean helper_eval_cb2 ( const GMatchInfo *info, GString *res, gpointer
|
||||||
|
|
||||||
char *helper_string_replace_if_exists ( char * string, ... )
|
char *helper_string_replace_if_exists ( char * string, ... )
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
|
||||||
GHashTable *h;
|
GHashTable *h;
|
||||||
h = g_hash_table_new ( g_str_hash, g_str_equal );
|
h = g_hash_table_new ( g_str_hash, g_str_equal );
|
||||||
// Add list from variable arguments.
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start ( ap, string );
|
va_start ( ap, string );
|
||||||
|
// Add list from variable arguments.
|
||||||
while ( 1 ) {
|
while ( 1 ) {
|
||||||
char * key = va_arg ( ap, char * );
|
char * key = va_arg ( ap, char * );
|
||||||
if ( key == (char *) 0 ) {
|
if ( key == (char *) 0 ) {
|
||||||
|
@ -1297,15 +1267,21 @@ char *helper_string_replace_if_exists ( char * string, ... )
|
||||||
char *value = va_arg ( ap, char * );
|
char *value = va_arg ( ap, char * );
|
||||||
g_hash_table_insert ( h, key, value );
|
g_hash_table_insert ( h, key, value );
|
||||||
}
|
}
|
||||||
|
char *retv = helper_string_replace_if_exists_v ( string, h );
|
||||||
va_end ( ap );
|
va_end ( ap );
|
||||||
|
// Destroy key-value storage.
|
||||||
|
g_hash_table_destroy ( h );
|
||||||
|
return retv;
|
||||||
|
}
|
||||||
|
char *helper_string_replace_if_exists_v ( char * string, GHashTable *h )
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
// Replace hits within {-\w+}.
|
// Replace hits within {-\w+}.
|
||||||
GRegex *reg = g_regex_new ( "\\[(.*)({[-\\w]+})(.*)\\]|({[\\w-]+})", 0, 0, NULL );
|
GRegex *reg = g_regex_new ( "\\[(.*)({[-\\w]+})(.*)\\]|({[\\w-]+})", 0, 0, NULL );
|
||||||
char *res = g_regex_replace_eval ( reg, string, -1, 0, 0, helper_eval_cb2, h, NULL );
|
char *res = g_regex_replace_eval ( reg, string, -1, 0, 0, helper_eval_cb2, h, NULL );
|
||||||
// Free regex.
|
// Free regex.
|
||||||
g_regex_unref ( reg );
|
g_regex_unref ( reg );
|
||||||
// Destroy key-value storage.
|
|
||||||
g_hash_table_destroy ( h );
|
|
||||||
// Throw error if shell parsing fails.
|
// Throw error if shell parsing fails.
|
||||||
if ( error ) {
|
if ( error ) {
|
||||||
char *msg = g_strdup_printf ( "Failed to parse: '%s'\nError: '%s'", string, error->message );
|
char *msg = g_strdup_printf ( "Failed to parse: '%s'\nError: '%s'", string, error->message );
|
||||||
|
|
Loading…
Reference in a new issue