1 /* Lepton EDA library
2 * Copyright (C) 1998-2010 Ales Hvezda
3 * Copyright (C) 1998-2016 gEDA Contributors
4 * Copyright (C) 2016 Peter Brett <peter@peter-b.co.uk>
5 * Copyright (C) 2017-2021 Lepton EDA Contributors
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21 /*! \file g_rc.c
22 * \brief Execute Scheme initialisation files.
23 *
24 * Contains functions to open, parse and manage Scheme initialisation
25 * (RC) files.
26 */
27
28 #include <config.h>
29
30 #include <errno.h>
31 #include <stdio.h>
32 #include <sys/stat.h>
33 #include <ctype.h>
34 #ifdef HAVE_STRING_H
35 #include <string.h>
36 #endif
37 #ifdef HAVE_STDLIB_H
38 #include <stdlib.h>
39 #endif
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43
44 #include "liblepton_priv.h"
45 #include "libleptonguile_priv.h"
46
47
48 /*! \brief Mark an RC file as loaded.
49 * \par Function Description
50 * If the Scheme initialisation file \a filename has not already been
51 * loaded, mark it as loaded and return TRUE, storing \a filename in
52 * \a toplevel (\a filename should not subsequently be freed).
53 * Otherwise, return FALSE, and set \a err appropriately.
54 *
55 * \note Should only be called by g_rc_parse_file().
56 *
57 * \param toplevel The current #LeptonToplevel structure.
58 * \param filename The RC file name to test.
59 * \param err Return location for errors, or NULL.
60 * \return TRUE if \a filename not already loaded, FALSE otherwise.
61 */
62 static gboolean
g_rc_try_mark_read(LeptonToplevel * toplevel,gchar * filename,GError ** err)63 g_rc_try_mark_read (LeptonToplevel *toplevel,
64 gchar *filename,
65 GError **err)
66 {
67 GList *found = NULL;
68 g_return_val_if_fail ((toplevel != NULL), FALSE);
69 g_return_val_if_fail ((filename != NULL), FALSE);
70
71 /* Test if marked read already */
72 found = g_list_find_custom (toplevel->RC_list, filename,
73 (GCompareFunc) strcmp);
74 if (found != NULL) {
75 g_set_error (err, EDA_ERROR, EDA_ERROR_RC_TWICE,
76 _("RC file already loaded"));
77 return FALSE;
78 }
79
80 toplevel->RC_list = g_list_append (toplevel->RC_list, filename);
81 /* N.b. don't free name_norm here; it's stored in the LeptonToplevel. */
82 return TRUE;
83 }
84
85 /*! \brief Load an RC file.
86 * \par Function Description
87 * Load and run the Scheme initialisation file \a rcfile, reporting
88 * errors via \a err.
89 *
90 * \param toplevel The current #LeptonToplevel structure.
91 * \param rcfile The filename of the RC file to load.
92 * \param cfg The configuration context to use while loading.
93 * \param err Return location for errors, or NULL;
94 * \return TRUE on success, FALSE on failure.
95 */
96 static gboolean
g_rc_parse_file(LeptonToplevel * toplevel,const gchar * rcfile,EdaConfig * cfg,GError ** err)97 g_rc_parse_file (LeptonToplevel *toplevel,
98 const gchar *rcfile,
99 EdaConfig *cfg,
100 GError **err)
101 {
102 gchar *name_norm = NULL;
103 GError *tmp_err = NULL;
104 gboolean status = FALSE;
105 g_return_val_if_fail ((toplevel != NULL), FALSE);
106 g_return_val_if_fail ((rcfile != NULL), FALSE);
107
108 /* If no configuration file was specified, get the default
109 * configuration file for the rc file. */
110 if (cfg == NULL) {
111 cfg = eda_config_get_context_for_path (rcfile);
112 }
113 /* If the configuration wasn't loaded yet, attempt to load
114 * it. Config loading is on a best-effort basis; if we fail, just
115 * print a warning. */
116 if (!eda_config_is_loaded (cfg)) {
117 eda_config_load (cfg, &tmp_err);
118 if (tmp_err != NULL &&
119 !g_error_matches (tmp_err, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
120 g_warning (_("Failed to load config from '%1$s': %2$s\n"),
121 eda_config_get_filename (cfg), tmp_err->message);
122 g_clear_error (&tmp_err);
123 }
124
125 /* Normalise filename */
126 name_norm = f_normalize_filename (rcfile, err);
127 if (name_norm == NULL) return FALSE;
128
129 /* Attempt to load the RC file, if it hasn't been loaded already.
130 * If g_rc_try_mark_read() succeeds, it stores name_norm in
131 * toplevel, so we *don't* free it. */
132 status = (g_rc_try_mark_read (toplevel, name_norm, &tmp_err)
133 && g_read_file (toplevel, name_norm, &tmp_err));
134
135 if (status) {
136 g_message (_("Loaded RC file [%1$s]"), name_norm);
137 } else {
138 /* Copy tmp_err into err, with a prefixed message. */
139 g_propagate_prefixed_error (err, tmp_err,
140 _("Failed to load RC file [%1$s]: "),
141 name_norm);
142 g_free (name_norm);
143 }
144 return status;
145 }
146
147 /*! \brief Load a system RC file.
148 * \par Function Description
149 * Attempts to load and run the system Scheme initialisation file with
150 * basename \a rcname. The string "system-" is prefixed to \a rcname.
151 * If \a rcname is NULL, the default value of "gafrc" is used.
152 *
153 * \param toplevel The current #LeptonToplevel structure.
154 * \param rcname The basename of the RC file to load, or NULL.
155 * \param err Return location for errors, or NULL.
156 * \return TRUE on success, FALSE on failure.
157 */
158 gboolean
g_rc_parse_system(LeptonToplevel * toplevel,const gchar * rcname,GError ** err)159 g_rc_parse_system (LeptonToplevel *toplevel,
160 const gchar *rcname,
161 GError **err)
162 {
163 gchar *sysname = NULL;
164 gchar *rcfile = NULL;
165 gboolean status = TRUE;
166 const gchar * const * sys_dirs = eda_get_system_config_dirs();
167 EdaConfig *cfg = eda_config_get_system_context();
168
169 /* Default to gafrc */
170 rcname = (rcname != NULL) ? rcname : "gafrc";
171
172 sysname = g_strdup_printf ("system-%s", rcname);
173 for (gint i = 0; sys_dirs[i]; ++i)
174 {
175 rcfile = g_build_filename (sys_dirs[i], sysname, NULL);
176 if (g_file_test(rcfile, G_FILE_TEST_IS_REGULAR))
177 {
178 break;
179 }
180 g_free(rcfile);
181 rcfile = NULL;
182 }
183
184 if (rcfile)
185 {
186 status = g_rc_parse_file (toplevel, rcfile, cfg, err);
187 }
188
189 g_free (rcfile);
190 g_free (sysname);
191 return status;
192 }
193
194 /*! \brief Load a user RC file.
195 * \par Function Description
196 * Attempts to load the user Scheme initialisation file with basename
197 * \a rcname. If \a rcname is NULL, the default value of "gafrc" is
198 * used.
199 *
200 * \param toplevel The current #LeptonToplevel structure.
201 * \param rcname The basename of the RC file to load, or NULL.
202 * \param err Return location for errors, or NULL.
203 * \return TRUE on success, FALSE on failure.
204 */
205 gboolean
g_rc_parse_user(LeptonToplevel * toplevel,const gchar * rcname,GError ** err)206 g_rc_parse_user (LeptonToplevel *toplevel,
207 const gchar *rcname,
208 GError **err)
209 {
210 gchar *rcfile = NULL;
211 gboolean status;
212
213 /* Default to gafrc */
214 rcname = (rcname != NULL) ? rcname : "gafrc";
215
216 rcfile = g_build_filename (eda_get_user_config_dir (), rcname, NULL);
217 status = g_rc_parse_file (toplevel, rcfile,
218 eda_config_get_user_context (), err);
219 g_free (rcfile);
220 return status;
221 }
222
223 /*! \brief Load a local RC file.
224 * \par Function Description
225 * Attempts to load the Scheme initialisation file with basename \a
226 * rcname corresponding to \a path, reporting errors via \a err. If
227 * \a path is a directory, looks for a file named \a rcname in that
228 * directory. Otherwise, looks for a file named \a rcname in the same
229 * directory as \a path. If \a path is NULL, looks in the current
230 * directory. If \a rcname is NULL, the default value of "gafrc" is
231 * used.
232 *
233 * \param toplevel The current #LeptonToplevel structure.
234 * \param rcname The basename of the RC file to load, or NULL.
235 * \param path The path to load a RC file for, or NULL.
236 * \param err Return location for errors, or NULL.
237 * \return TRUE on success, FALSE on failure.
238 */
239 gboolean
g_rc_parse_local(LeptonToplevel * toplevel,const gchar * rcname,const gchar * path,GError ** err)240 g_rc_parse_local (LeptonToplevel *toplevel,
241 const gchar *rcname,
242 const gchar *path,
243 GError **err)
244 {
245 gchar *dir = NULL;
246 gchar *rcfile = NULL;
247 gboolean status;
248 g_return_val_if_fail ((toplevel != NULL), FALSE);
249
250 /* Default to gafrc */
251 rcname = (rcname != NULL) ? rcname : "gafrc";
252 /* Default to cwd */
253 path = (path != NULL) ? path : ".";
254
255 /* If path isn't a directory, get the dirname. */
256 if (g_file_test (path, G_FILE_TEST_IS_DIR)) {
257 dir = g_strdup (path);
258 } else {
259 dir = g_path_get_dirname (path);
260 }
261
262 rcfile = g_build_filename (dir, rcname, NULL);
263 status = g_rc_parse_file (toplevel, rcfile, NULL, err);
264
265 g_free (dir);
266 g_free (rcfile);
267 return status;
268 }
269
270 static void
g_rc_parse__process_error(GError ** err,const gchar * pname)271 g_rc_parse__process_error (GError **err, const gchar *pname)
272 {
273 char *pbase;
274
275 /* Take no chances; if err was not set for some reason, bail out. */
276 if (*err == NULL) {
277 const gchar *msgl =
278 _("ERROR: An unknown error occurred while parsing configuration files.");
279 g_message ("%1$s", msgl);
280 fprintf(stderr, "%1$s\n", msgl);
281
282 } else {
283 /* RC files are allowed to be missing or skipped; check for
284 * this. */
285 if (g_error_matches (*err, G_FILE_ERROR, G_FILE_ERROR_NOENT) ||
286 g_error_matches (*err, EDA_ERROR, EDA_ERROR_RC_TWICE)) {
287 return;
288 }
289
290 g_message (_("ERROR: %1$s"), (*err)->message);
291 fprintf (stderr, _("ERROR: %1$s\n"), (*err)->message);
292 }
293
294 /* g_path_get_basename() allocates memory, but we don't care
295 * because we're about to exit. */
296 pbase = g_path_get_basename (pname);
297 fprintf (stderr, _("ERROR: The %1$s log may contain more information.\n"),
298 pbase);
299 exit (1);
300 }
301
302 /*! \brief General RC file parsing function.
303 * \par Function Description
304 * Calls g_rc_parse_handler() with the default error handler. If any
305 * error other than ENOENT occurs while loading or running a Scheme
306 * initialisation file, prints an informative message and calls
307 * exit(1).
308 *
309 * \bug libgeda shouldn't call exit() - this function calls
310 * g_rc_parse__process_error(), which does.
311 *
312 * \warning Since this function may not return, it should only be used
313 * on application startup or when there is no chance of data loss from
314 * an unexpected exit().
315 *
316 * \param [in] pname The name of the application (usually argv[0]).
317 * \param [in] rcname RC file basename, or NULL.
318 * \param [in] rcfile Specific RC file path, or NULL.
319 */
320 void
g_rc_parse(const gchar * pname,const gchar * rcname,const gchar * rcfile)321 g_rc_parse (const gchar *pname,
322 const gchar *rcname,
323 const gchar *rcfile)
324 {
325 LeptonToplevel *toplevel = edascm_c_current_toplevel ();
326 g_rc_parse_handler (toplevel, rcname, rcfile,
327 (ConfigParseErrorFunc) g_rc_parse__process_error,
328 (void *) pname);
329 }
330
331
332 /*! \brief General RC file parsing function.
333 * \par Function Description
334 * Attempt to load and run system, user and local (current working directory)
335 * Scheme initialisation files, first with the default "gafrc"
336 * basename and then with the basename \a rcname, if \a rcname is not
337 * NULL. Additionally, attempt to load and run \a rcfile
338 * if \a rcfile is not NULL.
339 *
340 * If an error occurs, calls \a handler with the provided \a user_data
341 * and a GError.
342 *
343 * \see g_rc_parse().
344 *
345 * \param toplevel The current #LeptonToplevel structure.
346 * \param rcname RC file basename, or NULL.
347 * \param rcfile Specific RC file path, or NULL.
348 * \param handler Handler function for RC errors.
349 * \param user_data Data to be passed to \a handler.
350 */
351 void
g_rc_parse_handler(LeptonToplevel * toplevel,const gchar * rcname,const gchar * rcfile,ConfigParseErrorFunc handler,void * user_data)352 g_rc_parse_handler (LeptonToplevel *toplevel,
353 const gchar *rcname,
354 const gchar *rcfile,
355 ConfigParseErrorFunc handler,
356 void *user_data)
357 {
358 GError *err = NULL;
359
360 #ifdef HANDLER_DISPATCH
361 # error HANDLER_DISPATCH already defined
362 #endif
363 #define HANDLER_DISPATCH \
364 do { if (err == NULL) break; handler (&err, user_data); \
365 g_clear_error (&err); } while (0)
366
367 /* Load cache configuration: */
368 g_rc_load_cache_config (toplevel, &err); HANDLER_DISPATCH;
369
370 /* Load RC files in order. */
371 /* First gafrc files. */
372 g_rc_parse_system (toplevel, NULL, &err); HANDLER_DISPATCH;
373 g_rc_parse_user (toplevel, NULL, &err); HANDLER_DISPATCH;
374 g_rc_parse_local (toplevel, NULL, NULL, &err); HANDLER_DISPATCH;
375 /* Next application-specific rcname. */
376 if (rcname != NULL) {
377 g_rc_parse_system (toplevel, rcname, &err); HANDLER_DISPATCH;
378 g_rc_parse_user (toplevel, rcname, &err); HANDLER_DISPATCH;
379 g_rc_parse_local (toplevel, rcname, NULL, &err); HANDLER_DISPATCH;
380 }
381 /* Finally, optional additional RC file. Specifically use the
382 * current working directory's configuration context here, no matter
383 * where the rc file is located on disk. */
384 if (rcfile != NULL) {
385 EdaConfig *cwd_cfg = eda_config_get_context_for_path (".");
386 g_rc_parse_file (toplevel, rcfile, cwd_cfg, &err); HANDLER_DISPATCH;
387 }
388
389 #undef HANDLER_DISPATCH
390 }
391
392
393 /*! \brief Load cache configuration data.
394 *
395 * \param toplevel The current #LeptonToplevel structure.
396 * \param err Return location for errors, or NULL.
397 * \return TRUE on success, FALSE on failure.
398 */
399 gboolean
g_rc_load_cache_config(LeptonToplevel * toplevel,GError ** err)400 g_rc_load_cache_config (LeptonToplevel* toplevel,
401 GError** err)
402 {
403 g_return_val_if_fail (toplevel != NULL, FALSE);
404
405 EdaConfig* cfg = eda_config_get_cache_context();
406
407 gboolean status = FALSE;
408 if (cfg != NULL)
409 {
410 GError* tmp_err = NULL;
411 status = eda_config_load (cfg, &tmp_err);
412
413 /* It's OK if file is not found (e.g. on first program run): */
414 if (g_error_matches (tmp_err, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
415 {
416 g_clear_error (&tmp_err);
417 status = TRUE;
418 }
419 }
420
421 return status;
422 }
423