missing NULL terminator in set_config_x
[geda-gaf.git] / gschem / src / gschem.c
blob06227bac3841353500a613b44e262868a7417da6
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2020 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
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.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include <config.h>
21 #include <version.h>
23 #include <stdio.h>
24 #ifdef HAVE_STRING_H
25 #include <string.h>
26 #endif
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
31 #include <glib.h>
33 #include "gschem.h"
35 #ifdef HAVE_LOCALE_H
36 #include <locale.h>
37 #endif
39 /* These are generated by parse_commandline() */
40 extern SCM s_pre_load_expr;
41 extern SCM s_post_load_expr;
43 typedef struct {
44 gschem_atexit_func func;
45 gpointer arg;
46 } gschem_atexit_struct;
48 static GList *exit_functions = NULL;
50 /*! \brief Register a function to be called on program exit
52 * \par Function Description
53 * This function registers a function to be called on
54 * program exit. Multiple functions will be executed in
55 * the order they are registered.
57 * \param [in] func a pointer to the function to be registered
58 * \param [in] data an arbitrary argument provided to the function
59 * when it is called
61 void gschem_atexit(gschem_atexit_func func, gpointer data)
63 gschem_atexit_struct *p;
65 p = g_new(gschem_atexit_struct, 1);
66 p->func = func;
67 p->arg = data;
68 exit_functions = g_list_append(exit_functions, p);
71 /*! \brief Cleanup gSchem on exit.
72 * \par Function Description
73 * This function cleans up all memory objects allocated during the
74 * gSchem runtime.
76 static void gschem_quit(void)
78 GList *list;
79 gschem_atexit_struct *p;
81 /* Call all registered functions in order */
82 list = exit_functions;
83 while(list != NULL) {
84 p = (gschem_atexit_struct *) list->data;
85 p->func(p->arg);
86 g_free(p);
87 list = g_list_next(list);
89 g_list_free(exit_functions);
91 x_controlfd_free ();
93 s_clib_free();
94 s_slib_free();
95 /* o_text_freeallfonts();*/
96 s_attrib_free();
97 x_fam_free ();
98 x_stroke_free ();
99 o_undo_cleanup();
100 /* s_stroke_free(); no longer needed */
102 i_vars_freenames();
103 i_vars_libgeda_freenames();
105 /* x_window_free_head(); can't do this since it causes a
106 * condition in which window_head->... is still being refered
107 * after this */
109 /* enable this to get more memory usage from glib */
110 /* You also have to enable something in glib I think */
111 /* g_mem_profile();*/
114 /*! \brief Show warning dialog if certain configuration options are set.
116 * Some gnetlist configuration options, but not all, have been moved
117 * from gnetlistrc to geda.conf in 1.9.1. This is not compatible with
118 * the way gnetlist configuration currently works, so the options have
119 * been moved back to gnetlistrc.
121 * Chances are users which have used gEDA/gaf 1.9.1 or 1.9.2 changed
122 * their gnetlist configuration to geda.conf, so their options are now
123 * ignored. Unfortunately, I don't see a way to resolve this silently
124 * (short of adding geda.conf support to gnetlist just for these four
125 * options). Silently producing a broken netlist is a bad thing, so
126 * warn about this issue on gschem startup.
128 static void
129 warn_if_using_invalid_config ()
131 EdaConfig *cfg = eda_config_get_context_for_file (NULL);
132 EdaConfig *cfg_hierarchy_traversal =
133 eda_config_get_source (cfg, "gnetlist", "traverse-hierarchy", NULL);
134 EdaConfig *cfg_net_naming_priority =
135 eda_config_get_source (cfg, "gnetlist", "net-naming-priority", NULL);
136 EdaConfig *cfg_unnamed_netname =
137 eda_config_get_source (cfg, "gnetlist", "default-net-name", NULL);
138 EdaConfig *cfg_unnamed_busname =
139 eda_config_get_source (cfg, "gnetlist", "default-bus-name", NULL);
141 if (cfg_hierarchy_traversal == NULL && cfg_net_naming_priority == NULL &&
142 cfg_unnamed_netname == NULL && cfg_unnamed_busname == NULL)
143 return;
145 GtkWidget *dialog;
146 gchar *hierarchy_traversal_before = "", *hierarchy_traversal_after = "";
147 gchar *net_naming_priority_before = "", *net_naming_priority_after = "";
148 gchar *unnamed_netname_before = "", *unnamed_netname_after = "";
149 gchar *unnamed_busname_before = "", *unnamed_busname_after = "";
151 if (cfg_hierarchy_traversal != NULL) {
152 hierarchy_traversal_before = g_strdup_printf (
153 " traverse-hierarchy (in %s)\n",
154 eda_config_get_filename (cfg_hierarchy_traversal));
155 hierarchy_traversal_after = g_strdup_printf (
156 " (hierarchy-traversal \"%s\")\n",
157 eda_config_get_boolean (cfg, "gnetlist", "traverse-hierarchy", NULL)
158 ? "enabled" : "disabled");
161 if (cfg_net_naming_priority != NULL) {
162 gchar *str;
163 net_naming_priority_before = g_strdup_printf (
164 " net-naming-priority (in %s)\n",
165 eda_config_get_filename (cfg_net_naming_priority));
166 str = eda_config_get_string (cfg, "gnetlist", "net-naming-priority", NULL);
167 net_naming_priority_after = g_strdup_printf (
168 " (net-naming-priority \"%s\")\n",
169 strcmp (str, "netname-attribute") == 0 ? "netname" : "netattrib");
170 g_free (str);
173 if (cfg_unnamed_netname != NULL) {
174 gchar *str;
175 unnamed_netname_before = g_strdup_printf (
176 " default-net-name (in %s)\n",
177 eda_config_get_filename (cfg_unnamed_netname));
178 str = eda_config_get_string (cfg, "gnetlist", "default-net-name", NULL);
179 unnamed_netname_after = g_strdup_printf (
180 " (unnamed-netname \"%s\")\n", str);
181 g_free (str);
184 if (cfg_unnamed_busname != NULL) {
185 gchar *str;
186 unnamed_busname_before = g_strdup_printf (
187 " default-bus-name (in %s)\n",
188 eda_config_get_filename (cfg_unnamed_busname));
189 str = eda_config_get_string (cfg, "gnetlist", "default-bus-name", NULL);
190 unnamed_busname_after = g_strdup_printf (
191 " (unnamed-busname \"%s\")\n", str);
192 g_free (str);
195 dialog = gtk_message_dialog_new (
196 NULL,
197 GTK_DIALOG_MODAL,
198 GTK_MESSAGE_WARNING,
199 GTK_BUTTONS_OK,
200 _("The following options are present in your configuration:\n\n%s%s%s%s\n"
201 "These options were introduced in gEDA/gaf 1.9.1 as a replacement for "
202 "the corresponding gnetlistrc options but were removed again in "
203 "gEDA/gaf 1.10.0. The current version of gnetlist uses gnetlistrc "
204 "options instead:\n\n%s%s%s%s\n"
205 "Please make sure to update your configuration as the options currently "
206 "set won't have the desired effect."),
207 hierarchy_traversal_before, net_naming_priority_before,
208 unnamed_netname_before, unnamed_busname_before,
209 hierarchy_traversal_after, net_naming_priority_after,
210 unnamed_netname_after, unnamed_busname_after);
212 if (cfg_hierarchy_traversal != NULL) {
213 g_free (hierarchy_traversal_before);
214 g_free (hierarchy_traversal_after);
216 if (cfg_net_naming_priority != NULL) {
217 g_free (net_naming_priority_before);
218 g_free (net_naming_priority_after);
220 if (cfg_unnamed_netname != NULL) {
221 g_free (unnamed_netname_before);
222 g_free (unnamed_netname_after);
224 if (cfg_unnamed_busname != NULL) {
225 g_free (unnamed_busname_before);
226 g_free (unnamed_busname_after);
229 gtk_dialog_run (GTK_DIALOG (dialog));
230 gtk_widget_destroy (dialog);
233 /*! \brief Main Scheme(GUILE) program function.
234 * \par Function Description
235 * This function is the main program called from scm_boot_guile.
236 * It handles initializing all libraries and gSchem variables
237 * and passes control to the gtk main loop.
239 void main_prog(void *closure, int argc, char *argv[])
241 int i;
242 char *cwd = NULL;
243 GschemToplevel *w_current = NULL;
244 TOPLEVEL *toplevel = NULL;
245 char *input_str = NULL;
246 int argv_index;
247 GSList *filenames;
248 char *filename;
249 SCM scm_tmp;
251 #ifdef HAVE_GTHREAD
252 /* Gschem isn't threaded, but some of GTK's file chooser
253 * backends uses threading so we need to call g_thread_init().
254 * GLib requires threading be initialised before any other GLib
255 * functions are called. Do it now if its not already setup. */
256 if (!g_thread_supported ()) g_thread_init (NULL);
257 #endif
259 #if ENABLE_NLS
260 /* This must be the same for all locales */
261 setlocale(LC_NUMERIC, "C");
262 #endif
264 gtk_init(&argc, &argv);
266 argv_index = parse_commandline(argc, argv);
267 cwd = g_get_current_dir();
269 libgeda_init();
271 /* create log file right away even if logging is enabled */
272 s_log_init ("gschem");
274 s_log_message(
275 _("gEDA/gschem version %s%s.%s\n"), PREPEND_VERSION_STRING,
276 PACKAGE_DOTTED_VERSION, PACKAGE_DATE_VERSION);
277 s_log_message(
278 _("gEDA/gschem comes with ABSOLUTELY NO WARRANTY; see COPYING for more details.\n"));
279 s_log_message(
280 _("This is free software, and you are welcome to redistribute it under certain\n"
281 "conditions; please see the COPYING file for more details.\n\n"));
283 #if defined(__MINGW32__) && defined(DEBUG)
284 fprintf(stderr, _("This is the MINGW32 port.\n"));
285 #endif
287 #if DEBUG
288 fprintf(stderr, _("Current locale settings: %s\n"), setlocale(LC_ALL, NULL));
289 #endif
291 /* init global buffers */
292 o_buffer_init();
294 /* register guile (scheme) functions */
295 g_register_funcs();
296 g_init_window ();
297 g_init_select ();
298 g_init_hook ();
299 g_init_attrib ();
300 g_init_keys ();
301 gschem_action_init ();
302 g_init_util ();
304 /* initialise color map (need to do this before reading rc files */
305 x_color_init ();
307 o_undo_init();
309 if (s_path_sys_data () == NULL) {
310 const gchar *message =
311 _("You must set the GEDADATA environment variable!\n\n"
312 "gschem cannot locate its data files. You must set the GEDADATA\n"
313 "environment variable to point to the correct location.\n");
314 GtkWidget* error_diag =
315 gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR,
316 GTK_BUTTONS_OK,
317 "%s", message);
318 gtk_dialog_run (GTK_DIALOG (error_diag));
319 g_error ("%s", message);
322 scm_dynwind_begin (0);
324 /* Run pre-load Scheme expressions */
325 g_scm_eval_protected (s_pre_load_expr, scm_current_module ());
327 /* By this point, libgeda should have setup the Guile load path, so
328 * we can take advantage of that. */
329 scm_tmp = scm_sys_search_load_path (scm_from_utf8_string ("gschem.scm"));
330 if (scm_is_false (scm_tmp)) {
331 GtkWidget *dialog;
332 GString *string;
333 gchar *msg;
334 dialog = gtk_message_dialog_new (
335 NULL,
336 GTK_DIALOG_MODAL,
337 GTK_MESSAGE_ERROR,
338 GTK_BUTTONS_CLOSE,
339 _("Can't find Scheme initialization file \"%s\"."),
340 "gschem.scm");
341 string = g_string_new (NULL);
342 g_string_printf (
343 string,
344 _("It appears the gschem data files are missing, or they are not where "
345 "the gschem binary expects them to be.\n\n"
346 "Are you sure you installed gschem?\n\n"
347 "The following directories have been searched for \"%s\":"),
348 "gschem.scm");
349 for (SCM l = scm_variable_ref (scm_c_lookup ("%load-path"));
350 scm_is_pair (l); l = scm_cdr (l)) {
351 char *path = scm_to_utf8_string (scm_car (l));
352 g_string_append_printf (string, "\n\t%s", path);
353 free (path);
355 msg = g_string_free (string, FALSE);
356 g_object_set (dialog, "secondary-text", msg, NULL);
357 g_free (msg);
358 gtk_window_set_title (GTK_WINDOW (dialog), _("gschem"));
359 gtk_dialog_run (GTK_DIALOG (dialog));
360 gtk_widget_destroy (dialog);
361 exit (1);
363 input_str = scm_to_utf8_string (scm_tmp);
364 toplevel = s_toplevel_new ();
365 if (g_read_file(toplevel, input_str, NULL)) {
366 s_log_message(_("Read init scm file [%s]\n"), input_str);
367 } else {
368 /*! \todo These two messages are the same. Should be
369 * integrated. */
370 s_log_message(_("Failed to read init scm file [%s]\n"),
371 input_str);
373 free (input_str); /* M'allocated by scm_to_utf8_string() */
374 scm_remember_upto_here_1 (scm_tmp);
376 /* Set up default configuration */
377 i_vars_init_gschem_defaults ();
378 gschem_atexit (i_vars_atexit_save_user_config, NULL);
380 /* Now read in RC files. */
381 g_rc_parse_gtkrc();
382 x_rc_parse_gschem (toplevel, NULL);
384 /* Set default icon theme and make sure we can find our own icons */
385 x_window_set_default_icon();
386 x_window_init_icons ();
388 /* At end, complete set up of window. */
389 x_color_allocate();
391 /* Allocate w_current */
392 w_current = x_window_new (toplevel);
394 g_dynwind_window (w_current);
396 x_stroke_init ();
397 x_fam_init ();
399 filenames = NULL;
401 for (i = argv_index; i < argc; i++) {
403 if (g_path_is_absolute(argv[i]))
405 /* Path is already absolute so no need to do any concat of cwd */
406 filename = g_strdup (argv[i]);
407 } else {
408 filename = g_build_filename (cwd, argv[i], NULL);
411 filenames = g_slist_prepend (filenames, filename);
413 * SDB notes: at this point the filename might be unnormalized, like
414 * /path/to/foo/../bar/baz.sch. Bad filenames will be
415 * normalized in f_open (called by x_highlevel_open_pages).
416 * This works for Linux and MINGW32.
420 filenames = g_slist_reverse (filenames);
421 x_highlevel_open_pages (w_current, filenames, FALSE);
422 g_slist_free_full (filenames, g_free);
424 g_free(cwd);
426 /* Create an empty page if necessary */
427 if (w_current->toplevel->page_current == NULL)
428 x_highlevel_new_page (w_current, NULL);
431 #if DEBUG
432 scm_c_eval_string ("(display \"hello guile\n\")");
433 #endif
435 /* Run post-load expressions */
436 if (scm_is_false (g_scm_eval_protected (s_post_load_expr, scm_current_module ()))) {
437 fprintf (stderr, _("ERROR: Failed to load or evaluate startup script.\n\n"
438 "The gschem log may contain more information.\n"));
439 exit (1);
442 scm_dynwind_end ();
444 x_controlfd_init ();
446 warn_if_using_invalid_config ();
448 /* enter main loop */
449 gtk_main();
451 gschem_quit ();
454 /*! \brief Main executable entrance point.
455 * \par Function Description
456 * This is the main function for gSchem. It sets up the Scheme(GUILE)
457 * environment and passes control to via scm_boot_guile to
458 * the #main_prog function.
460 int main (int argc, char *argv[])
463 #if ENABLE_NLS
464 setlocale(LC_ALL, "");
465 setlocale(LC_NUMERIC, "C");
466 bindtextdomain("geda-gschem", LOCALEDIR);
467 textdomain("geda-gschem");
468 bind_textdomain_codeset("geda-gschem", "UTF-8");
469 #endif
471 scm_boot_guile (argc, argv, main_prog, 0);
473 return 0;