Fix o_net_consolidate_segments() to consolidate with all joined lines
[geda-gaf/pcjc2.git] / gnetlist / src / gnetlist.c
blob7135ce946b2960427196fdb25f6722bb6994e9f7
1 /* gEDA - GPL Electronic Design Automation
2 * gnetlist - gEDA Netlist
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2010 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
21 #include <config.h>
22 #include <version.h>
23 #include <missing.h>
25 #include <stdio.h>
26 #include <sys/param.h>
27 #include <sys/types.h>
28 #ifdef HAVE_ERRNO_H
29 #include <errno.h>
30 #endif
31 #include <dirent.h>
32 #ifdef HAVE_STRING_H
33 #include <string.h>
34 #endif
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
40 #include <libgeda/libgeda.h>
41 #include <libgeda/libgedaguile.h>
43 #include "../include/globals.h"
44 #include "../include/prototype.h"
45 #include "../include/gettext.h"
47 #ifdef HAVE_LIBDMALLOC
48 #include <dmalloc.h>
49 #endif
51 void gnetlist_quit(void)
53 s_clib_free();
54 s_slib_free();
55 s_rename_destroy_all();
56 /* o_text_freeallfonts(); */
58 /* Free GSList *backend_params */
59 g_slist_free (backend_params);
61 g_slist_free (input_files);
65 /* \brief Print a list of available backends.
66 * \par Function Description
67 * Prints a list of available gnetlist backends by searching for files
68 * in each of the directories in the current Guile %load-path. A file
69 * is considered to be a gnetlist backend if its basename begins with
70 * "gnet-" and ends with ".scm".
72 * \param pr_current Current #TOPLEVEL structure.
74 void
75 gnetlist_backends (TOPLEVEL *pr_current)
77 SCM s_load_path;
78 GList *backend_names = NULL, *iter = NULL;
80 /* Look up the current Guile %load-path */
81 s_load_path = scm_variable_ref (scm_c_lookup ("%load-path"));
83 for ( ; s_load_path != SCM_EOL; s_load_path = scm_cdr (s_load_path)) {
84 SCM s_dir_name = scm_car (s_load_path);
85 char *dir_name;
86 DIR *dptr;
87 struct dirent *dentry;
89 /* Get directory name from Scheme */
90 g_assert (scm_is_true (scm_list_p (s_load_path))); /* Sanity check */
91 g_assert (scm_is_string (scm_car (s_load_path))); /* Sanity check */
92 dir_name = scm_to_utf8_string (s_dir_name);
94 /* Open directory */
95 dptr = opendir (dir_name);
96 if (dptr == NULL) {
97 g_warning (_("Can't open directory %s: %s\n"),
98 dir_name, strerror (errno));
99 continue;
101 free (dir_name);
103 while (1) {
104 char *name;
106 dentry = readdir (dptr);
107 if (dentry == NULL) break;
109 /* Check that filename has the right format to be a gnetlist
110 * backend */
111 if (!(g_str_has_prefix (dentry->d_name, "gnet-")
112 && g_str_has_suffix (dentry->d_name, ".scm")))
113 continue;
115 /* Copy filename and remove prefix & suffix. Add to list of
116 * backend names. */
117 name = g_strdup (dentry->d_name + 5);
118 name[strlen(name)-4] = '\0';
119 backend_names = g_list_prepend (backend_names, name);
122 /* Close directory */
123 closedir (dptr);
126 /* Sort the list of backends */
127 backend_names = g_list_sort (backend_names, (GCompareFunc) strcmp);
129 printf (_("List of available backends: \n\n"));
131 for (iter = backend_names; iter != NULL; iter = g_list_next (iter)) {
132 printf ("%s\n", (char *) iter->data);
134 printf ("\n");
136 scm_remember_upto_here_1 (s_load_path);
140 void main_prog(void *closure, int argc, char *argv[])
142 int i;
143 int argv_index;
144 char *cwd;
145 gchar *str;
146 gchar *filename;
148 TOPLEVEL *pr_current;
150 /* set default output filename */
151 output_filename = g_strdup("output.net");
153 argv_index = parse_commandline(argc, argv);
154 cwd = g_get_current_dir();
156 scm_set_program_arguments (argc, argv, NULL);
158 /* this is a kludge to make sure that spice mode gets set */
159 /* Hacked by SDB to allow spice netlisters of arbitrary name
160 * as long as they begin with "spice". For example, this spice
161 * netlister is valid: "spice-sdb".
163 if (guile_proc) {
164 if (strncmp(guile_proc, "spice", 5) == 0) {
165 netlist_mode = SPICE;
169 libgeda_init();
171 /* create log file right away */
172 /* even if logging is enabled */
173 s_log_init ("gnetlist");
175 s_log_message(_(
176 "gEDA/gnetlist version %s%s.%s\n"
177 "gEDA/gnetlist comes with ABSOLUTELY NO WARRANTY; see COPYING for more details.\n"
178 "This is free software, and you are welcome to redistribute it under certain\n"
179 "conditions; please see the COPYING file for more details.\n\n"),
180 PREPEND_VERSION_STRING, PACKAGE_DOTTED_VERSION, PACKAGE_DATE_VERSION);
182 #if defined(__MINGW32__) && defined(DEBUG)
183 fprintf(stderr, _("This is the MINGW32 port.\n\n"));
184 #endif
186 /* register guile (scheme) functions */
187 g_register_funcs();
189 scm_dynwind_begin (0);
190 pr_current = s_toplevel_new ();
191 edascm_dynwind_toplevel (pr_current);
193 /* Evaluate Scheme expressions that need to be run before rc files
194 * are loaded. */
195 scm_eval (pre_rc_list, scm_current_module ());
197 g_rc_parse (pr_current, argv[0], "gnetlistrc", rc_filename);
198 /* immediately setup user params */
199 i_vars_init_gnetlist_defaults ();
200 i_vars_set (pr_current);
202 s_rename_init();
204 if(list_backends) {
205 gnetlist_backends(pr_current);
206 exit (0);
209 /* Evaluate the first set of Scheme expressions before we load any
210 * schematic files */
211 scm_eval (pre_backend_list, scm_current_module ());
213 i = argv_index;
214 while (argv[i] != NULL) {
215 GError *err = NULL;
217 if (g_path_is_absolute(argv[i])) {
218 /* Path is already absolute so no need to do any concat of cwd */
219 filename = g_strdup (argv[i]);
220 } else {
221 filename = g_build_filename (cwd, argv[i], NULL);
224 if (!quiet_mode) {
225 s_log_message (_("Loading schematic [%s]\n"), filename);
226 printf (_("Loading schematic [%s]\n"), filename);
229 s_page_goto (pr_current, s_page_new (pr_current, filename));
231 if (!f_open (pr_current, pr_current->page_current, filename, &err)) {
232 g_warning ("%s\n", err->message);
233 fprintf (stderr, _("ERROR: Failed to load '%s': %s\n"),
234 filename, err->message);
235 g_error_free (err);
236 exit(2);
239 /* collect input filenames for backend use */
240 input_files = g_slist_append(input_files, argv[i]);
242 i++;
243 g_free (filename);
246 /* Change back to the directory where we started. This is done */
247 /* since gnetlist is a command line utility and will deposit its output */
248 /* in the current directory. Having the output go to a different */
249 /* directory will confuse the user (confused me, at first). */
250 if (chdir (cwd)) {
251 /* Error occured with chdir */
252 #warning FIME: What do we do?
254 /* free(cwd); - Defered; see below */
256 if (argv[argv_index] == NULL) {
257 fprintf (stderr, _(
258 "ERROR: No schematics files specified for processing.\n"
259 "\nRun `%s --help' for more information.\n"), argv[0]);
260 exit (1);
263 #if DEBUG
264 s_page_print_all(pr_current);
265 #endif
267 /* Load basic gnetlist functions */
268 scm_primitive_load_path (scm_from_utf8_string ("gnetlist.scm"));
270 if (guile_proc) {
271 SCM s_backend_path;
273 /* Search for backend scm file in load path */
274 str = g_strdup_printf("gnet-%s.scm", guile_proc);
275 s_backend_path = scm_sys_search_load_path (scm_from_locale_string (str));
276 g_free (str);
278 /* If it couldn't be found, fail. */
279 if (scm_is_false (s_backend_path)) {
280 fprintf (stderr, _(
281 "ERROR: Could not find backend `%s' in load path.\n"
282 "\nRun `%s --list-backends' for a full list of available backends.\n"),
283 guile_proc, argv[0]);
284 exit (1);
287 /* Load backend code. */
288 scm_primitive_load (s_backend_path);
290 /* Evaluate second set of Scheme expressions. */
291 scm_eval (post_backend_list, scm_current_module ());
294 s_traverse_init();
295 s_traverse_start(pr_current);
297 /* Change back to the directory where we started AGAIN. This is done */
298 /* because the s_traverse functions can change the Current Working Directory. */
299 if (chdir (cwd)) {
300 /* Error occured with chdir */
301 #warning FIXME: What do we do?
303 g_free(cwd);
305 /* Run post-traverse code. */
306 scm_primitive_load_path (scm_from_utf8_string ("gnetlist-post.scm"));
308 if (interactive_mode) {
309 scm_c_eval_string ("(set-repl-prompt! \"gnetlist> \")");
310 scm_shell (0, NULL);
311 } else if (guile_proc) {
312 /* check size here hack */
313 str = g_strdup_printf ("(%s \"%s\")", guile_proc, output_filename);
314 scm_c_eval_string (str);
315 g_free (str);
316 /* gh_eval_str_with_stack_saving_handler (input_str); */
317 } else {
318 fprintf(stderr,
319 _("You gave neither backend to execute nor interactive mode!\n"));
322 gnetlist_quit();
324 scm_dynwind_end();
327 int main(int argc, char *argv[])
329 scm_boot_guile (argc, argv, main_prog, 0);
330 return 0;