/*! \brief Load a subpage * * \par Function Description * Implements s_hierarchy_down_schematic(), but without changing variables * related to the UI. * * - Ensures a duplicate page is not loaded * - Does not change the current page * - Does not modify the most recent "up" page * * \param [in] page * \param [in] filename * \param [out] error * \return A pointer to the subpage or NULL if an error occured. */ PAGE* s_hierarchy_load_subpage (PAGE *page, const char *filename, GError **error) { char *string; PAGE *subpage = NULL; g_return_val_if_fail (filename != NULL, NULL); g_return_val_if_fail (page != 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 (error, EDA_ERROR, EDA_ERROR_NOLIB, _("Schematic not found in source library.")); } else { string = scm_to_utf8_string (string_s); gchar *normalized = f_normalize_filename (string, error); subpage = s_page_search (page->toplevel, normalized); if (subpage == NULL) { int success; subpage = s_page_new (page->toplevel, string); success = f_open (page->toplevel, subpage, s_page_get_filename (subpage), error); if (success) { subpage->page_control = ++page_control_counter; } else { s_page_delete (page->toplevel, subpage); subpage = NULL; } } g_free (normalized); } return subpage; }
/*! \brief Load a subpage * * \par Function Description * Implements s_hierarchy_down_schematic(), but without changing variables * related to the UI. * * - Ensures a duplicate page is not loaded * - Does not change the current page * - Does not modify the most recent "up" page * * \param [in] page * \param [in] filename * \param [out] error * \return A pointer to the subpage or NULL if an error occured. */ PAGE* s_hierarchy_load_subpage (PAGE *page, const char *filename, GError **error) { char *string; PAGE *subpage = NULL; g_return_val_if_fail (filename != NULL, NULL); g_return_val_if_fail (page != NULL, NULL); string = s_slib_search_single (filename); if (string == NULL) { g_set_error (error, EDA_ERROR, EDA_ERROR_NOLIB, _("Schematic not found in source library.")); } else { gchar *normalized = f_normalize_filename (string, error); subpage = s_page_search (page->toplevel, normalized); if (subpage == NULL) { int success; subpage = s_page_new (page->toplevel, string); success = f_open (page->toplevel, subpage, subpage->page_filename, error); if (success) { subpage->page_control = ++page_control_counter; } else { s_page_delete (page->toplevel, subpage); subpage = NULL; } } g_free (normalized); } return subpage; }
/*! \brief Load a configuration file. * \par Function Description * Load the configuration file \a rcfile, reporting errors via \a err. * * \param toplevel The current #TOPLEVEL structure. * \param rcfile The filename of the configuration file to load. * \param err Return location for errors, or NULL; * \return TRUE on success, FALSE on failure. */ gboolean g_rc_parse_file (TOPLEVEL *toplevel, const gchar *rcfile, GError **err) { gchar *name_norm = NULL; GError *tmp_err = NULL; g_return_val_if_fail ((toplevel != NULL), FALSE); g_return_val_if_fail ((rcfile != NULL), FALSE); /* Normalise filename */ name_norm = f_normalize_filename (rcfile, &tmp_err); if (name_norm == NULL) goto parse_file_error; /* Attempt to load the rc file, if it hasn't been loaded already. * If g_rc_try_mark_read() succeeds, it stores name_norm in * toplevel, so we *don't* free it. */ if (g_rc_try_mark_read (toplevel, name_norm, &tmp_err) && g_read_file (toplevel, name_norm, &tmp_err)) { s_log_message (_("Parsed config from [%s]\n"), name_norm); return TRUE; } parse_file_error: /* Copy tmp_err into err, with a prefixed message. */ /*! \todo We should upgrade to GLib >= 2.16 and use * g_propagate_prefixed_error(). */ if (err == NULL) { g_error_free (tmp_err); } else { gchar *orig_msg = tmp_err->message; tmp_err->message = g_strdup_printf (_("Unable to parse config from [%s]: %s"), (name_norm != NULL) ? name_norm : rcfile, orig_msg); g_free (orig_msg); *err = tmp_err; } g_free (name_norm); return FALSE; }
/*! * \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; }
/*! \brief Opens the schematic file with fine-grained control over behaviour. * \par Function Description * Opens the schematic file and carries out a number of actions * depending on the \a flags set. If #F_OPEN_RC is set, executes * configuration files found in the target directory. If * #F_OPEN_CHECK_BACKUP is set, warns user if a backup is found for * the file being loaded, and possibly prompts user for whether to * load the backup instead. If #F_OPEN_RESTORE_CWD is set, does not * change the working directory to that of the file being loaded. * * \param [in,out] toplevel The TOPLEVEL object to load the schematic into. * \param [in] filename A character string containing the file name * to open. * \param [in] flags Combination of #FOpenFlags values. * \param [in,out] err #GError structure for error reporting, or * NULL to disable error reporting * * \return 0 on failure, 1 on success. */ int f_open_flags(TOPLEVEL *toplevel, PAGE *page, const gchar *filename, const gint flags, GError **err) { int opened=FALSE; char *full_filename = NULL; char *full_rcfilename = NULL; char *file_directory = NULL; char *saved_cwd = NULL; char *backup_filename = NULL; char load_backup_file = 0; GError *tmp_err = NULL; /* has the head been freed yet? */ /* probably not hack PAGE */ set_window(toplevel, page, toplevel->init_left, toplevel->init_right, toplevel->init_top, toplevel->init_bottom); /* Cache the cwd so we can restore it later. */ if (flags & F_OPEN_RESTORE_CWD) { saved_cwd = g_get_current_dir(); } /* get full, absolute path to file */ full_filename = f_normalize_filename (filename, &tmp_err); if (full_filename == NULL) { g_set_error (err, G_FILE_ERROR, tmp_err->code, _("Cannot find file %s: %s"), filename, tmp_err->message); g_error_free(tmp_err); return 0; } /* write full, absolute filename into page->page_filename */ g_free(page->page_filename); page->page_filename = g_strdup(full_filename); /* Before we open the page, let's load the corresponding gafrc. */ /* First cd into file's directory. */ file_directory = g_dirname (full_filename); if (file_directory) { if (chdir (file_directory)) { /* Error occurred with chdir */ #warning FIXME: What do we do? } } /* Now open RC and process file */ if (flags & F_OPEN_RC) { full_rcfilename = g_build_filename (file_directory, "gafrc", NULL); g_rc_parse_file (toplevel, full_rcfilename, &tmp_err); if (tmp_err != NULL) { /* Config files are allowed to be missing or skipped; check for * this. */ if (!g_error_matches (tmp_err, G_FILE_ERROR, G_FILE_ERROR_NOENT) && !g_error_matches (tmp_err, EDA_ERROR, EDA_ERROR_RC_TWICE)) { s_log_message ("%s\n", tmp_err->message); } g_error_free (tmp_err); tmp_err = NULL; } } g_free (file_directory); if (flags & F_OPEN_CHECK_BACKUP) { /* Check if there is a newer autosave backup file */ GString *message; gboolean active_backup = f_has_active_autosave (full_filename, &tmp_err); backup_filename = f_get_autosave_filename (full_filename); if (tmp_err != NULL) g_warning ("%s\n", tmp_err->message); if (active_backup) { message = g_string_new (""); g_string_append_printf(message, _("\nWARNING: Found an autosave backup file:\n %s.\n\n"), backup_filename); if (tmp_err != NULL) { g_string_append(message, _("I could not guess if it is newer, so you have to do it manually.\n")); } else { g_string_append(message, _("The backup copy is newer than the schematic, so it seems you should load it instead of the original file.\n")); } g_string_append (message, _("Gschem usually makes backup copies automatically, and this situation happens when it crashed or it was forced to exit abruptly.\n")); if (toplevel->load_newer_backup_func == NULL) { g_warning ("%s", message->str); g_warning (_("\nRun gschem and correct the situation.\n\n")); } else { /* Ask the user if load the backup or the original file */ if (toplevel->load_newer_backup_func (toplevel->load_newer_backup_data, message)) { /* Load the backup file */ load_backup_file = 1; } } g_string_free (message, TRUE); } if (tmp_err != NULL) g_error_free (tmp_err); } /* Now that we have set the current directory and read * the RC file, it's time to read in the file. */ if (load_backup_file == 1) { /* Load the backup file */ s_page_append_list (toplevel, page, o_read (toplevel, NULL, backup_filename, &tmp_err)); } else { /* Load the original file */ s_page_append_list (toplevel, page, o_read (toplevel, NULL, full_filename, &tmp_err)); } if (tmp_err == NULL) opened = TRUE; else g_propagate_error (err, tmp_err); if (load_backup_file == 0) { /* If it's not the backup file */ page->CHANGED=0; /* added 4/7/98 */ } else { /* We are loading the backup file, so gschem should ask the user if save it or not when closing the page. */ page->CHANGED=1; } g_free(full_filename); g_free(full_rcfilename); g_free (backup_filename); /* Reset the directory to the value it had when f_open was * called. */ if (flags & F_OPEN_RESTORE_CWD) { if (chdir (saved_cwd)) { /* Error occurred with chdir */ #warning FIXME: What do we do? } g_free(saved_cwd); } return opened; }
/*! \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 gattrib_main -- main gattrib fcn. * * \par * *------------------------------------------------------------------*/ void gattrib_main(void *closure, int argc, char *argv[]) { /* TOPLEVEL *pr_current is a global */ /* SHEET_DATA *sheet_head is a global */ /* GtkWidget *main_window is a global */ int argv_index; gchar *cwd; gchar *logfile; #ifdef HAVE_GTHREAD /* Gattrib isn't threaded, but some of GTK's file chooser * backends uses threading so we need to call g_thread_init(). * GLib requires threading be initialised before any other GLib * functions are called. Do it now if its not already setup. */ if (!g_thread_supported ()) g_thread_init (NULL); #endif /* Initialize gEDA stuff */ libgeda_init(); /* Ensure object->sel_func can be used to correctly determine object * locking when the project is saved out */ select_func = s_toplevel_select_object; /* Note that argv_index holds index to first non-flag command line option * (that is, to the first file name) */ argv_index = parse_commandline(argc, argv); /* ---------- create log file right away ---------- */ /* ---------- even if logging is enabled ---------- */ cwd = g_get_current_dir(); logfile = g_build_filename (cwd, "gattrib.log", NULL); s_log_init (logfile); g_free (logfile); g_free (cwd); s_log_message ("gEDA/gattrib version %s%s.%s\n", PREPEND_VERSION_STRING, DOTTED_VERSION, DATE_VERSION); s_log_message ("gEDA/gattrib 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 (!quiet_mode) { fflush(stderr); fflush(stdout); fprintf(stderr, "gEDA/gattrib version %s%s.%s\n", PREPEND_VERSION_STRING, DOTTED_VERSION, DATE_VERSION); fprintf(stderr, "gEDA/gattrib comes with ABSOLUTELY NO WARRANTY; see COPYING for more details.\n"); fprintf(stderr, "This is free software, and you are welcome to redistribute it under certain\n"); fprintf(stderr, "conditions; please see the COPYING file for more details.\n\n"); } /* ------ register guile (scheme) functions. Necessary to parse RC file. ------ */ g_register_funcs(); /* ---------- Start creation of new project: (TOPLEVEL *pr_current) ---------- */ pr_current = s_toplevel_new(); /* ----- Read in RC files. ----- */ g_rc_parse(pr_current, "gattribrc", NULL); i_vars_set(pr_current); gtk_init(&argc, &argv); x_window_init(); /* ---------- Initialize SHEET_DATA data structure ---------- */ sheet_head = s_sheet_data_new(); /* sheet_head was declared in globals.h */ GSList *file_list = NULL; if (argv_index >= argc) { /* No files specified on the command line, pop up the File open dialog. */ file_list = x_fileselect_open(); if(file_list == NULL) exit(0); } else { /* Construct the list of filenames from the command line. * argv_index holds the position of the first filename */ while (argv_index < argc) { gchar *filename = f_normalize_filename(argv[argv_index], NULL); if (filename != NULL) { file_list = g_slist_append(file_list, filename); } else { fprintf(stderr, "Couldn't find file [%s]\n", argv[argv_index]); exit(1); } argv_index++; } } /* Load the files */ if(x_fileselect_load_files(file_list) == FALSE) { /* just exit the program */ exit(1); } g_slist_foreach(file_list, (GFunc)g_free, NULL); g_slist_free(file_list); gtk_main(); exit(0); }