~ubuntu-branches/ubuntu/karmic/gtk-gnutella/karmic

« back to all changes in this revision

Viewing changes to src/lib/eval.c

  • Committer: Bazaar Package Importer
  • Author(s): Anand Kumria
  • Date: 2005-08-04 11:32:05 UTC
  • mfrom: (1.2.1 upstream) (2.1.1 sarge)
  • Revision ID: james.westby@ubuntu.com-20050804113205-q746i4lgo3rtlegn
Tags: 0.95.4-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: eval.c,v 1.7 2005/06/29 14:24:26 daichik Exp $
 
3
 *
 
4
 * Copyright (c) 2003, Raphael Manfredi
 
5
 *
 
6
 *----------------------------------------------------------------------
 
7
 * This file is part of gtk-gnutella.
 
8
 *
 
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.
 
13
 *
 
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.
 
18
 *
 
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
 
21
 *  Foundation, Inc.:
 
22
 *      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
23
 *----------------------------------------------------------------------
 
24
 */
 
25
 
 
26
/**
 
27
 * @ingroup lib
 
28
 * @file
 
29
 *
 
30
 * String evaluation.
 
31
 *
 
32
 * @author Raphael Manfredi
 
33
 * @date 2003
 
34
 */
 
35
 
 
36
#include "common.h"
 
37
 
 
38
RCSID("$Id: eval.c,v 1.7 2005/06/29 14:24:26 daichik Exp $");
 
39
 
 
40
#include <pwd.h>
 
41
 
 
42
#include "eval.h"
 
43
#include "atoms.h"
 
44
#include "misc.h"                       /* For g_strlcpy() */
 
45
#include "override.h"           /* Must be the last header included */
 
46
 
 
47
#define MAX_STRING      1024    /**< Max length for substitution */
 
48
 
 
49
static guint32 common_dbg = 0;  /**< XXX -- need to init lib's props --RAM */
 
50
 
 
51
static GHashTable *constants;
 
52
static gchar *home;
 
53
 
 
54
static gchar *get_home(void);
 
55
static gchar *get_variable(gchar *s, gchar **end);
 
56
 
 
57
/**
 
58
 * Create a constant string, or reuse an existing one if possible.
 
59
 *
 
60
 * @returns a string atom.
 
61
 */
 
62
static gchar *
 
63
constant_make(gchar *s)
 
64
{
 
65
        gchar *v;
 
66
 
 
67
        v = (gchar *) g_hash_table_lookup(constants, s);
 
68
        if (v != NULL)
 
69
                return v;                       /* Already exists */
 
70
 
 
71
        v = atom_str_get(s);
 
72
        g_hash_table_insert(constants, v, v);
 
73
 
 
74
        return v;
 
75
}
 
76
 
 
77
/**
 
78
 * Initialize string evaluation.
 
79
 */
 
80
void
 
81
eval_init(void)
 
82
{
 
83
        constants = g_hash_table_new(g_str_hash, g_str_equal);
 
84
        home = get_home();
 
85
}
 
86
 
 
87
static void
 
88
constants_free_kv(gpointer key,
 
89
        gpointer unused_val, gpointer unused_x)
 
90
{
 
91
        (void) unused_val;
 
92
        (void) unused_x;
 
93
        atom_str_free(key);
 
94
}
 
95
 
 
96
/**
 
97
 * Cleanup local structures at shutdown time.
 
98
 */
 
99
void
 
100
eval_close(void)
 
101
{
 
102
        atom_str_free(home);
 
103
 
 
104
        g_hash_table_foreach(constants, constants_free_kv, NULL);
 
105
        g_hash_table_destroy(constants);
 
106
}
 
107
 
 
108
/**
 
109
 * Insert value `val' at beginning of string `start'.
 
110
 *
 
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.
 
114
 *
 
115
 * @return the pointer right after the inserted value.
 
116
 */
 
117
static gchar *
 
118
insert_value(gchar *val, gchar *start, gint off,
 
119
        gint len, gint maxlen)
 
120
{
 
121
        gint vlen = strlen(val);
 
122
 
 
123
        g_assert(len <= maxlen);
 
124
        g_assert(off >= 0 && off <= len);
 
125
 
 
126
        if (len + vlen > maxlen) {
 
127
                g_warning("ignoring variable substitution text \"%s\"", val);
 
128
                return start;
 
129
        }
 
130
 
 
131
        memmove(start + vlen, start, len + 1 - off);
 
132
        memmove(start, val, vlen);
 
133
 
 
134
        return start + vlen;
 
135
}
 
136
 
 
137
/**
 
138
 * Needs brief description here.
 
139
 *
 
140
 * Substitutes variables from string:
 
141
 *
 
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.
 
145
 *
 
146
 * If given a NULL input, we return NULL.
 
147
 *
 
148
 * @return string atom, which is not meant to be freed until exit time.
 
149
 */
 
