#ifndef _ASCII_H
#define _ASCII_H
+#define VB_UPPER 0x01
+#define VB_LOWER 0x02
+#define VB_DIGIT 0x04
+#define VB_SPACE 0x08
+#define VB_PUNKT 0x10
+#define VB_CTRL 0x20
+#define VB_IDENT 0x40
+#define VB_ALPHA (VB_UPPER|VB_LOWER)
+#define VB_ALNUM (VB_ALPHA|VB_DIGIT)
+
+#define U VB_UPPER
+#define L VB_LOWER
+#define D VB_DIGIT
+#define P VB_PUNKT
+#define S VB_SPACE
+#define C VB_CTRL
+#define I VB_IDENT
+#define LI VB_LOWER|VB_IDENT
+#define UI VB_UPPER|VB_IDENT
+#define SC VB_SPACE|VB_CTRL
+#define PI VB_PUNKT|VB_IDENT
+static const unsigned char chartable[256] = {
+ C, C, C, C, C, C, C, C, C, SC, SC, C, SC, SC, C, C,
+ C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
+ S, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P,
+ D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, P,
+ PI, UI, UI, UI, UI, UI, UI, UI, UI, UI, UI, UI, UI, UI, UI, UI,
+ UI, UI, UI, UI, UI, UI, UI, UI, UI, UI, UI, P, P, P, P, PI,
+ P, LI, LI, LI, LI, LI, LI, LI, LI, LI, LI, LI, LI, LI, LI, LI,
+ LI, LI, LI, LI, LI, LI, LI, LI, LI, LI, LI, P, P, P, P, C,
+ P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P,
+ P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P,
+ P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P,
+ P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P,
+ P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P,
+ P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P,
+ P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P,
+ P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P
+};
+#undef U
+#undef L
+#undef D
+#undef P
+#undef S
+#undef C
+#undef I
+#undef LI
+#undef UI
+#undef SC
+
+#define VB_IS_UPPER(c) ((chartable[(unsigned char)c] & VB_UPPER) != 0)
+#define VB_IS_LOWER(c) ((chartable[(unsigned char)c] & VB_LOWER) != 0)
+#define VB_IS_DIGIT(c) ((chartable[(unsigned char)c] & VB_DIGIT) != 0)
+#define VB_IS_PUNKT(c) ((chartable[(unsigned char)c] & VB_PUNKT) != 0)
+#define VB_IS_SPACE(c) ((chartable[(unsigned char)c] & VB_SPACE) != 0)
+#define VB_IS_CTRL(c) ((chartable[(unsigned char)c] & VB_CTRL) != 0)
+#define VB_IS_IDENT(c) ((chartable[(unsigned char)c] & VB_IDENT) != 0)
+#define VB_IS_ALPHA(c) ((chartable[(unsigned char)c] & VB_ALPHA) != 0)
+#define VB_IS_ALNUM(c) ((chartable[(unsigned char)c] & VB_ALNUM) != 0)
+
/* CSI (control sequence introducer) is the first byte of a control sequence
* and is always followed by two bytes. */
#define CSI 0x80
#include "config.h"
#include <stdio.h>
+#include <pwd.h>
#include "ctype.h"
#include "util.h"
+#include "ascii.h"
char *util_get_config_dir(void)
{
char *fullPath = NULL, *fexp, *dexp, *p;
/* if the path could be expanded */
- if ((fexp = util_shell_expand(path))) {
- if (*fexp == '/') {
+ if ((fexp = util_expand(path))) {
+ if (*fexp == G_DIR_SEPARATOR) {
/* path is already absolute, no need to use given dir - there is
* no need to free fexp, bacuse this should be done by the caller
* on fullPath later */
fullPath = fexp;
} else if (dir) {
/* try to expand also the dir given - this may be ~/path */
- if ((dexp = util_shell_expand(dir))) {
+ if ((dexp = util_expand(dir))) {
/* use expanded dir and append expanded path */
fullPath = g_build_filename(dexp, fexp, NULL);
g_free(dexp);
}
/**
- * Run the shell to expand given string 'echo -n str'.
+ * Expand ~user, ~/, $ENV and ${ENV} for given string into new allocated
+ * string.
*
* Returned path must be g_freed.
*/
-char *util_shell_expand(const char *str)
+char *util_expand(const char *src)
{
- GError *error = NULL;
- char *shellcmd, *cmd, *out = NULL;
-
- /* first check if the string may contain expandable chars */
- if (*str == '~' || strchr(str, '$')) {
- cmd = g_strconcat("echo -n ", str, NULL);
- shellcmd = g_strdup_printf(SHELL_CMD, cmd);
- if (!g_spawn_command_line_sync(shellcmd, &out, NULL, NULL, &error)) {
- g_warning("Could not run shell expansion: %s", error->message);
- g_clear_error(&error);
+ GString *dst = g_string_new("");
+ GString *name;
+ gboolean start = true; /* is start of string of subpart */
+ const char *env;
+ char *result;
+ struct passwd *pwd;
+
+ while (*src) {
+ /* expand ~/path and ~user */
+ if (*src == '~' && start) {
+ /* skip the ~ */
+ src++;
+ if (*src == G_DIR_SEPARATOR) {
+ g_string_append(dst, util_get_home_dir());
+ } else {
+ name = g_string_new("");
+ /* look ahead to / space or end of string */
+ while (*src && *src != G_DIR_SEPARATOR && !VB_IS_SPACE(*src)) {
+ g_string_append_c(name, *src);
+ src++;
+ }
+ /* append the name to the destination string */
+ if ((pwd = getpwnam(name->str))) {
+ g_string_append(dst, pwd->pw_dir);
+ }
+ g_string_free(name, true);
+ }
+ } else if (*src == '$') {
+ name = g_string_new("");
+ /* skip the $ */
+ src++;
+ /* look for ${VAR}*/
+ if (*src == '{') {
+ /* skip { */
+ src++;
+ /* look ahead to } or end of string */
+ while (*src && *src != '}') {
+ g_string_append_c(name, *src);
+ src++;
+ }
+ /* if the } was reached - skip this */
+ if (*src == '}') {
+ src++;
+ }
+ } else { /* process $VAR */
+ /* look ahead to /, space or end of string */
+ while (*src && VB_IS_IDENT(*src)) {
+ g_string_append_c(name, *src);
+ src++;
+ }
+ }
+ /* append the variable to the destination string */
+ if ((env = g_getenv(name->str))) {
+ g_string_append(dst, env);
+ }
+ g_string_free(name, true);
+ } else if (!VB_IS_ALNUM(*src)) {
+ /* if we match non alnum char - mark this as beginning of new part */
+ start = true;
+ } else {
+ /* we left the start of phrase behind */
+ start = false;
}
- g_free(shellcmd);
- g_free(cmd);
- }
- /* if string needn't to be expanded or expansion fialed use it like it is */
- if (!out) {
- out = g_strdup(str);
+ g_string_append_c(dst, *src);
+ src++;
}
- return out;
+ result = dst->str;
+ g_string_free(dst, false);
+
+ return result;
}