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
39 /* These are generated by parse_commandline() */
40 extern SCM s_pre_load_expr
;
41 extern SCM s_post_load_expr
;
44 gschem_atexit_func func
;
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
61 void gschem_atexit(gschem_atexit_func func
, gpointer data
)
63 gschem_atexit_struct
*p
;
65 p
= g_new(gschem_atexit_struct
, 1);
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
76 static void gschem_quit(void)
79 gschem_atexit_struct
*p
;
81 /* Call all registered functions in order */
82 list
= exit_functions
;
84 p
= (gschem_atexit_struct
*) list
->data
;
87 list
= g_list_next(list
);
89 g_list_free(exit_functions
);
95 /* o_text_freeallfonts();*/
100 /* s_stroke_free(); no longer needed */
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
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.
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
)
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
) {
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");
173 if (cfg_unnamed_netname
!= NULL
) {
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
);
184 if (cfg_unnamed_busname
!= NULL
) {
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
);
195 dialog
= gtk_message_dialog_new (
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
[])
243 GschemToplevel
*w_current
= NULL
;
244 TOPLEVEL
*toplevel
= NULL
;
245 char *input_str
= NULL
;
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
);
260 /* This must be the same for all locales */
261 setlocale(LC_NUMERIC
, "C");
264 gtk_init(&argc
, &argv
);
266 argv_index
= parse_commandline(argc
, argv
);
267 cwd
= g_get_current_dir();
271 /* create log file right away even if logging is enabled */
272 s_log_init ("gschem");
275 _("gEDA/gschem version %s%s.%s\n"), PREPEND_VERSION_STRING
,
276 PACKAGE_DOTTED_VERSION
, PACKAGE_DATE_VERSION
);
278 _("gEDA/gschem comes with ABSOLUTELY NO WARRANTY; see COPYING for more details.\n"));
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"));
288 fprintf(stderr
, _("Current locale settings: %s\n"), setlocale(LC_ALL
, NULL
));
291 /* init global buffers */
294 /* register guile (scheme) functions */
301 gschem_action_init ();
304 /* initialise color map (need to do this before reading rc files */
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
,
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
)) {
334 dialog
= gtk_message_dialog_new (
339 _("Can't find Scheme initialization file \"%s\"."),
341 string
= g_string_new (NULL
);
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\":"),
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
);
355 msg
= g_string_free (string
, FALSE
);
356 g_object_set (dialog
, "secondary-text", msg
, NULL
);
358 gtk_window_set_title (GTK_WINDOW (dialog
), _("gschem"));
359 gtk_dialog_run (GTK_DIALOG (dialog
));
360 gtk_widget_destroy (dialog
);
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
);
368 /*! \todo These two messages are the same. Should be
370 s_log_message(_("Failed to read init scm file [%s]\n"),
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. */
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. */
391 /* Allocate w_current */
392 w_current
= x_window_new (toplevel
);
394 g_dynwind_window (w_current
);
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
]);
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
);
426 /* Create an empty page if necessary */
427 if (w_current
->toplevel
->page_current
== NULL
)
428 x_highlevel_new_page (w_current
, NULL
);
432 scm_c_eval_string ("(display \"hello guile\n\")");
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"));
446 warn_if_using_invalid_config ();
448 /* enter main loop */
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
[])
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");
471 scm_boot_guile (argc
, argv
, main_prog
, 0);