Logo Search packages:      
Sourcecode: galculator version File versions  Download package

config_file.c

/*
 *  config_file.c - manages config file access.
 *    part of galculator
 *    (c) 2002-2006 Simon Floery (chimaira@users.sf.net)
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
 
/* to add a new preference, add it to 
      - s_preferences in config_file.h
      - #define DEFAULTS in config_file.h
      - to config_file_get_default_prefs
      - to struct prefs_list (increase array size!)
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* i18n */

#include <libintl.h>
#define _(String) gettext (String)
#define gettext_noop(String) String
#define N_(String) gettext_noop (String)

#include "config_file.h"
#include "general_functions.h"

s_preferences prefs;
static s_prefs_entry prefs_list[53] = {
      {"display_bkg_color", &(prefs.bkg_color), STRING, "prefs_bkg_color", set_button_color},
      {"display_result_font", &(prefs.result_font), STRING, "prefs_result_font", set_button_label},
      {"display_result_color", &(prefs.result_color), STRING, "prefs_result_color", set_button_color},
      {"display_stack_font", &(prefs.stack_font), STRING, "prefs_stack_font", set_button_label},
      {"display_stack_color", &(prefs.stack_color), STRING, "prefs_stack_color", set_button_color},
      {"display_module_font", &(prefs.mod_font), STRING, "prefs_mod_font", set_button_label},
      {"display_module_active_color", &(prefs.act_mod_color), STRING, "prefs_act_mod_color", set_button_color},
      {"display_module_inactive_color", &(prefs.inact_mod_color), STRING, "prefs_inact_mod_color", set_button_color},
      {"display_module_number", &(prefs.vis_number), BOOLEAN, "prefs_vis_number", set_checkbutton},
/*10*/      {"display_module_angle", &(prefs.vis_angle), BOOLEAN, "prefs_vis_angle", set_checkbutton},
      {"display_module_notation", &(prefs.vis_notation), BOOLEAN, "prefs_vis_notation", set_checkbutton},
      {"display_module_arith", &(prefs.vis_arith), BOOLEAN, "prefs_vis_arith", set_checkbutton},
      {"display_module_open", &(prefs.vis_bracket), BOOLEAN, "prefs_vis_bracket", set_checkbutton},
      {"custom_button_font", &(prefs.custom_button_font), BOOLEAN, "prefs_custom_button_font", set_checkbutton},
      {"button_font", &(prefs.button_font), STRING, "prefs_button_font", set_button_label},
      {"button_width", &(prefs.button_width), INTEGER, "prefs_button_width", set_spinbutton},
      {"button_height", &(prefs.button_height), INTEGER, "prefs_button_height", set_spinbutton},
      {"function_button_group", &(prefs.vis_funcs), BOOLEAN, NULL, NULL},
      {"dispctrl_button_group", &(prefs.vis_dispctrl), BOOLEAN, NULL, NULL},
/*20*/      {"logic_button_group", &(prefs.vis_logic), BOOLEAN, NULL, NULL},
      {"standard_button_group", &(prefs.vis_standard), BOOLEAN, NULL, NULL},
      {"mode", &(prefs.mode), INTEGER, NULL, NULL},
      {"dec_sep", &(prefs.dec_sep), BOOLEAN, "prefs_dec_sep", set_checkbutton},
      {"dec_sep_length", &(prefs.dec_sep_length), INTEGER, "prefs_dec_sep_length", set_spinbutton},
      {"dec_sep_char", &(prefs.dec_sep_char), STRING, "prefs_dec_sep_char", set_entry},
      {"hex_bits", &(prefs.hex_bits), INTEGER, "prefs_hex_bits", set_spinbutton},
      {"hex_signed", &(prefs.hex_signed), BOOLEAN, "prefs_hex_signed", set_checkbutton},
      {"hex_sep", &(prefs.hex_sep), BOOLEAN, "prefs_hex_sep", set_checkbutton},
      {"hex_sep_length", &(prefs.hex_sep_length), INTEGER, "prefs_hex_sep_length", set_spinbutton},
/*30*/      {"hex_sep_char", &(prefs.hex_sep_char), STRING, "prefs_hex_sep_char", set_entry},
      {"oct_bits", &(prefs.oct_bits), INTEGER, "prefs_oct_bits", set_spinbutton},
      {"oct_signed", &(prefs.oct_signed), BOOLEAN, "prefs_oct_signed", set_checkbutton},
      {"oct_sep", &(prefs.oct_sep), BOOLEAN, "prefs_oct_sep", set_checkbutton},
      {"oct_sep_length", &(prefs.oct_sep_length), INTEGER, "prefs_oct_sep_length", set_spinbutton},
      {"oct_sep_char", &(prefs.oct_sep_char), STRING, "prefs_oct_sep_char", set_entry},
      {"bin_bits", &(prefs.bin_bits), INTEGER, "prefs_bin_bits", set_spinbutton},
      {"bin_signed", &(prefs.bin_signed), BOOLEAN, "prefs_bin_signed", set_checkbutton},
      {"bin_fixed", &(prefs.bin_fixed), BOOLEAN, "prefs_bin_fixed", set_checkbutton},
      {"bin_length", &(prefs.bin_length), INTEGER, "prefs_bin_length", set_spinbutton},
/*40*/      {"bin_sep", &(prefs.bin_sep), BOOLEAN, "prefs_bin_sep", set_checkbutton},
      {"bin_sep_length", &(prefs.bin_sep_length), INTEGER, "prefs_bin_sep_length", set_spinbutton},
      {"bin_sep_char", &(prefs.bin_sep_char), STRING, "prefs_bin_sep_char", set_entry},
      {"default_number_base", &(prefs.def_number), INTEGER, NULL, NULL},
      {"default_angle_base", &(prefs.def_angle), INTEGER, NULL, NULL},
      {"default_notation_mode", &(prefs.def_notation), INTEGER, NULL, NULL},
      {"stack_size", &(prefs.stack_size), INTEGER, NULL, set_stacksize},
      {"remembers_display", &(prefs.rem_display), BOOLEAN, "prefs_rem_display", set_checkbutton},
      {"remembered_valuex", &(prefs.rem_valuex), STRING, NULL, NULL},
      {"remembered_valuey", &(prefs.rem_valuey), STRING, NULL, NULL},
/*50*/      {"remembered_valuez", &(prefs.rem_valuez), STRING, NULL, NULL},
      {"remembered_valuet", &(prefs.rem_valuet), STRING, NULL, NULL},
      {"show_menu_bar", &(prefs.show_menu), BOOLEAN, "prefs_show_menu", set_checkbutton},
      {NULL, NULL, 0, NULL, NULL}
};
static char *prefs_list_old_entries[3] = {"show_status_bar", "remembered_value", NULL};
static s_constant *cf_constant=NULL;
static s_user_function *cf_user_function=NULL;

