Branch data Line data Source code
1 : : /*
2 : : * gnc-environment.c:
3 : : *
4 : : * Copyright (C) 2013 Geert Janssens <geert@kobaltwit.be>
5 : : *
6 : : * This program is free software; you can redistribute it and/or
7 : : * modify it under the terms of the GNU General Public License as
8 : : * published by the Free Software Foundation; either version 2 of
9 : : * the License, or (at your option) any later version.
10 : : *
11 : : * This program is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : : * GNU General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU General Public License
17 : : * along with this program; if not, contact:
18 : : *
19 : : * Free Software Foundation Voice: +1-617-542-5942
20 : : * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
21 : : * Boston, MA 02110-1301, USA gnu@gnu.org
22 : : */
23 : :
24 : : #include <glib.h>
25 : : #include <stdbool.h>
26 : : #include <stdio.h>
27 : :
28 : : #include <string.h>
29 : : #include "gnc-environment.h"
30 : : #include "gnc-path.h"
31 : :
32 : 24 : static gchar *environment_expand(gchar *param)
33 : : {
34 : : gchar *search_start;
35 : : gchar *opening_brace;
36 : : gchar *closing_brace;
37 : : gchar *result;
38 : : gchar *tmp;
39 : 24 : gchar *expanded = NULL;
40 : :
41 : 24 : if (!param)
42 : 0 : return NULL;
43 : :
44 : : /* Set an initial return value, so we can always use g_strconcat below) */
45 : 24 : result = g_strdup ("x");
46 : :
47 : : /* Look for matching pairs of { and }. Anything in between should be expanded */
48 : 24 : search_start = param;
49 : 24 : opening_brace = g_strstr_len (search_start, -1, "{");
50 : 24 : closing_brace = g_strstr_len (search_start, -1, "}");
51 : :
52 : : /* Note: the test on valid braces is fairly simple:
53 : : * * if no pair of opening/closing braces is found, no expansion occurs
54 : : * * braces can't be nested, this will give unexpected results
55 : : * * the string should contain no other braces than those used to mark
56 : : * expandable variables, or unexpected results will be returned.
57 : : */
58 : 44 : while ( opening_brace && closing_brace && (closing_brace > opening_brace) )
59 : : {
60 : : /* Found a first matching pair */
61 : : gchar *to_expand;
62 : : const gchar *env_val;
63 : :
64 : : /* If the string had characters before the opening {, copy them first */
65 : 20 : if (opening_brace > search_start)
66 : : {
67 : 0 : gchar *prefix = g_strndup (search_start, opening_brace - search_start);
68 : :
69 : 0 : tmp = g_strconcat (result, prefix, NULL);
70 : 0 : g_free (result);
71 : 0 : result = tmp;
72 : 0 : g_free (prefix);
73 : : }
74 : :
75 : : /* Expand the variable we found and append it to the result */
76 : 20 : to_expand = g_strndup (opening_brace + 1, closing_brace - opening_brace - 1);
77 : 20 : env_val = g_getenv (to_expand);
78 : 20 : tmp = g_strconcat (result, env_val, NULL);
79 : 20 : g_free (result);
80 : 20 : result = tmp;
81 : 20 : g_free (to_expand);
82 : :
83 : : /* Look for matching pairs of { and }. Anything in between should be expanded */
84 : 20 : search_start = closing_brace + 1;
85 : 20 : opening_brace = g_strstr_len (search_start, -1, "{");
86 : 20 : closing_brace = g_strstr_len (search_start, -1, "}");
87 : : }
88 : :
89 : : /* No more braces found, append the remaining characters */
90 : 24 : tmp = g_strconcat (result, search_start, NULL);
91 : 24 : g_free (result);
92 : 24 : result = tmp;
93 : :
94 : : /* Remove the "x" from our result */
95 : 24 : if (g_strcmp0 (result, "x"))
96 : 36 : expanded = g_strdup (result + 1);
97 : 24 : g_free (result);
98 : :
99 : 24 : return expanded;
100 : : }
101 : :
102 : : static bool
103 : 7 : char_array_contains(const char **array, unsigned num_keys, const char *key)
104 : : {
105 : 49 : for (unsigned i = 0; i < num_keys; ++i)
106 : : {
107 : 42 : if (strcmp(key, array[i]) == 0)
108 : 0 : return true;
109 : : }
110 : 7 : return false;
111 : : }
112 : :
113 : : static void
114 : 2 : gnc_environment_parse_one (const gchar *env_path)
115 : : {
116 : 2 : GKeyFile *keyfile = g_key_file_new();
117 : : gchar **env_vars;
118 : : gsize param_count;
119 : : gint i;
120 : : gboolean got_keyfile;
121 : 2 : const unsigned num_keys = 6;
122 : 2 : const char *reserved_keys[] = {"GNC_HOME", "GNC_BIN", "GNC_LIB",
123 : : "GNC_DATA", "GNC_CONF", "SYS_LIB"};
124 : :
125 : 2 : got_keyfile = g_key_file_load_from_file (keyfile, env_path, G_KEY_FILE_NONE, NULL);
126 : 2 : if ( !got_keyfile )
127 : : {
128 : 1 : g_key_file_free(keyfile);
129 : 1 : return;
130 : : }
131 : :
132 : : /* Read the environment overrides and apply them */
133 : 1 : env_vars = g_key_file_get_keys(keyfile, "Variables", ¶m_count, NULL);
134 : 8 : for ( i = 0; i < param_count; i++ )
135 : : {
136 : : gchar **val_list;
137 : : gsize val_count;
138 : : gint j;
139 : 7 : gchar *new_val = NULL, *tmp_val;
140 : 7 : if (char_array_contains(reserved_keys, num_keys, env_vars[i]))
141 : 0 : continue;
142 : :
143 : : /* for each variable, read its new value, optionally expand it and set/unset it */
144 : 7 : val_list = g_key_file_get_string_list (keyfile, "Variables",
145 : 7 : env_vars[i], &val_count,
146 : : NULL);
147 : 7 : if ( val_count == 0 )
148 : 0 : g_unsetenv (env_vars[i]);
149 : : else
150 : : {
151 : : /* Set an initial return value, so we can always use g_build_path below) */
152 : 7 : tmp_val = g_strdup ("x");
153 : 31 : for ( j = 0; j < val_count; j++ )
154 : : {
155 : 24 : gchar *expanded = environment_expand (val_list[j]);
156 : 24 : if (expanded && strlen(expanded))
157 : : {
158 : 18 : new_val = g_build_path (G_SEARCHPATH_SEPARATOR_S, tmp_val, expanded, NULL);
159 : 18 : g_free (tmp_val);
160 : 18 : g_free(expanded);
161 : 18 : tmp_val = new_val;
162 : : }
163 : : }
164 : 7 : g_strfreev (val_list);
165 : :
166 : : /* Remove the "x" from our result */
167 : 7 : if (g_strcmp0 (tmp_val, "x"))
168 : : {
169 : 7 : new_val = g_strdup (tmp_val + sizeof (G_SEARCHPATH_SEPARATOR_S));
170 : 7 : g_free (tmp_val);
171 : : }
172 : 7 : if (!g_setenv (env_vars[i], new_val, TRUE))
173 : 0 : g_warning ("Couldn't properly override environment variable \"%s\". "
174 : : "This may lead to unexpected results", env_vars[i]);
175 : 7 : g_free(new_val);
176 : : }
177 : : }
178 : :
179 : 1 : g_strfreev(env_vars);
180 : 1 : g_key_file_free(keyfile);
181 : : }
182 : :
183 : : void
184 : 1 : gnc_environment_setup (void)
185 : : {
186 : : gchar *config_path;
187 : : gchar *env_path;
188 : : gchar *env_parm;
189 : :
190 : : /* Export default parameters to the environment */
191 : 1 : env_parm = gnc_path_get_prefix();
192 : 1 : if (!g_setenv("GNC_HOME", env_parm, TRUE))
193 : 0 : g_warning ("Couldn't set/override environment variable GNC_HOME.");
194 : 1 : g_free (env_parm);
195 : 1 : env_parm = gnc_path_get_bindir();
196 : 1 : if (!g_setenv("GNC_BIN", env_parm, TRUE))
197 : 0 : g_warning ("Couldn't set/override environment variable GNC_BIN.");
198 : 1 : g_free (env_parm);
199 : 1 : env_parm = gnc_path_get_pkglibdir();
200 : 1 : if (!g_setenv("GNC_LIB", env_parm, TRUE))
201 : 0 : g_warning ("Couldn't set/override environment variable GNC_LIB.");
202 : 1 : g_free (env_parm);
203 : 1 : env_parm = gnc_path_get_pkgdatadir();
204 : 1 : if (!g_setenv("GNC_DATA", env_parm, TRUE))
205 : 0 : g_warning ("Couldn't set/override environment variable GNC_DATA.");
206 : 1 : g_free (env_parm);
207 : 1 : env_parm = gnc_path_get_pkgsysconfdir();
208 : 1 : if (!g_setenv("GNC_CONF", env_parm, TRUE))
209 : 0 : g_warning ("Couldn't set/override environment variable GNC_CONF.");
210 : 1 : g_free (env_parm);
211 : 1 : env_parm = gnc_path_get_libdir();
212 : 1 : if (!g_setenv("SYS_LIB", env_parm, TRUE))
213 : 0 : g_warning ("Couldn't set/override environment variable SYS_LIB.");
214 : 1 : g_free (env_parm);
215 : :
216 : 1 : config_path = gnc_path_get_pkgsysconfdir();
217 : : #ifdef G_OS_WIN32
218 : : {
219 : : /* unhide files without extension */
220 : : gchar *pathext = g_build_path(";", ".", g_getenv("PATHEXT"),
221 : : (gchar*) NULL);
222 : : g_setenv("PATHEXT", pathext, TRUE);
223 : : g_free(pathext);
224 : : }
225 : : #endif
226 : :
227 : : /* Parse the environment file that got installed with gnucash */
228 : 1 : env_path = g_build_filename (config_path, "environment", NULL);
229 : 1 : gnc_environment_parse_one(env_path);
230 : 1 : g_free (env_path);
231 : :
232 : : /* Parse local overrides for this file */
233 : 1 : env_path = g_build_filename (config_path, "environment.local", NULL);
234 : 1 : gnc_environment_parse_one(env_path);
235 : 1 : g_free (env_path);
236 : 1 : g_free (config_path);
237 : 1 : }
|