GnuCash  5.6-150-g038405b370+
gnc-environment.c
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 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  gchar *expanded = NULL;
40 
41  if (!param)
42  return NULL;
43 
44  /* Set an initial return value, so we can always use g_strconcat below) */
45  result = g_strdup ("x");
46 
47  /* Look for matching pairs of { and }. Anything in between should be expanded */
48  search_start = param;
49  opening_brace = g_strstr_len (search_start, -1, "{");
50  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  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  if (opening_brace > search_start)
66  {
67  gchar *prefix = g_strndup (search_start, opening_brace - search_start);
68 
69  tmp = g_strconcat (result, prefix, NULL);
70  g_free (result);
71  result = tmp;
72  g_free (prefix);
73  }
74 
75  /* Expand the variable we found and append it to the result */
76  to_expand = g_strndup (opening_brace + 1, closing_brace - opening_brace - 1);
77  env_val = g_getenv (to_expand);
78  tmp = g_strconcat (result, env_val, NULL);
79  g_free (result);
80  result = tmp;
81  g_free (to_expand);
82 
83  /* Look for matching pairs of { and }. Anything in between should be expanded */
84  search_start = closing_brace + 1;
85  opening_brace = g_strstr_len (search_start, -1, "{");
86  closing_brace = g_strstr_len (search_start, -1, "}");
87  }
88 
89  /* No more braces found, append the remaining characters */
90  tmp = g_strconcat (result, search_start, NULL);
91  g_free (result);
92  result = tmp;
93 
94  /* Remove the "x" from our result */
95  if (g_strcmp0 (result, "x"))
96  expanded = g_strdup (result + 1);
97  g_free (result);
98 
99  return expanded;
100 }
101 
102 static bool
103 char_array_contains(const char **array, unsigned num_keys, const char *key)
104 {
105  for (unsigned i = 0; i < num_keys; ++i)
106  {
107  if (strcmp(key, array[i]) == 0)
108  return true;
109  }
110  return false;
111 }
112 
113 static void
114 gnc_environment_parse_one (const gchar *env_path)
115 {
116  GKeyFile *keyfile = g_key_file_new();
117  gchar **env_vars;
118  gsize param_count;
119  gint i;
120  gboolean got_keyfile;
121  const unsigned num_keys = 6;
122  const char *reserved_keys[] = {"GNC_HOME", "GNC_BIN", "GNC_LIB",
123  "GNC_DATA", "GNC_CONF", "SYS_LIB"};
124 
125  got_keyfile = g_key_file_load_from_file (keyfile, env_path, G_KEY_FILE_NONE, NULL);
126  if ( !got_keyfile )
127  {
128  g_key_file_free(keyfile);
129  return;
130  }
131 
132  /* Read the environment overrides and apply them */
133  env_vars = g_key_file_get_keys(keyfile, "Variables", &param_count, NULL);
134  for ( i = 0; i < param_count; i++ )
135  {
136  gchar **val_list;
137  gsize val_count;
138  gint j;
139  gchar *new_val = NULL, *tmp_val;
140  if (char_array_contains(reserved_keys, num_keys, env_vars[i]))
141  continue;
142 
143  /* for each variable, read its new value, optionally expand it and set/unset it */
144  val_list = g_key_file_get_string_list (keyfile, "Variables",
145  env_vars[i], &val_count,
146  NULL);
147  if ( val_count == 0 )
148  g_unsetenv (env_vars[i]);
149  else
150  {
151  /* Set an initial return value, so we can always use g_build_path below) */
152  tmp_val = g_strdup ("x");
153  for ( j = 0; j < val_count; j++ )
154  {
155  gchar *expanded = environment_expand (val_list[j]);
156  if (expanded && strlen(expanded))
157  {
158  new_val = g_build_path (G_SEARCHPATH_SEPARATOR_S, tmp_val, expanded, NULL);
159  g_free (tmp_val);
160  g_free(expanded);
161  tmp_val = new_val;
162  }
163  }
164  g_strfreev (val_list);
165 
166  /* Remove the "x" from our result */
167  if (g_strcmp0 (tmp_val, "x"))
168  {
169  new_val = g_strdup (tmp_val + sizeof (G_SEARCHPATH_SEPARATOR_S));
170  g_free (tmp_val);
171  }
172  if (!g_setenv (env_vars[i], new_val, TRUE))
173  g_warning ("Couldn't properly override environment variable \"%s\". "
174  "This may lead to unexpected results", env_vars[i]);
175  g_free(new_val);
176  }
177  }
178 
179  g_strfreev(env_vars);
180  g_key_file_free(keyfile);
181 }
182 
183 void
185 {
186  gchar *config_path;
187  gchar *env_path;
188  gchar *env_parm;
189 
190  /* Export default parameters to the environment */
191  env_parm = gnc_path_get_prefix();
192  if (!g_setenv("GNC_HOME", env_parm, TRUE))
193  g_warning ("Couldn't set/override environment variable GNC_HOME.");
194  g_free (env_parm);
195  env_parm = gnc_path_get_bindir();
196  if (!g_setenv("GNC_BIN", env_parm, TRUE))
197  g_warning ("Couldn't set/override environment variable GNC_BIN.");
198  g_free (env_parm);
199  env_parm = gnc_path_get_pkglibdir();
200  if (!g_setenv("GNC_LIB", env_parm, TRUE))
201  g_warning ("Couldn't set/override environment variable GNC_LIB.");
202  g_free (env_parm);
203  env_parm = gnc_path_get_pkgdatadir();
204  if (!g_setenv("GNC_DATA", env_parm, TRUE))
205  g_warning ("Couldn't set/override environment variable GNC_DATA.");
206  g_free (env_parm);
207  env_parm = gnc_path_get_pkgsysconfdir();
208  if (!g_setenv("GNC_CONF", env_parm, TRUE))
209  g_warning ("Couldn't set/override environment variable GNC_CONF.");
210  g_free (env_parm);
211  env_parm = gnc_path_get_libdir();
212  if (!g_setenv("SYS_LIB", env_parm, TRUE))
213  g_warning ("Couldn't set/override environment variable SYS_LIB.");
214  g_free (env_parm);
215 
216  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  env_path = g_build_filename (config_path, "environment", NULL);
229  gnc_environment_parse_one(env_path);
230  g_free (env_path);
231 
232  /* Parse local overrides for this file */
233  env_path = g_build_filename (config_path, "environment.local", NULL);
234  gnc_environment_parse_one(env_path);
235  g_free (env_path);
236  g_free (config_path);
237 }
code to set up the environment for proper gnucash functioning.
void gnc_environment_setup(void)
Parse <prefix>/etc/gnucash/environment and set environment variables based on the contents of that fi...