/*
 * config_file_get_default_prefs - initialize ALL members of the given s_preferences
 *    structure with default values.
 */
static void config_file_get_default_prefs (s_preferences *this_prefs)
{
      /* 1st pref page */
      this_prefs->bkg_color = g_strdup (DEFAULT_BKG_COLOR);
      this_prefs->result_font = g_strdup (DEFAULT_RESULT_FONT);
      this_prefs->result_color = g_strdup (DEFAULT_RESULT_COLOR);
      this_prefs->stack_font = g_strdup (DEFAULT_STACK_FONT);
      this_prefs->stack_color = g_strdup (DEFAULT_STACK_COLOR);
      this_prefs->mod_font = g_strdup (DEFAULT_MOD_FONT);
      this_prefs->act_mod_color = g_strdup (DEFAULT_ACT_MOD_COLOR);
      this_prefs->inact_mod_color = g_strdup (DEFAULT_INACT_MOD_COLOR);
      this_prefs->vis_number = DEFAULT_VIS_NUMBER;
      this_prefs->vis_angle = DEFAULT_VIS_ANGLE;
      this_prefs->vis_notation = DEFAULT_VIS_NOTATION;
      this_prefs->vis_arith = DEFAULT_VIS_ARITH;
      this_prefs->vis_bracket = DEFAULT_VIS_BRACKET;
      
      /* 2nd pref page */
      this_prefs->custom_button_font = DEFAULT_CUSTOM_BUTTON_FONT;
      this_prefs->button_font = g_strdup (DEFAULT_BUTTON_FONT);
      this_prefs->button_width = DEFAULT_BUTTON_WIDTH;
      this_prefs->button_height = DEFAULT_BUTTON_HEIGHT;
      this_prefs->vis_funcs = DEFAULT_VIS_FUNCS;
      this_prefs->vis_dispctrl = DEFAULT_VIS_DISPCTRL;
      this_prefs->vis_logic = DEFAULT_VIS_LOGIC;
      this_prefs->vis_standard = DEFAULT_VIS_STANDARD;
      this_prefs->mode = DEFAULT_MODE;
      
      /* 3rd pref page */
      /* constants - handled different */
      
      /* 4th pref page */
      this_prefs->dec_sep = DEFAULT_DEC_SEP;
      this_prefs->dec_sep_char = g_strdup (DEFAULT_DEC_SEP_CHAR);
      this_prefs->dec_sep_length = DEFAULT_DEC_SEP_LENGTH;
      this_prefs->hex_bits = DEFAULT_HEX_BITS;
      this_prefs->hex_signed = DEFAULT_HEX_SIGNED;
      this_prefs->hex_sep = DEFAULT_HEX_SEP;
      this_prefs->hex_sep_char = g_strdup (DEFAULT_HEX_SEP_CHAR);
      this_prefs->hex_sep_length = DEFAULT_HEX_SEP_LENGTH;
      this_prefs->oct_bits = DEFAULT_OCT_BITS;
      this_prefs->oct_signed = DEFAULT_OCT_SIGNED;
      this_prefs->oct_sep = DEFAULT_OCT_SEP;
      this_prefs->oct_sep_char = g_strdup (DEFAULT_OCT_SEP_CHAR);
      this_prefs->oct_sep_length = DEFAULT_OCT_SEP_LENGTH;
      this_prefs->bin_bits = DEFAULT_BIN_BITS;
      this_prefs->bin_signed = DEFAULT_BIN_SIGNED;
      this_prefs->bin_fixed = DEFAULT_BIN_FIXED;
      this_prefs->bin_length = DEFAULT_BIN_LENGTH;
      this_prefs->bin_sep = DEFAULT_BIN_SEP;
      this_prefs->bin_sep_char = g_strdup (DEFAULT_BIN_SEP_CHAR);
      this_prefs->bin_sep_length = DEFAULT_BIN_SEP_LENGTH;

      /* 5rd pref page */
      this_prefs->stack_size = DEFAULT_STACK_SIZE;
      this_prefs->def_number = DEFAULT_NUMBER;
      this_prefs->def_angle = DEFAULT_ANGLE;
      this_prefs->def_notation = DEFAULT_NOTATION;
      this_prefs->rem_display = DEFAULT_REM_DISPLAY;
      this_prefs->rem_valuex = g_strdup (DEFAULT_REM_VALUEX);
      this_prefs->rem_valuey = g_strdup (DEFAULT_REM_VALUEY);
      this_prefs->rem_valuez = g_strdup (DEFAULT_REM_VALUEZ);
      this_prefs->rem_valuet = g_strdup (DEFAULT_REM_VALUET);
      this_prefs->show_menu = DEFAULT_SHOW_MENU;
}

