diff options
author | Alexander Larsson <alexl@redhat.com> | 2015-06-18 11:57:12 +0200 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2015-06-22 17:29:19 +0200 |
commit | 6e26045943d27656b4444e157d0d10c025aa69db (patch) | |
tree | c95ff4fd1b4c4f4e3a24420a53cebc34678ad225 /common | |
parent | 60058fd5bdf289fe9210671447aaf027c8cd8a03 (diff) | |
download | gdm-6e26045943d27656b4444e157d0d10c025aa69db.tar.gz |
gdm-common: Add gdm_shell_expand() and tests
This allows shell-like expansion of strings. It will be later
used to allow configuring the environment via config files.
https://bugzilla.gnome.org/show_bug.cgi?id=751158
Diffstat (limited to 'common')
-rw-r--r-- | common/gdm-common.c | 87 | ||||
-rw-r--r-- | common/gdm-common.h | 9 |
2 files changed, 96 insertions, 0 deletions
diff --git a/common/gdm-common.c b/common/gdm-common.c index 5beeebf9..a96b30f2 100644 --- a/common/gdm-common.c +++ b/common/gdm-common.c @@ -710,3 +710,90 @@ gdm_run_script (const char *dir, return ret; } + +gboolean +gdm_shell_var_is_valid_char (gchar c, gboolean first) +{ + return (!first && g_ascii_isdigit (c)) || + c == '_' || + g_ascii_isalpha (c); +} + +/* This expands a string somewhat similar to how a shell would do it + if it was enclosed inside double quotes. It handles variable + expansion like $FOO and ${FOO}, single-char escapes using \, and + non-escaped # at the begining of a word is taken as a comment and ignored */ +char * +gdm_shell_expand (const char *str, + GdmExpandVarFunc expand_var_func, + gpointer user_data) +{ + GString *s = g_string_new(""); + const gchar *p, *start; + gchar c; + gboolean at_new_word; + + p = str; + at_new_word = TRUE; + while (*p) { + c = *p; + if (c == '\\') { + p++; + c = *p; + if (c != '\0') { + p++; + switch (c) { + case '\\': + g_string_append_c (s, '\\'); + break; + case '$': + g_string_append_c (s, '$'); + break; + case '#': + g_string_append_c (s, '#'); + break; + default: + g_string_append_c (s, '\\'); + g_string_append_c (s, c); + break; + } + } + } else if (c == '#' && at_new_word) { + break; + } else if (c == '$') { + gboolean brackets = FALSE; + p++; + if (*p == '{') { + brackets = TRUE; + p++; + } + start = p; + while (*p != '\0' && + gdm_shell_var_is_valid_char (*p, p == start)) + p++; + if (p == start || (brackets && *p != '}')) { + /* Invalid variable, use as-is */ + g_string_append_c (s, '$'); + if (brackets) + g_string_append_c (s, '{'); + g_string_append_len (s, start, p - start); + } else { + gchar *expanded; + gchar *var = g_strndup (start, p - start); + if (brackets && *p == '}') + p++; + + expanded = expand_var_func (var, user_data); + if (expanded) + g_string_append (s, expanded); + g_free (var); + g_free (expanded); + } + } else { + p++; + g_string_append_c (s, c); + at_new_word = g_ascii_isspace (c); + } + } + return g_string_free (s, FALSE); +} diff --git a/common/gdm-common.h b/common/gdm-common.h index 3302afec..d0812ed3 100644 --- a/common/gdm-common.h +++ b/common/gdm-common.h @@ -36,6 +36,9 @@ GQuark gdm_common_error_quark (void); #define GDM_COMMON_ERROR gdm_common_error_quark() +typedef char * (*GdmExpandVarFunc) (const char *var, + gpointer user_data); + G_BEGIN_DECLS int gdm_wait_on_pid (int pid); @@ -64,6 +67,12 @@ gboolean gdm_run_script (const char *dir, const char *display_hostname, const char *display_x11_authority_file); +gboolean gdm_shell_var_is_valid_char (char c, + gboolean first); +char * gdm_shell_expand (const char *str, + GdmExpandVarFunc expand_func, + gpointer user_data); + G_END_DECLS #endif /* _GDM_COMMON_H */ |