2
* $Id: eval.c,v 1.7 2005/06/29 14:24:26 daichik Exp $
4
* Copyright (c) 2003, Raphael Manfredi
6
*----------------------------------------------------------------------
7
* This file is part of gtk-gnutella.
9
* gtk-gnutella is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 2 of the License, or
12
* (at your option) any later version.
14
* gtk-gnutella is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with gtk-gnutella; if not, write to the Free Software
22
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
*----------------------------------------------------------------------
32
* @author Raphael Manfredi
38
RCSID("$Id: eval.c,v 1.7 2005/06/29 14:24:26 daichik Exp $");
44
#include "misc.h" /* For g_strlcpy() */
45
#include "override.h" /* Must be the last header included */
47
#define MAX_STRING 1024 /**< Max length for substitution */
49
static guint32 common_dbg = 0; /**< XXX -- need to init lib's props --RAM */
51
static GHashTable *constants;
54
static gchar *get_home(void);
55
static gchar *get_variable(gchar *s, gchar **end);
58
* Create a constant string, or reuse an existing one if possible.
60
* @returns a string atom.
63
constant_make(gchar *s)
67
v = (gchar *) g_hash_table_lookup(constants, s);
69
return v; /* Already exists */
72
g_hash_table_insert(constants, v, v);
78
* Initialize string evaluation.
83
constants = g_hash_table_new(g_str_hash, g_str_equal);
88
constants_free_kv(gpointer key,
89
gpointer unused_val, gpointer unused_x)
97
* Cleanup local structures at shutdown time.
104
g_hash_table_foreach(constants, constants_free_kv, NULL);
105
g_hash_table_destroy(constants);
109
* Insert value `val' at beginning of string `start'.
111
* The string `start' is held in a buffer capable of holding a string of
112
* `maxlen' bytes, and the string is currently `len' bytes long, with `start'
113
* being at the offset `off' within buffer.
115
* @return the pointer right after the inserted value.
118
insert_value(gchar *val, gchar *start, gint off,
119
gint len, gint maxlen)
121
gint vlen = strlen(val);
123
g_assert(len <= maxlen);
124
g_assert(off >= 0 && off <= len);
126
if (len + vlen > maxlen) {
127
g_warning("ignoring variable substitution text \"%s\"", val);
131
memmove(start + vlen, start, len + 1 - off);
132
memmove(start, val, vlen);
138
* Needs brief description here.
140
* Substitutes variables from string:
142
* - The leading "~" is replaced by the home directory.
143
* - Variables like "$PATH" or "${PATH}" are replaced by their value, as
144
* fetched from the environment, or the empty string if not found.
146
* If given a NULL input, we return NULL.
148
* @return string atom, which is not meant to be freed until exit time.
151
eval_subst(const gchar *str)
153
gchar buf[MAX_STRING];
155
gchar *end = buf + sizeof(buf);
162
len = g_strlcpy(buf, str, sizeof(buf));
163
if (len >= sizeof(buf)) {
164
g_warning("eval_subst: string too large for substitution (%d bytes)",
166
return constant_make((gchar *) str);
171
printf("eval_subst: on entry: \"%s\"\n", buf);
173
for (p = buf, c = *p++; c; c = *p++) {
175
gchar *start = p - 1;
177
if (c == '~' && start == buf) { /* Leading ~ only */
179
memmove(start, start + 1, len - (start - buf));
182
g_assert((ssize_t) len >= 0);
184
} else if (c == '$') {
187
val = get_variable(p, &after);
188
memmove(start, after, len + 1 - (after - buf));
189
len -= after - start; /* Also removing leading '$' */
191
g_assert((ssize_t) len >= 0);
196
gchar *next = insert_value(
197
val, start, start - buf, len, sizeof(buf) - 1);
202
g_assert(len < sizeof(buf));
206
g_assert(p <= (buf + len));
210
printf("eval_subst: on exit: \"%s\"\n", buf);
212
g_assert(len == strlen(buf));
214
return constant_make(buf);
218
* Compute the user's home directory.
219
* Uses the HOME environment variable first, then the entry from /etc/passwd.
221
* @return string atom.
231
return atom_str_get(v);
233
pp = getpwuid(getuid());
235
return atom_str_get(pp->pw_dir);
237
g_warning("Could not determine home directory");
238
return atom_str_get("/");
242
* Extract variable name from string `s', then fetch value from environment.
244
* @return variable's value, or "" if not found and set `end' to the address
245
* of the character right after the variable name.
247
static gchar *get_variable(gchar *s, gchar **end)
249
guchar *p = (guchar *) s;
253
gboolean end_brace = FALSE;
256
* Grab variable's name.
266
if (!isalnum(c) && c != '_')
271
if (end_brace && *p == '}')
272
*end = (gchar *) (p + 1);
277
* Get value from environment.
282
value = getenv(name);
288
printf("variable \"%s\" is \"%s\"\n", name, value);
295
/* vi: set ts=4 sw=4 cindent: */