/*
 * config_file_get_default_consts - fill in default constants, which are not
 *    saved to configuration file. sync with counter inits in write and set_consts!
 */

static void config_file_get_default_consts (s_constant **consts)
{
      *consts = (s_constant *) malloc (3 * sizeof (s_constant));
      (*consts)[0].desc = g_strdup (_("Pi"));
      (*consts)[0].name = g_strdup (_("pi"));
      (*consts)[0].value = g_strdup_printf ("%.11f", G_PI);
      (*consts)[1].desc = g_strdup (_("Euler's Number"));
      (*consts)[1].name = g_strdup (_("e"));
      (*consts)[1].value = g_strdup_printf ("%.11f", G_E);
      (*consts)[2].name = NULL;
}

/*
 * config_file_get_default_user_functions - fill in default user functions
 */

static void config_file_get_default_user_functions (s_user_function **this_user_funcs)
{
      *this_user_funcs = (s_user_function *) malloc (4 * sizeof (s_user_function));
      (*this_user_funcs)[0].name = g_strdup ("abs");
      (*this_user_funcs)[0].variable = g_strdup ("x");
      (*this_user_funcs)[0].expression = g_strdup_printf ("sqrt(x^2)");
      (*this_user_funcs)[1].name = g_strdup ("sign");
      (*this_user_funcs)[1].variable = g_strdup ("x");
      (*this_user_funcs)[1].expression = g_strdup_printf ("x/abs(x)");  
      (*this_user_funcs)[2].name = g_strdup ("cot");
      (*this_user_funcs)[2].variable = g_strdup ("x");
      (*this_user_funcs)[2].expression = g_strdup_printf ("cos(x)/sin(x)");
      (*this_user_funcs)[3].name = NULL;
}

