Avoid GNUism '\|' by using extended REs.
[geda-gaf.git] / gnetlist-legacy / src / gnetlist.c
blobc537e73a1603f94811c2e5efd7f143fde03c6ef9
1 /* gEDA - GPL Electronic Design Automation
2 * gnetlist - gEDA Netlist
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
21 #include <config.h>
22 #include <locale.h>
23 #include <version.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 void gnetlist_quit(void)
49 s_clib_free();
50 s_slib_free();
51 s_rename_destroy_all();
52 /* o_text_freeallfonts(); */
54 /* Free GSList *backend_params */
55 g_slist_free (backend_params);
57 g_slist_free (input_files);
61 /* \brief Print a list of available backends.
62 * \par Function Description
63 * Prints a list of available gnetlist backends by searching for files
64 * in each of the directories in the current Guile %load-path. A file
65 * is considered to be a gnetlist backend if its basename begins with
66 * "gnet-" and ends with ".scm".
68 * \param pr_current Current #TOPLEVEL structure.
70 void
71 gnetlist_backends (TOPLEVEL *pr_current)
73 SCM s_load_path;
74 GList *backend_names = NULL, *iter = NULL;
76 /* Look up the current Guile %load-path */
77 s_load_path = scm_variable_ref (scm_c_lookup ("%load-path"));
79 for ( ; !scm_is_null (s_load_path); s_load_path = scm_cdr (s_load_path)) {
80 SCM s_dir_name = scm_car (s_load_path);
81 char *dir_name;
82 DIR *dptr;
83 struct dirent *dentry;
85 /* Get directory name from Scheme */
86 g_assert (scm_is_true (scm_list_p (s_load_path))); /* Sanity check */
87 g_assert (scm_is_string (scm_car (s_load_path))); /* Sanity check */
88 dir_name = scm_to_utf8_string (s_dir_name);
90 /* Open directory */
91 dptr = opendir (dir_name);
92 if (dptr == NULL) {
93 g_warning (_("Can't open directory %s: %s\n"),
94 dir_name, strerror (errno));
95 continue;
97 free (dir_name);
99 while (1) {
100 char *name;
102 dentry = readdir (dptr);
103 if (dentry == NULL) break;
105 /* Check that filename has the right format to be a gnetlist
106 * backend */
107 if (!(g_str_has_prefix (dentry->d_name, "gnet-")
108 && g_str_has_suffix (dentry->d_name, ".scm")))
109 continue;
111 /* Copy filename and remove prefix & suffix. Add to list of
112 * backend names. */
113 name = g_strdup (dentry->d_name + 5);
114 name[strlen(name)-4] = '\0';
115 backend_names = g_list_prepend (backend_names, name);
118 /* Close directory */
119 closedir (dptr);
122 /* Sort the list of backends */
123 backend_names = g_list_sort (backend_names, (GCompareFunc) strcmp);
125 printf (_("List of available backends: \n\n"));
127 for (iter = backend_names; iter != NULL; iter = g_list_next (iter)) {
128 printf ("%s\n", (char *) iter->data);
130 printf ("\n");
132 scm_remember_upto_here_1 (s_load_path);
136 void main_prog(void *closure, int argc, char *argv[])
138 int i;
139 int argv_index;
140 char *cwd;
141 gchar *str;
142 gchar *filename;
144 TOPLEVEL *pr_current;
146 /* set default output filename */
147 output_filename = g_strdup("output.net");
149 argv_index = parse_commandline(argc, argv);
150 cwd = g_get_current_dir();
152 scm_set_program_arguments (argc, argv, NULL);
154 /* this is a kludge to make sure that spice mode gets set */
155 /* Hacked by SDB to allow spice netlisters of arbitrary name
156 * as long as they begin with "spice". For example, this spice
157 * netlister is valid: "spice-sdb".
159 if (guile_proc) {
160 if (strncmp(guile_proc, "spice", 5) == 0) {
161 netlist_mode = SPICE;
165 libgeda_init();
167 /* create log file right away */
168 /* even if logging is enabled */
169 s_log_init ("gnetlist");
171 s_log_message(_(
172 "gEDA/gnetlist-legacy version %s%s.%s\n"
173 "gEDA/gnetlist-legacy comes with ABSOLUTELY NO WARRANTY; see COPYING for more details.\n"
174 "This is free software, and you are welcome to redistribute it under certain\n"
175 "conditions; please see the COPYING file for more details.\n\n"),
176 PREPEND_VERSION_STRING, PACKAGE_DOTTED_VERSION, PACKAGE_DATE_VERSION);
178 #if defined(__MINGW32__) && defined(DEBUG)
179 fprintf(stderr, _("This is the MINGW32 port.\n\n"));
180 #endif
182 /* register guile (scheme) functions */
183 g_register_funcs();
185 scm_dynwind_begin (0);
186 pr_current = s_toplevel_new ();
187 edascm_dynwind_toplevel (pr_current);
189 /* Evaluate Scheme expressions that need to be run before rc files
190 * are loaded. */
191 scm_eval (pre_rc_list, scm_current_module ());
193 g_rc_parse (pr_current, argv[0], "gnetlistrc", rc_filename);
194 /* immediately setup user params */
195 i_vars_set (pr_current);
197 s_rename_init();
199 if(list_backends) {
200 gnetlist_backends(pr_current);
201 exit (0);
204 /* Evaluate the first set of Scheme expressions before we load any
205 * schematic files */
206 scm_eval (pre_backend_list, scm_current_module ());
208 i = argv_index;
209 while (argv[i] != NULL) {
210 GError *err = NULL;
212 if (g_path_is_absolute(argv[i])) {
213 /* Path is already absolute so no need to do any concat of cwd */
214 filename = g_strdup (argv[i]);
215 } else {
216 filename = g_build_filename (cwd, argv[i], NULL);
219 if (!quiet_mode) {
220 s_log_message (_("Loading schematic [%s]\n"), filename);
221 fprintf (stderr, _("Loading schematic [%s]\n"), filename);
224 s_page_goto (pr_current, s_page_new (pr_current, filename));
226 if (!f_open (pr_current, pr_current->page_current, filename, &err)) {
227 g_warning ("%s\n", err->message);
228 fprintf (stderr, _("ERROR: Failed to load '%s': %s\n"),
229 filename, err->message);
230 g_error_free (err);
231 exit(2);
234 /* collect input filenames for backend use */
235 input_files = g_slist_append(input_files, argv[i]);
237 i++;
238 g_free (filename);
241 /* Change back to the directory where we started. This is done */
242 /* since gnetlist is a command line utility and will deposit its output */
243 /* in the current directory. Having the output go to a different */
244 /* directory will confuse the user (confused me, at first). */
245 if (chdir (cwd) == -1) {
246 fprintf (stderr,
247 _("ERROR: Failed to restore working directory to `%s': %s\n"),
248 cwd, g_strerror (errno));
249 exit (1);
251 /* free(cwd); - Defered; see below */
253 if (argv[argv_index] == NULL) {
254 fprintf (stderr, _(
255 "ERROR: No schematics files specified for processing.\n"
256 "\nRun `%s --help' for more information.\n"), argv[0]);
257 exit (1);
260 #if DEBUG
261 s_page_print_all(pr_current);
262 #endif
264 /* Load basic gnetlist functions */
265 scm_primitive_load_path (scm_from_utf8_string ("gnetlist.scm"));
267 if (guile_proc) {
268 SCM s_backend_path;
270 /* Search for backend scm file in load path */
271 str = g_strdup_printf("gnet-%s.scm", guile_proc);
272 s_backend_path = scm_sys_search_load_path (scm_from_locale_string (str));
273 g_free (str);
275 /* If it couldn't be found, fail. */
276 if (scm_is_false (s_backend_path)) {
277 fprintf (stderr, _(
278 "ERROR: Could not find backend `%s' in load path.\n"
279 "\nRun `%s --list-backends' for a full list of available backends.\n"),
280 guile_proc, argv[0]);
281 exit (1);
284 /* Load backend code. */
285 scm_primitive_load (s_backend_path);
287 /* Evaluate second set of Scheme expressions. */
288 scm_eval (post_backend_list, scm_current_module ());
291 s_traverse_init();
292 s_traverse_start(pr_current);
294 /* Change back to the directory where we started AGAIN. This is done */
295 /* because the s_traverse functions can change the Current Working Directory. */
296 if (chdir (cwd) == -1) {
297 fprintf (stderr,
298 _("ERROR: Failed to restore working directory to `%s': %s\n"),
299 cwd, g_strerror (errno));
300 exit (1);
302 g_free(cwd);
304 /* Run post-traverse code. */
305 scm_primitive_load_path (scm_from_utf8_string ("gnetlist-post.scm"));
307 if (interactive_mode) {
308 scm_c_eval_string ("(set-repl-prompt! \"gnetlist-legacy> \")");
309 scm_shell (0, NULL);
310 } else if (guile_proc) {
311 /* check size here hack */
312 str = g_strdup_printf ("(%s \"%s\")", guile_proc, output_filename);
313 scm_c_eval_string (str);
314 g_free (str);
315 /* gh_eval_str_with_stack_saving_handler (input_str); */
316 } else {
317 fprintf(stderr,
318 _("You gave neither backend to execute nor interactive mode!\n"));
321 gnetlist_quit();
323 scm_dynwind_end();
326 int main(int argc, char *argv[])
328 #if ENABLE_NLS
329 setlocale (LC_ALL, "");
330 setlocale (LC_NUMERIC, "C");
331 bindtextdomain ("geda-gnetlist-legacy", LOCALEDIR);
332 textdomain ("geda-gnetlist-legacy");
333 bind_textdomain_codeset("geda-gnetlist-legacy", "UTF-8");
334 #endif
335 scm_boot_guile (argc, argv, main_prog, 0);
336 return 0;