gnetlist

gnetlist.c

Go to the documentation of this file.
00001 /* gEDA - GPL Electronic Design Automation
00002  * gnetlist - gEDA Netlist
00003  * Copyright (C) 1998-2010 Ales Hvezda
00004  * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00019  */
00020 
00021 #include <config.h>
00022 #include <version.h>
00023 #include <missing.h>
00024 
00025 #include <stdio.h>
00026 #include <sys/param.h>
00027 #include <sys/types.h>
00028 #ifdef HAVE_ERRNO_H
00029 #include <errno.h>
00030 #endif
00031 #include <dirent.h>
00032 #ifdef HAVE_STRING_H
00033 #include <string.h>
00034 #endif
00035 #ifdef HAVE_UNISTD_H
00036 #include <unistd.h>
00037 #endif
00038 
00039 
00040 #include <libgeda/libgeda.h>
00041 #include <libgeda/libgedaguile.h>
00042 
00043 #include "../include/globals.h"
00044 #include "../include/prototype.h"
00045 
00046 #ifdef HAVE_LIBDMALLOC
00047 #include <dmalloc.h>
00048 #endif
00049 
00050 void gnetlist_quit(void)
00051 {
00052     s_clib_free();
00053     s_slib_free();
00054     s_rename_destroy_all();
00055     /* o_text_freeallfonts(); */
00056 
00057     /* Free GSList *backend_params */
00058     g_slist_free (backend_params);
00059 
00060     g_slist_free (input_files);
00061 }
00062 
00063 
00064 /* \brief Print a list of available backends.
00065  * \par Function Description
00066  * Prints a list of available gnetlist backends by searching for files
00067  * in each of the directories in the current Guile %load-path.  A file
00068  * is considered to be a gnetlist backend if its basename begins with
00069  * "gnet-" and ends with ".scm".
00070  *
00071  * \param pr_current  Current #TOPLEVEL structure.
00072  */
00073 void
00074 gnetlist_backends (TOPLEVEL *pr_current)
00075 {
00076   SCM s_load_path;
00077   GList *backend_names = NULL, *iter = NULL;
00078 
00079   /* Look up the current Guile %load-path */
00080   s_load_path = scm_variable_ref (scm_c_lookup ("%load-path"));
00081 
00082   for ( ; s_load_path != SCM_EOL; s_load_path = scm_cdr (s_load_path)) {
00083     SCM s_dir_name = scm_car (s_load_path);
00084     char *dir_name;
00085     DIR *dptr;
00086     struct dirent *dentry;
00087 
00088     /* Get directory name from Scheme */
00089     g_assert (scm_is_true (scm_list_p (s_load_path))); /* Sanity check */
00090     g_assert (scm_is_string (scm_car (s_load_path))); /* Sanity check */
00091     dir_name = scm_to_utf8_string (s_dir_name);
00092 
00093     /* Open directory */
00094     dptr = opendir (dir_name);
00095     if (dptr == NULL) {
00096       g_warning ("Can't open directory %s: %s\n",
00097                  dir_name, strerror (errno));
00098       continue;
00099     }
00100     free (dir_name);
00101 
00102     while (1) {
00103       char *name;
00104 
00105       dentry = readdir (dptr);
00106       if (dentry == NULL) break;
00107 
00108       /* Check that filename has the right format to be a gnetlist
00109        * backend */
00110       if (!(g_str_has_prefix (dentry->d_name, "gnet-")
00111             && g_str_has_suffix (dentry->d_name, ".scm")))
00112         continue;
00113 
00114       /* Copy filename and remove prefix & suffix.  Add to list of
00115        * backend names. */
00116       name = g_strdup (dentry->d_name + 5);
00117       name[strlen(name)-4] = '\0';
00118       backend_names = g_list_prepend (backend_names, name);
00119     }
00120 
00121     /* Close directory */
00122     closedir (dptr);
00123   }
00124 
00125   /* Sort the list of backends */
00126   backend_names = g_list_sort (backend_names, (GCompareFunc) strcmp);
00127 
00128   printf ("List of available backends: \n\n");
00129 
00130   for (iter = backend_names; iter != NULL; iter = g_list_next (iter)) {
00131     printf ("%s\n", (char *) iter->data);
00132   }
00133   printf ("\n");
00134 
00135   scm_remember_upto_here_1 (s_load_path);
00136 }
00137 
00138 
00139 void main_prog(void *closure, int argc, char *argv[])
00140 {
00141     int i;
00142     int argv_index;
00143     char *cwd;
00144     gchar *str;
00145     gchar *filename;
00146 
00147     TOPLEVEL *pr_current;
00148 
00149     /* set default output filename */
00150     output_filename = g_strdup("output.net");
00151 
00152     argv_index = parse_commandline(argc, argv);
00153     cwd = g_get_current_dir();
00154 
00155     scm_set_program_arguments (argc, argv, NULL);
00156 
00157     /* this is a kludge to make sure that spice mode gets set */
00158     /*  Hacked by SDB to allow spice netlisters of arbitrary name
00159      *        as long as they begin with "spice".  For example, this spice
00160      *  netlister is valid: "spice-sdb".
00161      */
00162     if (guile_proc) {
00163         if (strncmp(guile_proc, "spice", 5) == 0) {
00164             netlist_mode = SPICE;
00165         }
00166     }
00167 
00168     libgeda_init();
00169 
00170     /* create log file right away */
00171     /* even if logging is enabled */
00172     s_log_init ("gnetlist");
00173 
00174     s_log_message("gEDA/gnetlist version %s%s.%s\n", PREPEND_VERSION_STRING,
00175                   PACKAGE_DOTTED_VERSION, PACKAGE_DATE_VERSION);
00176     s_log_message
00177         ("gEDA/gnetlist comes with ABSOLUTELY NO WARRANTY; see COPYING for more details.\n");
00178     s_log_message
00179         ("This is free software, and you are welcome to redistribute it under certain\n");
00180     s_log_message
00181         ("conditions; please see the COPYING file for more details.\n\n");
00182 
00183 #if defined(__MINGW32__) && defined(DEBUG)
00184     fprintf(stderr, "This is the MINGW32 port.\n\n");
00185 #endif
00186 
00187     /* register guile (scheme) functions */
00188     g_register_funcs();
00189 
00190     scm_dynwind_begin (0);
00191     pr_current = s_toplevel_new ();
00192     edascm_dynwind_toplevel (pr_current);
00193 
00194     /* Evaluate Scheme expressions that need to be run before rc files
00195      * are loaded. */
00196     scm_eval (pre_rc_list, scm_current_module ());
00197 
00198     g_rc_parse (pr_current, argv[0], "gnetlistrc", rc_filename);
00199     /* immediately setup user params */
00200     i_vars_set (pr_current);
00201 
00202     s_rename_init();
00203 
00204     if(list_backends) {
00205       gnetlist_backends(pr_current);
00206       exit (0);
00207     }
00208 
00209     /* Evaluate the first set of Scheme expressions before we load any
00210      * schematic files */
00211     scm_eval (pre_backend_list, scm_current_module ());
00212 
00213     i = argv_index;
00214     while (argv[i] != NULL) {
00215       GError *err = NULL;
00216 
00217       if (g_path_is_absolute(argv[i])) {
00218         /* Path is already absolute so no need to do any concat of cwd */
00219         filename = g_strdup (argv[i]);
00220       } else {
00221         filename = g_build_filename (cwd, argv[i], NULL);
00222       }
00223 
00224       if (!quiet_mode) {
00225         s_log_message ("Loading schematic [%s]\n", filename);
00226         printf ("Loading schematic [%s]\n", filename);
00227       }
00228 
00229       s_page_goto (pr_current, s_page_new (pr_current, filename));
00230 
00231       if (!f_open (pr_current, pr_current->page_current, filename, &err)) {
00232         g_warning ("%s\n", err->message);
00233         fprintf (stderr, "ERROR: Failed to load '%s': %s\n",
00234                  filename, err->message);
00235         g_error_free (err);
00236     exit(2);
00237       }
00238 
00239       /* collect input filenames for backend use */
00240       input_files = g_slist_append(input_files, argv[i]);
00241 
00242       i++;
00243       g_free (filename);
00244     }
00245 
00246     /* Change back to the directory where we started.  This is done */
00247     /* since gnetlist is a command line utility and will deposit its output */
00248     /* in the current directory.  Having the output go to a different */
00249     /* directory will confuse the user (confused me, at first). */
00250     if (chdir (cwd)) {
00251       /* Error occured with chdir */
00252 #warning FIME: What do we do?
00253     }
00254     /* free(cwd); - Defered; see below */
00255 
00256     if (argv[argv_index] == NULL) {
00257         fprintf (stderr, "ERROR: No schematics files specified for processing.\n");
00258         fprintf (stderr, "\nRun `%s --help' for more information.\n", argv[0]);
00259         exit (1);
00260     }
00261 
00262 #if DEBUG
00263     s_page_print_all(pr_current);
00264 #endif
00265 
00266     /* Load basic gnetlist functions */
00267     scm_primitive_load_path (scm_from_utf8_string ("gnetlist.scm"));
00268 
00269     if (guile_proc) {
00270       SCM s_backend_path;
00271 
00272       /* Search for backend scm file in load path */
00273       str = g_strdup_printf("gnet-%s.scm", guile_proc);
00274       s_backend_path = scm_sys_search_load_path (scm_from_locale_string (str));
00275       g_free (str);
00276 
00277       /* If it couldn't be found, fail. */
00278       if (scm_is_false (s_backend_path)) {
00279         fprintf (stderr, "ERROR: Could not find backend `%s' in load path.\n",
00280                  guile_proc);
00281         fprintf (stderr,
00282                  "\nRun `%s --list-backends' for a full list of available backends.\n",
00283                  argv[0]);
00284         exit (1);
00285       }
00286 
00287       /* Load backend code. */
00288       scm_primitive_load (s_backend_path);
00289 
00290       /* Evaluate second set of Scheme expressions. */
00291       scm_eval (post_backend_list, scm_current_module ());
00292     }
00293 
00294     s_traverse_init();
00295     s_traverse_start(pr_current);
00296 
00297     /* Change back to the directory where we started AGAIN.  This is done */
00298     /* because the s_traverse functions can change the Current Working Directory. */
00299     if (chdir (cwd)) {
00300       /* Error occured with chdir */
00301 #warning FIXME: What do we do?
00302     }
00303     g_free(cwd);
00304 
00305     /* Run post-traverse code. */
00306     scm_primitive_load_path (scm_from_utf8_string ("gnetlist-post.scm"));
00307 
00308     if (guile_proc) {
00309         /* check size here hack */
00310         str = g_strdup_printf ("(%s \"%s\")", guile_proc, output_filename);
00311         scm_c_eval_string (str);
00312         g_free (str);
00313         /* gh_eval_str_with_stack_saving_handler (input_str); */
00314     } else if (interactive_mode) {
00315         scm_c_eval_string ("(set-repl-prompt! \"gnetlist> \")");
00316         scm_shell (0, NULL);
00317     } else {
00318         fprintf(stderr,
00319                 "You gave neither backend to execute nor interactive mode!\n");
00320     }
00321 
00322     gnetlist_quit();
00323 
00324     scm_dynwind_end();
00325 }
00326 
00327 int main(int argc, char *argv[])
00328 {
00329     /* disable the deprecated warnings in guile 1.6.3 */
00330     /* Eventually the warnings will need to be fixed */
00331     if(getenv("GUILE_WARN_DEPRECATED")==NULL)
00332       putenv("GUILE_WARN_DEPRECATED=no");
00333 
00334     scm_boot_guile (argc, argv, main_prog, 0);
00335     return 0;
00336 }
 All Data Structures Files Functions Variables Defines