/*
 * config_file_set_prefs - find the key in the s_prefs_entry struct to retrieve
 *    the variable to set. The way to set this variable is given by key_type.
 *    used by config_file_read.
 */

void config_file_set_prefs (char *key, char *value)
{
      int         *int_var, counter=0, old_counter=0;
      char        **string_var, *end_ptr;
      gboolean    *bool_var;
      void        *this_var;
      
      while (prefs_list[counter].key != NULL)   {
            if (g_ascii_strcasecmp (key, prefs_list[counter].key) == 0) break;      
            counter++;
      }
      
      if (prefs_list[counter].key == NULL) {
            while (prefs_list_old_entries[old_counter] != NULL) {
                  if (g_ascii_strcasecmp (key, prefs_list_old_entries[old_counter]) == 0) break;      
                  old_counter++;
            }
            if (prefs_list_old_entries[old_counter] == NULL) \
                  fprintf (stderr, _("[%s] configuration file: ignoring unknown entry %s=%s. %s\n"), PACKAGE, key, value, BUG_REPORT);
            return;
      }
      
      this_var = prefs_list[counter].variable;
      switch (prefs_list[counter].key_type)
      {
            case STRING:
                  string_var = this_var;
                  g_free (*string_var);
                  /* version 1.2.4 introduced strings enbodied by pairs of
                   * \"'s. So remove those if they exist.
                   */
                  if ((value[0] == '\"') && (value[strlen(value)-1] == '\"'))
                  {
                        value++;
                        value[strlen(value)-1]='\0';
                  }
                  *string_var = g_strdup (value);
                  break;
            case BOOLEAN:
                  bool_var = this_var;
                  if (g_ascii_strcasecmp (value, "true")  == 0) *bool_var = TRUE;
                  else if (g_ascii_strcasecmp (value, "false")  == 0) *bool_var = FALSE;
                  else fprintf (stderr, _("[%s] configuration file: %s has to be TRUE or FALSE. Using defaults. %s\n"), PACKAGE, key, BUG_REPORT);
                  break;
            case INTEGER:
                  int_var = this_var;
                  *int_var = (int) g_ascii_strtod (value, &end_ptr);
                  if (*end_ptr != '\0')
                        fprintf (stderr, _("[%s] configuration file: failed to convert %s to a number properly. Have you changed your locales? %s\n"), PACKAGE, value, BUG_REPORT);
                  break;
            default:
                  fprintf (stderr, _("[%s] configuration file: ignoring unknown key_type in config structure. %s\n"), PACKAGE, BUG_REPORT);
      }
}

/*
 * config_file_get_mode - if the line is enclosed by [...] and the enclosed
 *    string is known, change to that mode.
 */