150
gchar *
 
151
eval_subst(const gchar *str)
 
152
{
 
153
        gchar buf[MAX_STRING];
 
154
        gchar *p;
 
155
        gchar *end = buf + sizeof(buf);
 
156
        size_t len;
 
157
        gchar c;
 
158
 
 
159
        if (str == NULL)
 
160
                return NULL;
 
161
 
 
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)",
 
165
                        (int) len);
 
166
                return constant_make((gchar *) str);
 
167
        }
 
168
 
 
169
 
 
170
        if (common_dbg > 3)
 
171
                printf("eval_subst: on entry: \"%s\"\n", buf);
 
172
 
 
173
        for (p =  buf, c = *p++; c; c = *p++) {
 
174
                gchar *val = NULL;
 
175
                gchar *start = p - 1;
 
176
 
 
177
                if (c == '~' && start == buf) {         /* Leading ~ only */
 
178
                        val = home;
 
179
                        memmove(start, start + 1, len - (start - buf));
 
180
                        len--;
 
181
 
 
182
                        g_assert((ssize_t) len >= 0);
 
183
 
 
184
                } else if (c == '$') {
 
185
                        gchar *after;
 
186
 
 
187
                        val = get_variable(p, &after);
 
188
                        memmove(start, after, len + 1 - (after - buf));
 
189
                        len -= after - start;           /* Also removing leading '$' */
 
190
 
 
191
                        g_assert((ssize_t) len >= 0);
 
192
                }
 
193
 
 
194
 
 
195
                if (val != NULL) {
 
196
                        gchar *next = insert_value(
 
197
                                val, start, start - buf, len, sizeof(buf) - 1);
 
198
 
 
199
                        len += next - start;
 
200
                        p = next;
 
201
 
 
202
                        g_assert(len < sizeof(buf));
 
203
                        g_assert(p < end);
 
204
                }
 
205
 
 
206
                g_assert(p <= (buf + len));
 
207
        }
 
208
 
 
209
        if (common_dbg > 3)
 
210
                printf("eval_subst: on exit: \"%s\"\n", buf);
 
211
 
 
212
        g_assert(len == strlen(buf));
 
213
 
 
214
        return constant_make(buf);
 
215
}
 
216
 
 
217
/**
 
218
 * Compute the user's home directory.
 
219
 * Uses the HOME environment variable first, then the entry from /etc/passwd.
 
220
 *
 
221
 * @return string atom.
 
222
 */
 
223
static gchar *
 
224
get_home(void)
 
225
{
 
226
        gchar *v;
 
227
        struct passwd *pp;
 
228
 
 
229
        v = getenv("HOME");
 
230
        if (v != NULL)
 
231
                return atom_str_get(v);
 
232
 
 
233
        pp = getpwuid(getuid());
 
234
        if (pp != NULL)
 
235
                return atom_str_get(pp->pw_dir);
 
236
 
 
237
        g_warning("Could not determine home directory");
 
238
        return atom_str_get("/");
 
239
}
 
240
 
 
241
/**
 
242
 * Extract variable name from string `s', then fetch value from environment.
 
243
 *
 
244
 * @return variable's value, or "" if not found and set `end' to the address
 
245
 * of the character right after the variable name.
 
246
 */
 
247
static gchar *get_variable(gchar *s, gchar **end)
 
248
{
 
249
        guchar *p = (guchar *) s;
 
250
        guchar c;
 
251
        gchar *name = s;
 
252
        gchar *value;
 
253
        gboolean end_brace = FALSE;
 
254
 
 
255
        /*
 
256
         * Grab variable's name.
 
257
         */
 
258
 
 
259
        if (*p == '{') {
 
260
                p++;
 
261
                name++;
 
262
                end_brace = TRUE;
 
263
        }
 
264
 
 
265
        while ((c = *p)) {
 
266
                if (!isalnum(c) && c != '_')
 
267
                        break;
 
268
                p++;
 
269
        }
 
270
 
 
271
        if (end_brace && *p == '}')
 
272
                *end = (gchar *) (p + 1);
 
273
        else
 
274
                *end = (gchar *) p;
 
275
 
 
276
        /*
 
277
         * Get value from environment.
 
278
         */
 
279
 
 
280
        c = *p;
 
281
        *p = '\0';
 
282
        value = getenv(name);
 
283
 
 
284
        if (value == NULL)
 
285
                value = "";
 
286
 
 
287
        if (common_dbg > 4)
 
288
                printf("variable \"%s\" is \"%s\"\n", name, value);
 
289
 
 
290
        *p = c;
 
291
 
 
292
        return value;
 
293
}
 
294
 
 
295
/* vi: set ts=4 sw=4 cindent: */