/*! \todo Finish function documentation!!! * \brief * \par Function Description * */ void s_hierarchy_down_symbol (TOPLEVEL *toplevel, const CLibSymbol *symbol, PAGE *parent) { PAGE *page; gchar *filename; filename = s_clib_symbol_get_filename (symbol); page = s_page_search (toplevel, filename); if (page) { s_page_goto (toplevel, page); g_free (filename); return; } page = s_page_new (toplevel, filename); g_free(filename); s_page_goto (toplevel, page); f_open(toplevel, page, page->page_filename, NULL); page->up = parent->pid; page_control_counter++; page->page_control = page_control_counter; }
/*! \todo Finish function documentation!!! * \brief * \par Function Description * */ void s_hierarchy_down_symbol (TOPLEVEL *toplevel, const CLibSymbol *symbol, PAGE *parent) { PAGE *page; gchar *filename; filename = s_clib_symbol_get_filename (symbol); page = s_page_search (toplevel, filename); if (page) { /* change link to parent page since we * can come here from any parent and must * come back to the same page */ page->up = parent->pid; s_page_goto (toplevel, page); g_free (filename); return; } page = s_page_new (toplevel, filename); g_free(filename); s_page_goto (toplevel, page); f_open(toplevel, page, s_page_get_filename (page), NULL); page->up = parent->pid; page_control_counter++; page->page_control = page_control_counter; }
/*! \brief Asks for confirmation before closing a changed page. * \par Function Description * This function asks the user to confirm its closing order for * page <B>page</B> while it still has unsaved changes. * * It displays a message dialog inviting the user to cancel the * closing, or to discard the changes or to save the changes to a * file. * * \param [in] w_current The toplevel environment. * \param [in] page The page to close. * * \return TRUE if okay to continue with closing page, FALSE * otherwise. */ gboolean x_dialog_close_changed_page (GschemToplevel *w_current, PAGE *page) { GtkWidget *dialog; PAGE *keep_page; gboolean result = FALSE; g_return_val_if_fail (page != NULL && page->CHANGED, TRUE); keep_page = w_current->toplevel->page_current; dialog = GTK_WIDGET (g_object_new (TYPE_CLOSE_CONFIRMATION_DIALOG, "unsaved-page", page, NULL)); /* set default response signal. This is usually triggered by the "Return" key */ gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_YES); switch (gtk_dialog_run (GTK_DIALOG (dialog))) { case GTK_RESPONSE_NO: /* action selected: close without saving */ /* close the page, discard changes */ result = TRUE; break; case GTK_RESPONSE_YES: /* action selected: save */ s_page_goto (w_current->toplevel, page); gschem_toplevel_page_changed (w_current); i_callback_file_save(w_current, 0, NULL); /* has the page been really saved? */ if (!page->CHANGED) { result = TRUE; } /* no, user has cancelled the save and page has changes */ /* do not close page */ break; case GTK_RESPONSE_CANCEL: /* action selected: cancel */ /* fall through */ default: /* Hit when the user breaks out of the dialog with the escape key * or otherwise destroys the dialog window without a proper response */ /* nothing to do */ break; } gtk_widget_destroy (dialog); /* Switch back to the page we were on if it wasn't the one being closed */ g_return_val_if_fail (keep_page != NULL, result); if (keep_page != page) { s_page_goto (w_current->toplevel, keep_page); gschem_toplevel_page_changed (w_current); } return result; }
/*! \todo Finish function documentation!!! * \brief * \par Function Description * */ static void pagesel_callback_selection_changed (GtkTreeSelection *selection, gpointer user_data) { GtkTreeModel *model; GtkTreeIter iter; Pagesel *pagesel = (Pagesel*)user_data; GSCHEM_TOPLEVEL *w_current; PAGE *page; if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { return; } w_current = GSCHEM_DIALOG (pagesel)->w_current; gtk_tree_model_get (model, &iter, COLUMN_PAGE, &page, -1); /* temp */ s_page_goto (w_current->toplevel, page); i_set_filename (w_current, w_current->toplevel->page_current->page_filename); x_scrollbars_update (w_current); o_invalidate_all (w_current); /* We would like to use the following call, but since it calls * x_pagesel_update() it would cause an infinite loop. */ /* x_window_set_current_page (toplevel, page); */ }
/*! \brief Completes initialitation of the widget after realization. * \par Function Description * This function terminates the initialization of preview's GSCHEM_TOPLEVEL * and TOPLEVEL environments after the widget has been realized. * * It creates a preview page in the TOPLEVEL environment. * * \param [in] widget The preview widget. * \param [in] user_data Unused user data. */ static void preview_callback_realize (GtkWidget *widget, gpointer user_data) { Preview *preview = PREVIEW (widget); GSCHEM_TOPLEVEL *preview_w_current = preview->preview_w_current; TOPLEVEL *preview_toplevel = preview_w_current->toplevel; PAGE *preview_page; preview_w_current->window = preview_w_current->drawing_area->window; gtk_widget_grab_focus (preview_w_current->drawing_area); preview_toplevel->width = preview_w_current->drawing_area->allocation.width; preview_toplevel->height = preview_w_current->drawing_area->allocation.height; preview_w_current->win_width = preview_toplevel->width; preview_w_current->win_height = preview_toplevel->height; preview_w_current->drawable = preview_w_current->window; x_window_setup_gc (preview_w_current); preview_page = s_page_new (preview_toplevel, "unknown"); s_page_goto (preview_toplevel, preview_page); a_zoom_extents(preview_w_current, s_page_objects (preview_page), A_PAN_DONT_REDRAW); o_invalidate_all (preview_w_current); }
/*! \brief Updates the preview widget. * \par Function Description * This function update the preview: if the preview is active and a * filename has been given, it opens the file and display * it. Otherwise it display a blank page. * * \param [in] preview The preview widget. */ static void preview_update (Preview *preview) { GSCHEM_TOPLEVEL *preview_w_current = preview->preview_w_current; TOPLEVEL *preview_toplevel = preview_w_current->toplevel; int left, top, right, bottom; int width, height; if (preview_toplevel->page_current == NULL) { return; } /* delete old preview, create new page */ /* it would be better to just resets current page - Fix me */ s_page_delete (preview_toplevel, preview_toplevel->page_current); s_page_goto (preview_toplevel, s_page_new (preview_toplevel, "preview")); if (preview->active) { g_assert ((preview->filename == NULL) || (preview->buffer == NULL)); if (preview->filename != NULL) { /* open up file in current page */ f_open_flags (preview_toplevel, preview_toplevel->page_current, preview->filename, F_OPEN_RC | F_OPEN_RESTORE_CWD, NULL); /* test value returned by f_open... - Fix me */ /* we should display something if there an error occured - Fix me */ } if (preview->buffer != NULL) { /* Load the data buffer */ s_page_append_list (preview_toplevel, preview_toplevel->page_current, o_read_buffer (preview_toplevel, NULL, preview->buffer, -1, _("Preview Buffer"))); } } if (world_get_object_glist_bounds (preview_toplevel, s_page_objects (preview_toplevel->page_current), &left, &top, &right, &bottom)) { /* Clamp the canvas size to the extents of the page being previewed */ width = right - left; height = bottom - top; preview_toplevel->init_left = left - ((double)width * OVER_ZOOM_FACTOR); preview_toplevel->init_right = right + ((double)width * OVER_ZOOM_FACTOR); preview_toplevel->init_top = top - ((double)height * OVER_ZOOM_FACTOR); preview_toplevel->init_bottom = bottom + ((double)height * OVER_ZOOM_FACTOR); } /* display current page (possibly empty) */ a_zoom_extents (preview_w_current, s_page_objects (preview_toplevel->page_current), A_PAN_DONT_REDRAW); o_invalidate_all (preview_w_current); }
/*! \brief Saves a page to a file. * \par Function Description * This function saves the page <B>page</B> to a file named * <B>filename</B>. * * It returns the value returned by function <B>f_save()</B> trying * to save page <B>page</B> to file <B>filename</B> (1 on success, 0 * on failure). * * <B>page</B> may not be the current page of <B>toplevel</B>. The * current page of <B>toplevel</B> is not affected by this function. * * \param [in] toplevel The toplevel environment. * \param [in] page The page to save. * \param [in] filename The name of the file in which to save page. * \returns 1 on success, 0 otherwise. */ gint x_window_save_page (GSCHEM_TOPLEVEL *w_current, PAGE *page, const gchar *filename) { TOPLEVEL *toplevel = w_current->toplevel; PAGE *old_current; const gchar *log_msg, *state_msg; gint ret; g_return_val_if_fail (toplevel != NULL, 0); g_return_val_if_fail (page != NULL, 0); g_return_val_if_fail (filename != NULL, 0); /* save current page for restore after opening */ old_current = toplevel->page_current; /* change to page */ s_page_goto (toplevel, page); /* and try saving current page to filename */ ret = (gint)f_save (toplevel, filename); if (ret != 1) { /* an error occured when saving page to file */ log_msg = _("Could NOT save page [%s]\n"); state_msg = _("Error while trying to save"); } else { /* successful save of page to file, update page... */ /* change page name if necessary and prepare log message */ if (g_ascii_strcasecmp (page->page_filename, filename) != 0) { g_free (page->page_filename); page->page_filename = g_strdup (filename); log_msg = _("Saved as [%s]\n"); } else { log_msg = _("Saved [%s]\n"); } state_msg = _("Saved"); /* reset page CHANGED flag */ page->CHANGED = 0; /* update recent file list */ recent_files_add(filename); } /* log status of operation */ s_log_message (log_msg, filename); /* update display and page manager */ x_window_set_current_page (w_current, old_current); i_set_state_msg (w_current, SELECT, state_msg); i_update_toolbar (w_current); return ret; }
/*! \brief Saves all the pages of a TOPLEVEL object. * \par Function Description * Saves all the pages in the <B>toplevel</B> parameter. * * \param [in] toplevel The TOPLEVEL to save pages from. * \return The number of failed tries to save a page. */ gint s_page_save_all (TOPLEVEL *toplevel) { const GList *iter; PAGE *p_save, *p_current; gint status = 0; /* save current page */ p_save = toplevel->page_current; for ( iter = geda_list_get_glist( toplevel->pages ); iter != NULL; iter = g_list_next( iter ) ) { p_current = (PAGE *)iter->data; /* make p_current the current page of toplevel */ s_page_goto (toplevel, p_current); if (f_save (toplevel, p_current->page_filename)) { s_log_message (_("Saved [%s]\n"), toplevel->page_current->page_filename); /* reset the CHANGED flag of p_current */ p_current->CHANGED = 0; } else { s_log_message (_("Could NOT save [%s]\n"), toplevel->page_current->page_filename); /* increase the error counter */ status++; } } /* restore current page */ if (p_save != NULL) { s_page_goto (toplevel, p_save); } return status; }
/*! \brief Changes the current page. * \par Function Description * This function displays the specified page <B>page</B> in the * window attached to <B>toplevel</B>. * * It changes the <B>toplevel</B>'s current page to <B>page</B>, * draws it and updates the user interface. * * <B>page</B> has to be in the list of PAGEs attached to <B>toplevel</B>. * * \param [in] w_current The toplevel environment. * \param [in] page The page to become current page. */ void x_window_set_current_page (GSCHEM_TOPLEVEL *w_current, PAGE *page) { TOPLEVEL *toplevel = w_current->toplevel; g_return_if_fail (toplevel != NULL); g_return_if_fail (page != NULL); o_redraw_cleanstates (w_current); s_page_goto (toplevel, page); i_update_menus (w_current); i_set_filename (w_current, page->page_filename); x_pagesel_update (w_current); x_multiattrib_update (w_current); x_manual_resize (w_current); x_hscrollbar_update (w_current); x_vscrollbar_update (w_current); o_invalidate_all (w_current); }
/*! \brief Opens a new page from a file. * \par Function Description * This function opens the file whose name is <B>filename</B> in a * new PAGE of <B>toplevel</B>. * * If there is no page for <B>filename</B> in <B>toplevel</B>'s list * of pages, it creates a new PAGE, loads the file in it and returns * a pointer on the new page. Otherwise it returns a pointer on the * existing page. * * If the filename passed is NULL, this function creates an empty, * untitled page. The name of the untitled page is build from * configuration data ('untitled-name') and a counter for uniqueness. * * The opened page becomes the current page of <B>toplevel</B>. * * \param [in] w_current The toplevel environment. * \param [in] filename The name of the file to open or NULL for a blank page. * \returns A pointer on the new page. * * \bug This code should check to make sure any untitled filename * does not conflict with a file on disk. */ PAGE* x_window_open_page (GSCHEM_TOPLEVEL *w_current, const gchar *filename) { TOPLEVEL *toplevel = w_current->toplevel; PAGE *old_current, *page; gchar *fn; g_return_val_if_fail (toplevel != NULL, NULL); /* Generate untitled filename if none was specified */ if (filename == NULL) { gchar *cwd, *tmp; cwd = g_get_current_dir (); tmp = g_strdup_printf ("%s_%d.sch", toplevel->untitled_name, ++w_current->num_untitled); fn = g_build_filename (cwd, tmp, NULL); g_free(cwd); g_free(tmp); } else { fn = g_strdup (filename); } /* Return existing page if it is already loaded */ page = s_page_search (toplevel, fn); if ( page != NULL ) { g_free(fn); return page; } old_current = toplevel->page_current; page = s_page_new (toplevel, fn); s_page_goto (toplevel, page); /* Load from file if necessary, otherwise just print a message */ if (filename != NULL) { GError *err = NULL; if (!quiet_mode) s_log_message (_("Loading schematic [%s]\n"), fn); if (!f_open (toplevel, page, (gchar *) fn, &err)) { GtkWidget *dialog; g_warning ("%s\n", err->message); dialog = gtk_message_dialog_new (GTK_WINDOW (w_current->main_window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", err->message); gtk_window_set_title (GTK_WINDOW (dialog), _("Failed to load file")); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); g_error_free (err); } else { gtk_recent_manager_add_item (recent_manager, g_filename_to_uri(fn, NULL, NULL)); } } else { if (!quiet_mode) s_log_message (_("New file [%s]\n"), toplevel->page_current->page_filename); } if (scm_is_false (scm_hook_empty_p (new_page_hook))) scm_run_hook (new_page_hook, scm_cons (g_make_page_smob (toplevel, page), SCM_EOL)); a_zoom_extents (w_current, s_page_objects (toplevel->page_current), A_PAN_DONT_REDRAW); o_undo_savestate (w_current, UNDO_ALL); if ( old_current != NULL ) s_page_goto (toplevel, old_current); /* This line is generally un-needed, however if some code * wants to open a page, yet not bring it to the front, it is * needed needed to add it into the page manager. Otherwise, * it will get done in x_window_set_current_page(...) */ x_pagesel_update (w_current); /* ??? */ g_free (fn); return page; }
/*! \todo Finish function documentation!!! * \brief * \par Function Description * * \todo Only descends into the first source schematic * */ int o_edit_find_text (GSCHEM_TOPLEVEL *w_current, const GList *o_list, char *stext, int descend, int skip) { TOPLEVEL *toplevel = w_current->toplevel; char *attrib = NULL; int count = 0; PAGE *parent = NULL; char *current_filename = NULL; int page_control = 0; int pcount = 0; int rv; int x1, y1, x2, y2; int text_screen_height; const GList *iter; OBJECT *o_current; skiplast = skip; iter = o_list; while (iter != NULL) { o_current = (OBJECT *)iter->data; if (descend) { if (o_current->type == OBJ_COMPLEX) { parent = toplevel->page_current; attrib = o_attrib_search_attached_attribs_by_name (o_current, "source", count); /* if above is null, then look inside symbol */ if (attrib == NULL) { attrib = o_attrib_search_inherited_attribs_by_name (o_current, "source", count); /* looking_inside = TRUE; */ } if (attrib) { pcount = 0; current_filename = u_basic_breakup_string(attrib, ',', pcount); if (current_filename != NULL) { PAGE *child_page = s_hierarchy_down_schematic_single(toplevel, current_filename, parent, page_control, HIERARCHY_NORMAL_LOAD); if (child_page != NULL) { page_control = child_page->page_control; rv = o_edit_find_text (w_current, s_page_objects (child_page), stext, descend, skiplast); if (!rv) { s_page_goto( toplevel, child_page ); return 0; } } } } } } if (o_current->type == OBJ_TEXT) { const gchar *str = o_text_get_string (toplevel, o_current); /* replaced strcmp with strstr to simplify the search */ if (strstr (str,stext)) { if (!skiplast) { a_zoom(w_current, ZOOM_FULL, DONTCARE, A_PAN_DONT_REDRAW); world_get_single_object_bounds (toplevel, o_current, &x1, &y1, &x2, &y2); text_screen_height = SCREENabs (w_current, y2 - y1); /* this code will zoom/pan till the text screen height is about */ /* 50 pixels high, perhaps a future enhancement will be to make */ /* this number configurable */ while (text_screen_height < 50) { a_zoom(w_current, ZOOM_IN, DONTCARE, A_PAN_DONT_REDRAW); text_screen_height = SCREENabs (w_current, y2 - y1); } a_pan_general(w_current, o_current->text->x, o_current->text->y, 1, 0); /* Make sure the titlebar and scrollbars are up-to-date */ x_window_set_current_page(w_current, w_current->toplevel->page_current ); last_o = o_current; break; } if (last_o == o_current) { skiplast = 0; } } /* if (strstr(o_current->text->string,stext)) */ } /* if (o_current->type == OBJ_TEXT) */ iter = g_list_next (iter); if (iter == NULL) { return 1; } } return (iter == NULL); }
/*! \brief Do autosave on all pages that are marked. * \par Function Description * Looks for pages with the do_autosave_backup flag activated and * autosaves them. * * \param [in] w_current The GSCHEM_TOPLEVEL object to search for autosave's. */ void o_autosave_backups(GSCHEM_TOPLEVEL *w_current) { TOPLEVEL *toplevel = w_current->toplevel; GList *iter; PAGE *p_save, *p_current; gchar *backup_filename; gchar *real_filename; gchar *only_filename; gchar *dirname; mode_t saved_umask; mode_t mask; struct stat st; /* save current page */ p_save = toplevel->page_current; for ( iter = geda_list_get_glist( toplevel->pages ); iter != NULL; iter = g_list_next( iter ) ) { p_current = (PAGE *)iter->data; if (p_current->do_autosave_backup == 0) { continue; } if (p_current->ops_since_last_backup != 0) { /* make p_current the current page of toplevel */ s_page_goto (toplevel, p_current); /* Get the real filename and file permissions */ real_filename = follow_symlinks (p_current->page_filename, NULL); if (real_filename == NULL) { s_log_message (_("o_autosave_backups: Can't get the real filename of %s."), p_current->page_filename); } else { /* Get the directory in which the real filename lives */ dirname = g_path_get_dirname (real_filename); only_filename = g_path_get_basename(real_filename); backup_filename = g_strdup_printf("%s%c"AUTOSAVE_BACKUP_FILENAME_STRING, dirname, G_DIR_SEPARATOR, only_filename); /* If there is not an existing file with that name, compute the * permissions and uid/gid that we will use for the newly-created file. */ if (stat (real_filename, &st) != 0) { #if defined(HAVE_GETUID) && defined(HAVE_GETGID) struct stat dir_st; int result; #endif /* Use default permissions */ saved_umask = umask(0); st.st_mode = 0666 & ~saved_umask; umask(saved_umask); #if defined(HAVE_GETUID) && defined(HAVE_GETGID) st.st_uid = getuid (); result = stat (dirname, &dir_st); if (result == 0 && (dir_st.st_mode & S_ISGID)) st.st_gid = dir_st.st_gid; else st.st_gid = getgid (); #endif } g_free (dirname); g_free (only_filename); g_free (real_filename); /* Make the backup file writable before saving a new one */ if ( g_file_test (backup_filename, G_FILE_TEST_EXISTS) && (! g_file_test (backup_filename, G_FILE_TEST_IS_DIR))) { saved_umask = umask(0); if (chmod(backup_filename, (S_IWRITE|S_IWGRP|S_IWOTH) & ((~saved_umask) & 0777)) != 0) { s_log_message (_("Could NOT set previous backup file [%s] read-write\n"), backup_filename); } umask(saved_umask); } if (o_save (toplevel, s_page_objects (toplevel->page_current), backup_filename, NULL)) { p_current->ops_since_last_backup = 0; p_current->do_autosave_backup = 0; /* Make the backup file readonly so a 'rm *' command will ask the user before deleting it */ saved_umask = umask(0); mask = (S_IWRITE|S_IWGRP|S_IEXEC|S_IXGRP|S_IXOTH); mask = (~mask)&0777; mask &= ((~saved_umask) & 0777); if (chmod(backup_filename,mask) != 0) { s_log_message (_("Could NOT set backup file [%s] readonly\n"), backup_filename); } umask(saved_umask); } else { s_log_message (_("Could NOT save backup file [%s]\n"), backup_filename); } g_free (backup_filename); } } } /* restore current page */ s_page_goto (toplevel, p_save); }
void main_prog(void *closure, int argc, char *argv[]) { int i; int argv_index; char *cwd; gchar *str; gchar *filename; TOPLEVEL *pr_current; /* set default output filename */ output_filename = g_strdup("output.net"); argv_index = parse_commandline(argc, argv); cwd = g_get_current_dir(); scm_set_program_arguments (argc, argv, NULL); /* this is a kludge to make sure that spice mode gets set */ /* Hacked by SDB to allow spice netlisters of arbitrary name * as long as they begin with "spice". For example, this spice * netlister is valid: "spice-sdb". */ if (guile_proc) { if (strncmp(guile_proc, "spice", 5) == 0) { netlist_mode = SPICE; } } libgeda_init(); /* create log file right away */ /* even if logging is enabled */ s_log_init ("gnetlist"); s_log_message("gEDA/gnetlist version %s%s.%s\n", PREPEND_VERSION_STRING, PACKAGE_DOTTED_VERSION, PACKAGE_DATE_VERSION); s_log_message ("gEDA/gnetlist comes with ABSOLUTELY NO WARRANTY; see COPYING for more details.\n"); s_log_message ("This is free software, and you are welcome to redistribute it under certain\n"); s_log_message ("conditions; please see the COPYING file for more details.\n\n"); #if defined(__MINGW32__) && defined(DEBUG) fprintf(stderr, "This is the MINGW32 port.\n\n"); #endif /* register guile (scheme) functions */ g_register_funcs(); pr_current = s_toplevel_new (); /* Evaluate Scheme expressions that need to be run before rc files * are loaded. */ scm_eval (pre_rc_list, scm_current_module ()); g_rc_parse (pr_current, argv[0], "gnetlistrc", rc_filename); /* immediately setup user params */ i_vars_set (pr_current); s_rename_init(); if(list_backends) { gnetlist_backends(pr_current); exit (0); } /* Evaluate the first set of Scheme expressions before we load any * schematic files */ scm_eval (pre_backend_list, scm_current_module ()); i = argv_index; while (argv[i] != NULL) { GError *err = NULL; if (g_path_is_absolute(argv[i])) { /* Path is already absolute so no need to do any concat of cwd */ filename = g_strdup (argv[i]); } else { filename = g_build_filename (cwd, argv[i], NULL); } if (!quiet_mode) { s_log_message ("Loading schematic [%s]\n", filename); printf ("Loading schematic [%s]\n", filename); } s_page_goto (pr_current, s_page_new (pr_current, filename)); if (!f_open (pr_current, pr_current->page_current, filename, &err)) { g_warning ("%s\n", err->message); fprintf (stderr, "%s\n", err->message); g_error_free (err); } /* collect input filenames for backend use */ input_files = g_slist_append(input_files, argv[i]); i++; g_free (filename); } /* Change back to the directory where we started. This is done */ /* since gnetlist is a command line utility and will deposit its output */ /* in the current directory. Having the output go to a different */ /* directory will confuse the user (confused me, at first). */ if (chdir (cwd)) { /* Error occured with chdir */ #warning FIME: What do we do? } /* free(cwd); - Defered; see below */ if (argv[argv_index] == NULL) { fprintf (stderr, "ERROR: No schematics files specified for processing.\n"); fprintf (stderr, "\nRun `%s --help' for more information.\n", argv[0]); exit (1); } g_set_project_current(pr_current); #if DEBUG s_page_print_all(pr_current); #endif /* Load basic gnetlist functions */ scm_primitive_load_path (scm_from_utf8_string ("gnetlist.scm")); if (guile_proc) { SCM s_backend_path; /* Search for backend scm file in load path */ str = g_strdup_printf("gnet-%s.scm", guile_proc); s_backend_path = scm_sys_search_load_path (scm_from_locale_string (str)); g_free (str); /* If it couldn't be found, fail. */ if (scm_is_false (s_backend_path)) { fprintf (stderr, "ERROR: Could not find backend `%s' in load path.\n", guile_proc); fprintf (stderr, "\nRun `%s --list-backends' for a full list of available backends.\n", argv[0]); exit (1); } /* Load backend code. */ scm_primitive_load (s_backend_path); /* Evaluate second set of Scheme expressions. */ scm_eval (post_backend_list, scm_current_module ()); } s_traverse_init(); s_traverse_start(pr_current); /* Change back to the directory where we started AGAIN. This is done */ /* because the s_traverse functions can change the Current Working Directory. */ if (chdir (cwd)) { /* Error occured with chdir */ #warning FIXME: What do we do? } g_free(cwd); /* Run post-traverse code. */ scm_primitive_load_path (scm_from_utf8_string ("gnetlist-post.scm")); if (guile_proc) { /* check size here hack */ str = g_strdup_printf ("(%s \"%s\")", guile_proc, output_filename); scm_c_eval_string (str); g_free (str); /* gh_eval_str_with_stack_saving_handler (input_str); */ } else if (interactive_mode) { scm_c_eval_string ("(set-repl-prompt! \"gnetlist> \")"); scm_shell (0, NULL); } else { fprintf(stderr, "You gave neither backend to execute nor interactive mode!\n"); } gnetlist_quit(); }
/*! \todo Finish function documentation!!! * \brief Search for schematic associated source files and load them. * \par Function Description * This function searches the associated source file refered by the * <B>filename</B> and loads it. If the <B>flag</B> is set to * <B>HIERARCHY_NORMAL_LOAD</B> and the page is allready in the list of * pages it will return the <B>pid</B> of that page. * If the <B>flag</B> is set to <B>HIERARCHY_FORCE_LOAD</B> then this * function will load the page again with a new page id. The second case * is mainly used by gnetlist where pushed down schematics MUST be unique. * * \param [in] toplevel The TOPLEVEL object. * \param [in] filename Schematic file name. * \param [in] parent The parent page of the schematic. * \param [in] page_control * \param [in] flag * \return The page loaded, or NULL if failed. * * \note * This function goes and finds the associated source files and * loads all up * It only works for schematic files though * this is basically push * flag can either be HIERARCHY_NORMAL_LOAD or HIERARCHY_FORCE_LOAD * flag is mainly used by gnetlist where pushed down schematics MUST be unique */ PAGE * s_hierarchy_down_schematic_single(TOPLEVEL *toplevel, const gchar *filename, PAGE *parent, int page_control, int flag) { gchar *string; PAGE *found = NULL; PAGE *forbear; g_return_val_if_fail ((toplevel != NULL), NULL); g_return_val_if_fail ((filename != NULL), NULL); g_return_val_if_fail ((parent != NULL), NULL); string = s_slib_search_single(filename); if (string == NULL) { return NULL; } switch (flag) { case HIERARCHY_NORMAL_LOAD: { gchar *filename = f_normalize_filename (string, NULL); found = s_page_search (toplevel, filename); g_free (filename); if (found) { /* check whether this page is in the parents list */ for (forbear = parent; forbear != NULL && found->pid != forbear->pid && forbear->up >= 0; forbear = s_page_search_by_page_id (toplevel->pages, forbear->up)) ; /* void */ if (found->pid == forbear->pid) { s_log_message(_("hierarchy loop detected while visiting page:\n" " \"%s\"\n"), found->page_filename); return NULL; /* error signal */ } s_page_goto (toplevel, found); if (page_control != 0) { found->page_control = page_control; } found->up = parent->pid; g_free (string); return found; } found = s_page_new (toplevel, string); f_open (toplevel, found, found->page_filename, NULL); } break; case HIERARCHY_FORCE_LOAD: { found = s_page_new (toplevel, string); f_open (toplevel, found, found->page_filename, NULL); } break; } if (page_control == 0) { page_control_counter++; found->page_control = page_control_counter; } else { found->page_control = page_control; } found->up = parent->pid; g_free (string); return found; }
/*! \brief Asks for confirmation before closing a window. * \par Function Description * This function asks the user to confirm its closing order for * the given window. * * The user is given the possibility to save the pages that currently * have unsaved changes, if any. * * It returns TRUE if the user really accepts the close of the * window. Otherwise the user has somehow cancelled and the window * must not be closed. * * \param [in] w_current The toplevel environment. * \returns TRUE if the window can be closed, FALSE otherwise. */ gboolean x_dialog_close_window (GschemToplevel *w_current) { TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current); GList *iter; GtkWidget *dialog; PAGE *p_current; PAGE *keep_page; GList *unsaved_pages, *p_unsaved; gboolean ret = FALSE; keep_page = toplevel->page_current; for ( iter = geda_list_get_glist( toplevel->pages ), unsaved_pages = NULL; iter != NULL; iter = g_list_next( iter ) ) { p_current = (PAGE*)iter->data; if (p_current->CHANGED) { unsaved_pages = g_list_append (unsaved_pages, (gpointer)p_current); } } if (unsaved_pages == NULL) { /* no page with unsaved changes, close window */ return TRUE; } dialog = GTK_WIDGET (g_object_new (TYPE_CLOSE_CONFIRMATION_DIALOG, "unsaved-pages", unsaved_pages, NULL)); gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (w_current->main_window)); g_list_free (unsaved_pages); switch (gtk_dialog_run (GTK_DIALOG (dialog))) { case GTK_RESPONSE_NO: /* action selected: close without saving */ /* discard changes, ok to close window */ ret = TRUE; break; case GTK_RESPONSE_YES: /* action selected: save */ g_object_get (dialog, "selected-pages", &unsaved_pages, NULL); for (p_unsaved = unsaved_pages, ret = TRUE; p_unsaved != NULL; p_unsaved = g_list_next (p_unsaved)) { p_current = (PAGE*)p_unsaved->data; s_page_goto (toplevel, p_current); gschem_toplevel_page_changed (w_current); i_callback_file_save(w_current, 0, NULL); /* if user cancelled previous, do not close window */ ret &= !p_current->CHANGED; } g_list_free (unsaved_pages); break; case GTK_RESPONSE_CANCEL: /* action selected: cancel */ /* fall through */ default: /* Hit when the user breaks out of the dialog with the escape key * or otherwise destroys the dialog window without a proper response */ ret = FALSE; break; } gtk_widget_destroy (dialog); /* Switch back to the page we were on */ g_return_val_if_fail (keep_page != NULL, ret); s_page_goto (toplevel, keep_page); gschem_toplevel_page_changed (w_current); return ret; }
/*! \brief delete a page and it's contents * \par Function Description * Deletes a single page <B>page</B> from <B>toplevel</B>'s list of pages. * * See #s_page_delete_list() to delete all pages of a <B>toplevel</B> * * If the current page of toplevel is given as parameter <B>page</B>, * the function sets the field <B>page_current</B> of the TOPLEVEL * struct to NULL. */ void s_page_delete (TOPLEVEL *toplevel, PAGE *page) { PAGE *tmp; gchar *backup_filename; gchar *real_filename; /* We need to temporarily make the page being deleted current because * various functions called below (some indirectly) assume they are * deleting objects from the current page. * * These functions are known to include: * s_delete_object () */ /* save page_current and switch to page */ if (page == toplevel->page_current) { tmp = NULL; } else { tmp = toplevel->page_current; s_page_goto (toplevel, page); } /* Get the real filename and file permissions */ real_filename = follow_symlinks (page->page_filename, NULL); if (real_filename == NULL) { s_log_message (_("s_page_delete: Can't get the real filename of %s."), page->page_filename); } else { backup_filename = f_get_autosave_filename (real_filename); /* Delete the backup file */ if ( (g_file_test (backup_filename, G_FILE_TEST_EXISTS)) && (!g_file_test(backup_filename, G_FILE_TEST_IS_DIR)) ) { if (unlink(backup_filename) != 0) { s_log_message(_("s_page_delete: Unable to delete backup file %s."), backup_filename); } } g_free (backup_filename); } g_free(real_filename); /* Free the selection object */ g_object_unref( page->selection_list ); /* then delete objects of page */ s_page_delete_objects (toplevel, page); /* Free the objects in the place list. */ s_delete_object_glist (toplevel, page->place_list); page->place_list = NULL; /* This removes all objects from the list of connectible objects * of the given \a page. */ if (g_list_length (page->connectible_list) != 0) { fprintf (stderr, "OOPS! page->connectible_list had something in it when it was freed!\n"); fprintf (stderr, "Length: %d\n", g_list_length (page->connectible_list)); } g_list_free (page->connectible_list); page->connectible_list = NULL; /* free current page undo structs */ s_undo_free_all (toplevel, page); /* ouch, deal with parents going away and the children still around */ page->up = -2; g_free (page->page_filename); geda_list_remove( toplevel->pages, page ); s_weakref_notify (page, page->weak_refs); g_free (page); /* restore page_current */ if (tmp != NULL) { s_page_goto (toplevel, tmp); } else { /* page was page_current */ s_toplevel_set_page_current (toplevel, NULL); /* page_current must be updated by calling function */ } }
void main_prog(void *closure, int argc, char *argv[]) { int i; int argv_index; int exit_status; char *cwd; TOPLEVEL *pr_current; argv_index = parse_commandline(argc, argv); cwd = g_get_current_dir(); libgeda_init(); /* create log file right away */ /* even if logging is enabled */ x_log_update_func = s_log_update; s_log_init ("symcheck"); logging_dest=STDOUT_TTY; #if defined(__MINGW32__) && defined(DEBUG) fprintf(stderr, "This is the MINGW32 port.\n"); #endif logging_dest=-1; /* don't output to the screen for now */ /* register guile (scheme) functions */ g_register_funcs(); pr_current = s_toplevel_new (); g_rc_parse (pr_current, argv[0], "gsymcheckrc", rc_filename); i_vars_set(pr_current); i = argv_index; while (argv[i] != NULL) { gchar *filename; GError *err = NULL; if (g_path_is_absolute(argv[i])) { /* Path is already absolute so no need to do any concat of cwd */ filename = g_strdup (argv[i]); } else { filename = g_build_filename (cwd, argv[i], NULL); } s_page_goto (pr_current, s_page_new (pr_current, filename)); if (!f_open (pr_current, pr_current->page_current, s_page_get_filename (pr_current->page_current), &err)) { /* Not being able to load a file is apparently a fatal error */ logging_dest = STDOUT_TTY; g_warning ("%s\n", err->message); g_error_free (err); exit(2); } else { g_message (_("Loaded file [%1$s]\n"), filename); } i++; g_free (filename); } if (argv[argv_index] == NULL) { fprintf(stderr, _("\nERROR! You must specify at least one filename\n\n")); usage(argv[0]); } g_free(cwd); logging_dest=STDOUT_TTY; #if DEBUG s_page_print_all(pr_current); #endif if (!quiet_mode) s_log_message("\n"); exit_status = s_check_all(pr_current); s_page_delete_list(pr_current); gsymcheck_quit(); exit(exit_status); }
/*! \brief Saves a page to a file. * \par Function Description * This function saves the page <B>page</B> to a file named * <B>filename</B>. * * It returns the value returned by function <B>f_save()</B> trying * to save page <B>page</B> to file <B>filename</B> (1 on success, 0 * on failure). * * <B>page</B> may not be the current page of <B>toplevel</B>. The * current page of <B>toplevel</B> is not affected by this function. * * \param [in] w_current The toplevel environment. * \param [in] page The page to save. * \param [in] filename The name of the file in which to save page. * \returns 1 on success, 0 otherwise. */ gint x_window_save_page (GSCHEM_TOPLEVEL *w_current, PAGE *page, const gchar *filename) { TOPLEVEL *toplevel = w_current->toplevel; PAGE *old_current; const gchar *log_msg, *state_msg; gint ret; GError *err = NULL; g_return_val_if_fail (toplevel != NULL, 0); g_return_val_if_fail (page != NULL, 0); g_return_val_if_fail (filename != NULL, 0); /* save current page for restore after opening */ old_current = toplevel->page_current; /* change to page */ s_page_goto (toplevel, page); /* and try saving current page to filename */ ret = (gint)f_save (toplevel, toplevel->page_current, filename, &err); if (ret != 1) { log_msg = _("Could NOT save page [%s]\n"); state_msg = _("Error while trying to save"); GtkWidget *dialog; dialog = gtk_message_dialog_new (GTK_WINDOW (w_current->main_window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", err->message); gtk_window_set_title (GTK_WINDOW (dialog), _("Failed to save file")); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); g_clear_error (&err); } else { /* successful save of page to file, update page... */ /* change page name if necessary and prepare log message */ if (g_ascii_strcasecmp (page->page_filename, filename) != 0) { g_free (page->page_filename); page->page_filename = g_strdup (filename); log_msg = _("Saved as [%s]\n"); } else { log_msg = _("Saved [%s]\n"); } state_msg = _("Saved"); /* reset page CHANGED flag */ page->CHANGED = 0; /* add to recent file list */ gtk_recent_manager_add_item (recent_manager, g_filename_to_uri(filename, NULL, NULL)); } /* log status of operation */ s_log_message (log_msg, filename); /* update display and page manager */ x_window_set_current_page (w_current, old_current); i_set_state_msg (w_current, SELECT, state_msg); i_update_toolbar (w_current); return ret; }
/*! \brief delete a page and it's contents * \par Function Description * Deletes a single page <B>page</B> from <B>toplevel</B>'s list of pages. * * See #s_page_delete_list() to delete all pages of a <B>toplevel</B> * * If the current page of toplevel is given as parameter <B>page</B>, * the function sets the field <B>page_current</B> of the TOPLEVEL * struct to NULL. */ void s_page_delete (TOPLEVEL *toplevel, PAGE *page) { PAGE *tmp; gchar *backup_filename; gchar *real_filename; /* We need to temporarily make the page being deleted current because * various functions called below (some indirectly) assume they are * deleting objects from the current page. * * These functions are known to include: * s_delete_object () */ /* save page_current and switch to page */ if (page == toplevel->page_current) { tmp = NULL; } else { tmp = toplevel->page_current; s_page_goto (toplevel, page); } /* Get the real filename and file permissions */ real_filename = follow_symlinks (page->page_filename, NULL); if (real_filename == NULL) { s_log_message (_("s_page_delete: Can't get the real filename of %s."), page->page_filename); } else { backup_filename = f_get_autosave_filename (real_filename); /* Delete the backup file */ if ( (g_file_test (backup_filename, G_FILE_TEST_EXISTS)) && (!g_file_test(backup_filename, G_FILE_TEST_IS_DIR)) ) { if (unlink(backup_filename) != 0) { s_log_message(_("s_page_delete: Unable to delete backup file %s."), backup_filename); } } g_free (backup_filename); } g_free(real_filename); /* Free the selection object */ g_object_unref( page->selection_list ); /* then delete objects of page */ s_page_delete_objects (toplevel, page); /* Free the objects in the place list. */ s_delete_object_glist (toplevel, page->place_list); page->place_list = NULL; #if DEBUG printf("Freeing page: %s\n", page->page_filename); s_tile_print(toplevel); #endif s_tile_free_all (page); s_stretch_destroy_all (page->stretch_list); /* free current page undo structs */ s_undo_free_all (toplevel, page); /* ouch, deal with parents going away and the children still around */ page->up = -2; g_free (page->page_filename); geda_list_remove( toplevel->pages, page ); #if DEBUG s_tile_print (toplevel); #endif g_free (page); /* restore page_current */ if (tmp != NULL) { s_page_goto (toplevel, tmp); } else { /* page was page_current */ toplevel->page_current = NULL; /* page_current must be updated by calling function */ } }
void s_hierarchy_traverse(TOPLEVEL * pr_current, OBJECT * o_current, NETLIST * netlist) { char *attrib; int page_control=-1; PAGE *p_current; PAGE *child_page; int count = 0; int pcount = 0; int looking_inside = FALSE; int loaded_flag = FALSE; char *current_filename; int graphical=FALSE; attrib = o_attrib_search_attached_attribs_by_name (o_current, "source", 0); /* if above is null, then look inside symbol */ if (attrib == NULL) { attrib = o_attrib_search_inherited_attribs_by_name (o_current, "source", count); looking_inside = TRUE; #if DEBUG printf("going to look inside now\n"); #endif } graphical = s_hierarchy_graphical_search(o_current, count); if (graphical) { /* Do not bother traversing the hierarchy if the symbol has an */ /* graphical attribute attached to it. */ if (attrib) { g_free(attrib); attrib = NULL; } } while (attrib) { /* look for source=filename,filename, ... */ pcount = 0; current_filename = u_basic_breakup_string(attrib, ',', pcount); /* loop over all filenames */ while (current_filename != NULL) { s_log_message(_("Going to traverse source [%1$s]"), current_filename); /* guts here */ /* guts for a single filename */ p_current = pr_current->page_current; #if DEBUG printf("Going down %s\n", current_filename); #endif GError *err = NULL; child_page = s_hierarchy_down_schematic_single(pr_current, current_filename, pr_current->page_current, page_control, HIERARCHY_FORCE_LOAD, &err); if (child_page == NULL) { g_warning (_("Failed to load subcircuit '%1$s': %2$s\n"), current_filename, err->message); fprintf(stderr, _("ERROR: Failed to load subcircuit '%1$s': %2$s\n"), current_filename, err->message); g_error_free (err); exit (2); } else { page_control = child_page->page_control; s_page_goto (pr_current, child_page); loaded_flag = TRUE; verbose_print("v\n"); verbose_reset_index(); netlist->composite_component = TRUE; /* can't do the following, don't know why... HACK TODO */ /*netlist->hierarchy_tag = u_basic_strdup (netlist->component_uref);*/ s_traverse_sheet (pr_current, s_page_objects (pr_current->page_current), netlist->component_uref); verbose_print("^"); } pr_current->page_current = p_current; g_free(current_filename); pcount++; current_filename = u_basic_breakup_string(attrib, ',', pcount); } g_free(attrib); g_free(current_filename); count++; /* continue looking outside first */ if (!looking_inside) { attrib = o_attrib_search_attached_attribs_by_name (o_current, "source", count); } /* okay we were looking outside and didn't */ /* find anything, so now we need to look */ /* inside the symbol */ if (!looking_inside && attrib == NULL && !loaded_flag) { looking_inside = TRUE; #if DEBUG printf("switching to go to look inside\n"); #endif } if (looking_inside) { #if DEBUG printf("looking inside\n"); #endif attrib = o_attrib_search_inherited_attribs_by_name (o_current, "source", count); } graphical = s_hierarchy_graphical_search(o_current, count); if (graphical) { /* Do not bother looking further in the hierarchy if the symbol */ /* has an graphical attribute attached to it. */ if (attrib) { g_free(attrib); attrib = NULL; } } } }
/*! \brief Handles all the options of the autonumber text dialog * \par Function Description * This function is the master of all autonumber code. It receives the options of * the the autonumber text dialog in an <B>AUTONUMBER_TEXT</B> structure. * First it collects all pages of a hierarchical schematic. * Second it gets all matching text elements for the searchtext. * Then it renumbers all text elements of all schematic pages. The renumbering * follows the rules of the parameters given in the autonumber text dialog. */ void autonumber_text_autonumber(AUTONUMBER_TEXT *autotext) { GList *pages; GList *searchtext_list=NULL; GList *text_item, *obj_item, *page_item; OBJECT *o_current; GschemToplevel *w_current; gchar *searchtext; gchar *scope_text; gchar *new_searchtext; gint i, number, slot; GList *o_list = NULL; const GList *iter; w_current = autotext->w_current; autotext->current_searchtext = NULL; autotext->root_page = 1; autotext->used_numbers = NULL; autotext->free_slots = NULL; autotext->used_slots = NULL; scope_text = g_list_first(autotext->scope_text)->data; /* Step1: get all pages of the hierarchy */ pages = s_hierarchy_traversepages (w_current->toplevel, w_current->toplevel->page_current, HIERARCHY_NODUPS); /* g_list_foreach(pages, (GFunc) s_hierarchy_print_page, NULL); */ /* Step2: if searchtext has an asterisk at the end we have to find all matching searchtextes. Example: "refdes=*" will match each text that starts with "refdes=" and has a trailing "?" or a trailing number if the "all"-option is set. We get a list of possible prefixes: refdes=R, refdes=C. If there is only one search pattern, it becomes a single item in the searchtext list */ if (strlen(scope_text) == 0) { s_log_message(_("No searchstring given in autonumber text.\n")); return; /* error */ } else if (g_str_has_suffix(scope_text,"?") == TRUE) { /* single searchtext, strip of the "?" */ searchtext = g_strndup(scope_text, strlen(scope_text)-1); searchtext_list=g_list_append (searchtext_list, searchtext); } else if (g_str_has_suffix(scope_text,"*") == TRUE) { /* strip of the "*" */ searchtext = g_strndup(scope_text, strlen(scope_text)-1); /* collect all the possible searchtexts in all pages of the hierarchy */ for (page_item = pages; page_item != NULL; page_item = g_list_next(page_item)) { s_page_goto(w_current->toplevel, page_item->data); gschem_toplevel_page_changed (w_current); /* iterate over all objects an look for matching searchtext's */ for (iter = s_page_objects (w_current->toplevel->page_current); iter != NULL; iter = g_list_next (iter)) { o_current = iter->data; if (o_current->type == OBJ_TEXT) { if (autotext->scope_number == SCOPE_HIERARCHY || autotext->scope_number == SCOPE_PAGE || ((autotext->scope_number == SCOPE_SELECTED) && (o_current->selected))) { const gchar *str = o_text_get_string (w_current->toplevel, o_current); if (g_str_has_prefix (str, searchtext)) { /* the beginnig of the current text matches with the searchtext now */ /* strip of the trailing [0-9?] chars and add it too the searchtext */ for (i = strlen (str)-1; (i >= strlen(searchtext)) && (str[i] == '?' || isdigit( (int) (str[i]) )); i--) ; /* void */ new_searchtext = g_strndup (str, i+1); if (g_list_find_custom(searchtext_list, new_searchtext, (GCompareFunc) strcmp) == NULL ) { searchtext_list = g_list_append(searchtext_list, new_searchtext); } else { g_free(new_searchtext); } } } } } if (autotext->scope_number == SCOPE_SELECTED || autotext->scope_number == SCOPE_PAGE) break; /* search only in the first page */ } g_free(searchtext); } else { s_log_message(_("No '*' or '?' given at the end of the autonumber text.\n")); return; } /* Step3: iterate over the search items in the list */ for (text_item=searchtext_list; text_item !=NULL; text_item=g_list_next(text_item)) { autotext->current_searchtext = text_item->data; /* printf("autonumber_text_autonumber: searchtext %s\n", autotext->current_searchtext); */ /* decide whether to renumber page by page or get a global used-list */ if (autotext->scope_skip == SCOPE_HIERARCHY) { /* whole hierarchy database */ /* renumbering all means that no db is required */ if (!(autotext->scope_number == SCOPE_HIERARCHY && autotext->scope_overwrite)) { for (page_item = pages; page_item != NULL; page_item = g_list_next(page_item)) { autotext->root_page = (pages->data == page_item->data); s_page_goto(w_current->toplevel, page_item->data); gschem_toplevel_page_changed (w_current); autonumber_get_used(w_current, autotext); } } } /* renumber the elements */ for (page_item = pages; page_item != NULL; page_item = g_list_next(page_item)) { s_page_goto(w_current->toplevel, page_item->data); gschem_toplevel_page_changed (w_current); autotext->root_page = (pages->data == page_item->data); /* build a page database if we're numbering pagebypage or selection only*/ if (autotext->scope_skip == SCOPE_PAGE || autotext->scope_skip == SCOPE_SELECTED) { autonumber_get_used(w_current, autotext); } /* RENUMBER CODE FOR ONE PAGE AND ONE SEARCHTEXT*/ /* 1. get objects to renumber */ for (iter = s_page_objects (w_current->toplevel->page_current); iter != NULL; iter = g_list_next (iter)) { o_current = iter->data; if (autonumber_match(autotext, o_current, &number) == AUTONUMBER_RENUMBER) { /* put number into the used list */ o_list = g_list_append(o_list, o_current); } } /* 2. sort object list */ switch (autotext->order) { case AUTONUMBER_SORT_YX: o_list=g_list_sort(o_list, autonumber_sort_yx); break; case AUTONUMBER_SORT_YX_REV: o_list=g_list_sort(o_list, autonumber_sort_yx_rev); break; case AUTONUMBER_SORT_XY: o_list=g_list_sort(o_list, autonumber_sort_xy); break; case AUTONUMBER_SORT_XY_REV: o_list=g_list_sort(o_list, autonumber_sort_xy_rev); break; case AUTONUMBER_SORT_DIAGONAL: o_list=g_list_sort(o_list, autonumber_sort_diagonal); break; default: ; /* unsorted file order */ } /* 3. renumber/reslot the objects */ for(obj_item=o_list; obj_item != NULL; obj_item=g_list_next(obj_item)) { o_current= obj_item->data; if(autotext->removenum) { autonumber_remove_number(autotext, o_current); } else { /* get valid numbers from the database */ autonumber_get_new_numbers(autotext, o_current, &number, &slot); /* and apply it. TODO: join these two functions */ autonumber_apply_new_text(autotext, o_current, number, slot); } } g_list_free(o_list); o_list = NULL; /* destroy the page database */ if (autotext->scope_skip == SCOPE_PAGE || autotext->scope_skip == SCOPE_SELECTED) autonumber_clear_database(autotext); if (autotext->scope_number == SCOPE_SELECTED || autotext->scope_number == SCOPE_PAGE) break; /* only renumber the parent page (the first page) */ } autonumber_clear_database(autotext); /* cleanup */ } /* cleanup and redraw all*/ g_list_foreach(searchtext_list, (GFunc) g_free, NULL); g_list_free(searchtext_list); s_page_goto(w_current->toplevel, pages->data); /* go back to the root page */ gschem_toplevel_page_changed (w_current); gschem_page_view_invalidate_all (gschem_toplevel_get_current_page_view (w_current)); g_list_free(pages); o_undo_savestate_old(w_current, UNDO_ALL); }
/*! * \brief Search for schematic associated source files and load them. * \par Function Description * This function searches the associated source file refered by the * <B>filename</B> and loads it. If the <B>flag</B> is set to * <B>HIERARCHY_NORMAL_LOAD</B> and the page is already in the list of * pages it will return the <B>pid</B> of that page. * If the <B>flag</B> is set to <B>HIERARCHY_FORCE_LOAD</B> then this * function will load the page again with a new page id. The second case * is mainly used by gnetlist where pushed down schematics MUST be unique. * * \param [in] toplevel The TOPLEVEL object. * \param [in] filename Schematic file name. * \param [in] parent The parent page of the schematic. * \param [in] page_control * \param [in] flag sets whether to force load * \param [out] err Location to return a GError on failure. * \return The page loaded, or NULL if failed. * * \note * This function finds the associated source files and * loads all up * It only works for schematic files though * this is basically push * flag can either be HIERARCHY_NORMAL_LOAD or HIERARCHY_FORCE_LOAD * flag is mainly used by gnetlist where pushed down schematics MUST be unique */ PAGE * s_hierarchy_down_schematic_single(TOPLEVEL *toplevel, const gchar *filename, PAGE *parent, int page_control, int flag, GError **err) { gchar *string; PAGE *found = NULL; PAGE *forbear; g_return_val_if_fail ((toplevel != NULL), NULL); g_return_val_if_fail ((filename != NULL), NULL); g_return_val_if_fail ((parent != NULL), NULL); SCM string_s = scm_call_1 (scm_c_public_ref ("geda library", "get-source-library-file"), scm_from_utf8_string (filename)); if (scm_is_false (string_s)) { g_set_error (err, EDA_ERROR, EDA_ERROR_NOLIB, _("Schematic not found in source library.")); return NULL; } string = scm_to_utf8_string (string_s); switch (flag) { case HIERARCHY_NORMAL_LOAD: { gchar *filename = f_normalize_filename (string, NULL); found = s_page_search (toplevel, filename); g_free (filename); if (found) { /* check whether this page is in the parents list */ for (forbear = parent; forbear != NULL && found->pid != forbear->pid && forbear->up >= 0; forbear = s_page_search_by_page_id (toplevel->pages, forbear->up)) ; /* void */ if (forbear != NULL && found->pid == forbear->pid) { g_set_error (err, EDA_ERROR, EDA_ERROR_LOOP, _("Hierarchy contains a circular dependency.")); return NULL; /* error signal */ } s_page_goto (toplevel, found); if (page_control != 0) { found->page_control = page_control; } found->up = parent->pid; g_free (string); return found; } found = s_page_new (toplevel, string); f_open (toplevel, found, s_page_get_filename (found), NULL); } break; case HIERARCHY_FORCE_LOAD: { found = s_page_new (toplevel, string); f_open (toplevel, found, s_page_get_filename (found), NULL); } break; default: g_return_val_if_reached (NULL); } if (page_control == 0) { page_control_counter++; found->page_control = page_control_counter; } else { found->page_control = page_control; } found->up = parent->pid; g_free (string); return found; }
/*! \todo Finish function documentation!!! * \brief * \par Function Description * * <B>type</B> can be one of the following values: * <DL> * <DT>*</DT><DD>UNDO_ACTION * <DT>*</DT><DD>REDO_ACTION * </DL> */ void o_undo_callback(GSCHEM_TOPLEVEL *w_current, int type) { TOPLEVEL *toplevel = w_current->toplevel; UNDO *u_current; UNDO *u_next; UNDO *save_bottom; UNDO *save_tos; UNDO *save_current; int save_logging; int find_prev_data=FALSE; char *save_filename; if (w_current->undo_control == FALSE) { s_log_message(_("Undo/Redo disabled in rc file\n")); return; } if (toplevel->page_current->undo_current == NULL) { return; } if (type == UNDO_ACTION) { u_current = toplevel->page_current->undo_current->prev; } else { u_current = toplevel->page_current->undo_current->next; } u_next = toplevel->page_current->undo_current; if (u_current == NULL) { return; } if (u_next->type == UNDO_ALL && u_current->type == UNDO_VIEWPORT_ONLY) { #if DEBUG printf("Type: %d\n", u_current->type); printf("Current is an undo all, next is viewport only!\n"); #endif find_prev_data = TRUE; if (w_current->undo_type == UNDO_DISK) { u_current->filename = o_undo_find_prev_filename(u_current); } else { u_current->object_list = o_undo_find_prev_object_head (u_current); } } /* save filename */ save_filename = g_strdup (toplevel->page_current->page_filename); /* save structure so it's not nuked */ save_bottom = toplevel->page_current->undo_bottom; save_tos = toplevel->page_current->undo_tos; save_current = toplevel->page_current->undo_current; toplevel->page_current->undo_bottom = NULL; toplevel->page_current->undo_tos = NULL; toplevel->page_current->undo_current = NULL; if (w_current->undo_type == UNDO_DISK && u_current->filename) { PAGE *p_new; s_page_delete (toplevel, toplevel->page_current); p_new = s_page_new(toplevel, u_current->filename); s_page_goto (toplevel, p_new); } else if (w_current->undo_type == UNDO_MEMORY && u_current->object_list) { PAGE *p_new; s_page_delete (toplevel, toplevel->page_current); p_new = s_page_new (toplevel, save_filename); s_page_goto (toplevel, p_new); } /* temporarily disable logging */ save_logging = do_logging; do_logging = FALSE; if (w_current->undo_type == UNDO_DISK && u_current->filename) { f_open(toplevel, toplevel->page_current, u_current->filename, NULL); x_manual_resize(w_current); toplevel->page_current->page_control = u_current->page_control; toplevel->page_current->up = u_current->up; toplevel->page_current->CHANGED=1; } else if (w_current->undo_type == UNDO_MEMORY && u_current->object_list) { s_page_delete_objects (toplevel, toplevel->page_current); s_page_append_list (toplevel, toplevel->page_current, o_glist_copy_all (toplevel, u_current->object_list, NULL)); x_manual_resize(w_current); toplevel->page_current->page_control = u_current->page_control; toplevel->page_current->up = u_current->up; toplevel->page_current->CHANGED=1; } /* do misc setups */ set_window(toplevel, toplevel->page_current, u_current->left, u_current->right, u_current->top, u_current->bottom); x_hscrollbar_update(w_current); x_vscrollbar_update(w_current); /* restore logging */ do_logging = save_logging; /* set filename right */ g_free(toplevel->page_current->page_filename); toplevel->page_current->page_filename = save_filename; /* final redraw */ x_pagesel_update (w_current); x_multiattrib_update (w_current); /* Let the caller to decide if redraw or not */ o_invalidate_all (w_current); i_update_menus(w_current); /* restore saved undo structures */ toplevel->page_current->undo_bottom = save_bottom; toplevel->page_current->undo_tos = save_tos; toplevel->page_current->undo_current = save_current; if (type == UNDO_ACTION) { if (toplevel->page_current->undo_current) { toplevel->page_current->undo_current = toplevel->page_current->undo_current->prev; if (toplevel->page_current->undo_current == NULL) { toplevel->page_current->undo_current = toplevel->page_current->undo_bottom; } } } else { /* type is REDO_ACTION */ if (toplevel->page_current->undo_current) { toplevel->page_current->undo_current = toplevel->page_current->undo_current->next; if (toplevel->page_current->undo_current == NULL) { toplevel->page_current->undo_current = toplevel->page_current->undo_tos; } } } /* don't have to free data here since filename, object_list are */ /* just pointers to the real data (lower in the stack) */ if (find_prev_data) { u_current->filename = NULL; u_current->object_list = NULL; } #if DEBUG printf("\n\n---Undo----\n"); s_undo_print_all(toplevel->page_current->undo_bottom); printf("TOS: %s\n", toplevel->page_current->undo_tos->filename); printf("CURRENT: %s\n", toplevel->page_current->undo_current->filename); printf("----\n"); #endif }
/*! \brief Opens a new page from a file. * \par Function Description * This function opens the file whose name is <B>filename</B> in a * new PAGE of <B>toplevel</B>. * * If there is no page for <B>filename</B> in <B>toplevel</B>'s list * of pages, it creates a new PAGE, loads the file in it and returns * a pointer on the new page. Otherwise it returns a pointer on the * existing page. * * If the filename passed is NULL, this function creates an empty, * untitled page. The name of the untitled page is build from * configuration data ('untitled-name') and a counter for uniqueness. * * The opened page becomes the current page of <B>toplevel</B>. * * \param [in] w_current The toplevel environment. * \param [in] filename The name of the file to open or NULL for a blank page. * \returns A pointer on the new page. * * \bug This code should check to make sure any untitled filename * does not conflict with a file on disk. */ PAGE* x_window_open_page (GschemToplevel *w_current, const gchar *filename) { TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current); GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current); PAGE *page; gchar *fn; g_return_val_if_fail (toplevel != NULL, NULL); /* Generate untitled filename if none was specified */ if (filename == NULL) { gchar *cwd, *tmp, *untitled_name; EdaConfig *cfg; cwd = g_get_current_dir (); cfg = eda_config_get_context_for_path (cwd); untitled_name = eda_config_get_string (cfg, "gschem", "default-filename", NULL); tmp = g_strdup_printf ("%s_%d.sch", untitled_name, ++w_current->num_untitled); fn = g_build_filename (cwd, tmp, NULL); g_free (untitled_name); g_free(cwd); g_free(tmp); } else { fn = g_strdup (filename); } /* Return existing page if it is already loaded */ page = s_page_search (toplevel, fn); if ( page != NULL ) { g_free(fn); return page; } page = s_page_new (toplevel, fn); s_page_goto (toplevel, page); gschem_toplevel_page_changed (w_current); /* Load from file if necessary, otherwise just print a message */ if (filename != NULL) { GError *err = NULL; if (!quiet_mode) s_log_message (_("Loading schematic [%s]\n"), fn); if (!f_open (toplevel, page, (gchar *) fn, &err)) { GtkWidget *dialog; g_warning ("%s\n", err->message); dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (w_current->main_window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("<b>An error occurred while loading the requested file.</b>\n\nLoading from '%s' failed: %s. The gschem log may contain more information."), fn, err->message); gtk_window_set_title (GTK_WINDOW (dialog), _("Failed to load file")); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); g_error_free (err); } else { gtk_recent_manager_add_item (recent_manager, g_filename_to_uri(fn, NULL, NULL)); } } else { if (!quiet_mode) s_log_message (_("New file [%s]\n"), toplevel->page_current->page_filename); g_run_hook_page (w_current, "%new-page-hook", toplevel->page_current); } gschem_page_view_set_page (page_view, toplevel->page_current); o_undo_savestate (w_current, toplevel->page_current, UNDO_ALL); /* This line is generally un-needed, however if some code * wants to open a page, yet not bring it to the front, it is * needed needed to add it into the page manager. Otherwise, * it will get done in x_window_set_current_page(...) */ x_pagesel_update (w_current); /* ??? */ g_free (fn); return page; }
void main_prog(void *closure, int argc, char *argv[]) { int i; int argv_index; int exit_status; char *cwd; char *logfile; TOPLEVEL *pr_current; argv_index = parse_commandline(argc, argv); cwd = g_get_current_dir(); libgeda_init(); /* create log file right away */ /* even if logging is enabled */ logfile = g_build_filename (cwd, "gsymcheck.log", NULL); x_log_update_func = s_log_update; s_log_init (logfile); g_free (logfile); logging_dest=STDOUT_TTY; if (!quiet_mode) { s_log_message( "gEDA/gsymcheck version %s%s.%s\n", PREPEND_VERSION_STRING, DOTTED_VERSION, DATE_VERSION); s_log_message( "gEDA/symcheck comes with ABSOLUTELY NO WARRANTY; see COPYING for more details.\n"); s_log_message( "This is free software, and you are welcome to redistribute it under certain\n"); s_log_message( "conditions; please see the COPYING file for more details.\n\n"); } #ifdef __MINGW32__ fprintf(stderr, "This is the MINGW32 port.\n"); #endif logging_dest=-1; /* don't output to the screen for now */ /* register guile (scheme) functions */ g_register_funcs(); pr_current = s_toplevel_new (); g_rc_parse(pr_current, "gsymcheckrc", rc_filename); i_vars_set(pr_current); i = argv_index; while (argv[i] != NULL) { gchar *filename; GError *err = NULL; if (g_path_is_absolute(argv[i])) { /* Path is already absolute so no need to do any concat of cwd */ filename = g_strdup (argv[i]); } else { filename = g_build_filename (cwd, argv[i], NULL); } s_page_goto (pr_current, s_page_new (pr_current, filename)); if (!f_open (pr_current, pr_current->page_current->page_filename, &err)) { /* Not being able to load a file is apparently a fatal error */ logging_dest = STDOUT_TTY; g_warning ("%s\n", err->message); g_error_free (err); exit(2); } else { g_message ("Loaded file [%s]\n", filename); } i++; g_free (filename); } if (argv[argv_index] == NULL) { fprintf(stderr, "\nERROR! You must specify at least one filename\n\n"); usage(argv[0]); } g_free(cwd); logging_dest=STDOUT_TTY; #if DEBUG s_page_print_all(pr_current); #endif if (!quiet_mode) s_log_message("\n"); exit_status = s_check_all(pr_current); s_page_delete_list(pr_current); gsymcheck_quit(); exit(exit_status); }