int config_file_get_mode (char *line, char *filename, int old_mode)
{
      int   len;
      
      line = g_strstrip(line);
      len = strlen(line);
      if ((line[0] == '[') && (line[len - 1] == ']')) {
            if (strcmp (line, SECTION_GENERAL) == 0) return GENERAL;
            else if (strcmp (line, SECTION_CONSTANTS) == 0) return CONSTANTS;
            else if (strcmp (line, SECTION_USER_FUNCTIONS) == 0) return USER_FUNCTIONS;
            else fprintf (stderr, _("[%s] found unknown section %s in \
configuration file %s. Using preceding section.\n"), PACKAGE, line, filename);
      }
      return old_mode;
}

/*
 * config_file_set_constants - parses line and fills into the s_constants array.
 */

void config_file_set_constants (char *line)
{
      char        *desc, *name, *value;
      static int  nr_consts=0;
      
      desc = line;
      name = strchr (line, ':');
      if (name == NULL) return;
      *name = '\0';
      name++;
      value = strchr (name, '=');
      if (value == NULL) return;
      *value = '\0';
      value++;
      desc = g_strstrip(desc);
      name = g_strstrip(name);
      value = g_strstrip(value);
      /* allowing desc and name to be "" */
      if (strlen(value) == 0) return;
      nr_consts++;
      cf_constant = (s_constant *) realloc (cf_constant, (nr_consts + 1) * sizeof(s_constant));
      cf_constant[nr_consts-1].desc = g_strdup (desc);
      cf_constant[nr_consts-1].name = g_strdup (name);
      cf_constant[nr_consts-1].value = g_strdup (value);
      /* keep it NULL terminated */
      cf_constant[nr_consts].name = NULL;
}

/* config_file_set_user_functions
 *
 */

void config_file_set_user_functions (char *line)
{
      char        *name, *variable, *expression;
      static int  nr_user_functions=0;
      
      name = line;
      variable = strchr (line, '(');
      if (variable == NULL) return;
      *variable = '\0';
      variable++;
      expression = strchr (variable, ')');
      if (expression == NULL) return;
      *expression = '\0';
      expression++;
      expression = strchr (expression, '=');
      if (expression == NULL) return;
      expression++;
      name = g_strstrip(name);
      variable = g_strstrip(variable);
      expression = g_strstrip(expression);
      /* allowing name to be "" */
      if ((strlen(variable) == 0) || (strlen(expression) == 0)) return;
      nr_user_functions++;
      cf_user_function = (s_user_function *) realloc (cf_user_function, 
            (nr_user_functions + 1) * sizeof(s_user_function));
      cf_user_function[nr_user_functions-1].name = g_strdup (name);
      cf_user_function[nr_user_functions-1].variable = g_strdup (variable);
      cf_user_function[nr_user_functions-1].expression = g_strdup (expression);
      /* keep it NULL terminated */
      cf_user_function[nr_user_functions].name = NULL;
}

/*
 * config_file_read - open/read/close. values are saved to global variable prefs!
 *    policy: if there is no constants section, pi and e are added as default
 *    constants. of there is the section headline, nothing is added.
 */

s_preferences config_file_read (char *filename)
{
      char        line[MAX_FILE_LINE_LENGTH], *key, *value;
      FILE        *this_file;
      int         mode=GENERAL;
      gboolean    have_const_section=FALSE, have_user_function_section=FALSE;
      
      this_file = fopen (filename, "r");
      config_file_get_default_prefs (&prefs);
      cf_constant = (s_constant *) malloc (sizeof(s_constant));
      cf_constant->desc = NULL;
      if (this_file != NULL) {
            while (fgets (line, MAX_FILE_LINE_LENGTH, this_file) != NULL) {
                  if (line[0] != '#') {
                        mode = config_file_get_mode (line, filename, mode);
                        switch (mode) {
                        case GENERAL:
                              key = line;
                              value = strchr (line, '=');
                              if (value == NULL) break;
                              *value = '\0';
                              value++;
                              key = g_strstrip(key);
                              value = g_strstrip(value);
                              config_file_set_prefs (key, value);
                              break;
                        case CONSTANTS:
                              have_const_section = TRUE;
                              config_file_set_constants (line);
                              break;
                        case USER_FUNCTIONS:
                              have_user_function_section = TRUE;
                              config_file_set_user_functions (line);
                              break;
                        }
                  }
            }
            fclose (this_file);
      }
      else fprintf (stderr, _("[%s] configuration file: couldn't open configuration file %s for reading. \
Nothing to worry about if you are starting %s for the first time. Using defaults.\n"), PACKAGE, filename, PACKAGE);
      if (have_const_section == FALSE) config_file_get_default_consts (&cf_constant);
      if (have_user_function_section == FALSE) config_file_get_default_user_functions (&cf_user_function);
      return prefs;
}

