/*! \brief Load a local configuration file. * \par Function Description * Attempts to load the configuration file with basename \a rcname * corresponding to \a path, reporting errors via \a err. If \a path * is a directory, looks for a file named \a rcname in that * directory. Otherwise, looks for a file named \a rcname in the same * directory as \a path. If \a path is NULL, looks in the current * directory. If \a rcname is NULL, the default value of "gafrc" is * used. * * \param toplevel The current #TOPLEVEL structure. * \param rcname The basename of the configuration file to load, or NULL. * \param path The path to load a configuration file for, or NULL. * \param err Return location for errors, or NULL. * \return TRUE on success, FALSE on failure. */ gboolean g_rc_parse_local (TOPLEVEL *toplevel, const gchar *rcname, const gchar *path, GError **err) { gchar *dir = NULL; gchar *rcfile = NULL; gboolean status; g_return_val_if_fail ((toplevel != NULL), FALSE); /* Default to gafrc */ rcname = (rcname != NULL) ? rcname : "gafrc"; /* Default to cwd */ path = (path != NULL) ? path : "."; /* If path isn't a directory, get the dirname. */ if (g_file_test (path, G_FILE_TEST_IS_DIR)) { dir = g_strdup (path); } else { dir = g_path_get_dirname (path); } rcfile = g_build_filename (dir, rcname, NULL); status = g_rc_parse_file (toplevel, rcfile, err); g_free (dir); g_free (rcfile); return status; }
/*! \brief General RC file parsing function. * \par Function Description * Attempt to load system, user and local (current working directory) * configuration files, first with the default "gafrc" basename and * then with the basename \a rcname, if \a rcname is not NULL. * Additionally, attempt to load configuration from \a rcfile if \a * rcfile is not NULL. * * If an error occurs, calls \a handler with the provided \a user_data * and a GError. * * \see g_rc_parse(). * * \param toplevel The current #TOPLEVEL structure. * \param rcname Config file basename, or NULL. * \param rcfile Specific config file path, or NULL. * \param handler Handler function for config parse errors. * \param user_data Data to be passed to \a handler. */ void g_rc_parse_handler (TOPLEVEL *toplevel, const gchar *rcname, const gchar *rcfile, ConfigParseErrorFunc handler, void *user_data) { GError *err = NULL; #ifdef HANDLER_DISPATCH # error HANDLER_DISPATCH already defined #endif #define HANDLER_DISPATCH \ do { if (err == NULL) break; handler (&err, user_data); \ g_error_free (err); err = NULL; } while (0) /* Load configuration files in order. */ /* First gafrc files. */ g_rc_parse_system (toplevel, NULL, &err); HANDLER_DISPATCH; g_rc_parse_user (toplevel, NULL, &err); HANDLER_DISPATCH; g_rc_parse_local (toplevel, NULL, NULL, &err); HANDLER_DISPATCH; /* Next application-specific rcname. */ if (rcname != NULL) { g_rc_parse_system (toplevel, rcname, &err); HANDLER_DISPATCH; g_rc_parse_user (toplevel, rcname, &err); HANDLER_DISPATCH; g_rc_parse_local (toplevel, rcname, NULL, &err); HANDLER_DISPATCH; } /* Finally, optional additional config file. */ if (rcfile != NULL) { g_rc_parse_file (toplevel, rcfile, &err); HANDLER_DISPATCH; } #undef HANDLER_DISPATCH }
/*! \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; }