gnetlist
|
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 }