/*
 * config_file_write - open/write/close.
 */

void config_file_write (char *filename, s_preferences this_prefs, s_constant *this_constants, s_user_function *this_user_functions)
{
      int         *int_var, counter=0;
      char        **string_var;
      gboolean    *bool_var;
      void        *this_var;
      char        *line=NULL;
      FILE        *this_file;
      
      cf_constant = this_constants;
      cf_user_function = this_user_functions;
      this_file = fopen (filename, "w+");
      /* overwrite local prefs memory with supplied prefs. probably ugly. */
      prefs = this_prefs;
      if (this_file != NULL) {
            fprintf (this_file, "\n%s\n\n", SECTION_GENERAL);
            while (prefs_list[counter].key != NULL) {
                  this_var = prefs_list[counter].variable;
                  switch (prefs_list[counter].key_type) {
                        case STRING:
                              string_var = this_var;
                              line = g_strdup_printf ("%s=\"%s\"\n", prefs_list[counter].key, *string_var);
                              break;
                        case BOOLEAN:
                              bool_var = this_var;
                              if (*bool_var == TRUE) line = g_strdup_printf ("%s=true\n", prefs_list[counter].key);
                              else if (*bool_var == FALSE) line = g_strdup_printf ("%s=false\n", prefs_list[counter].key);
                              else fprintf (stderr, _("[%s] configuration file: strange boolean when writing. Skipping this key. %s\n"), PACKAGE, BUG_REPORT);
                              break;
                        case INTEGER:
                              int_var = this_var;
                              line = g_strdup_printf ("%s=%i\n", prefs_list[counter].key, *int_var);
                              break;
                        default:
                              line = g_strdup_printf ("#%s=???\n", prefs_list[counter].key);
                              fprintf (stderr, _("[%s] configuration file: ignoring unknown \"key_type\" in \"config_structure\". %s\n"), PACKAGE, BUG_REPORT);
                  }
                  fputs (line, this_file);
                  g_free (line);
                  counter ++;
            }
            counter = 0;
            fprintf (this_file, "\n%s\n\n", SECTION_CONSTANTS);
            while (cf_constant[counter].name != NULL) {
                  fprintf (this_file, "%s:%s=%s\n", cf_constant[counter].desc, 
                        cf_constant[counter].name, cf_constant[counter].value);
                  counter++;
            }
            counter = 0;
            fprintf (this_file, "\n%s\n\n", SECTION_USER_FUNCTIONS);
            while (cf_user_function[counter].name != NULL) {      
                  fprintf (this_file, "%s(%s)=%s\n", cf_user_function[counter].name, 
                        cf_user_function[counter].variable, 
                        cf_user_function[counter].expression);
                  counter++;
            }
            fclose (this_file);
      }     
      else fprintf (stderr, _("[%s] configuration file: couldn't save/write to configuration file %s.\n"), PACKAGE, filename);
}

s_prefs_entry *config_file_get_prefs_list()
{
      return prefs_list;
}

s_constant *config_file_get_constants()
{
      return cf_constant;
}

s_user_function *config_file_get_user_functions()
{
      return cf_user_function;
}

Generated by  Doxygen 1.6.0   Back to index