/* prefs.c
 * geg, a GTK+ Equation Grapher
 * David Bryant 1998
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include "prefs.h"
#include "colorsel.h"
#include "misc.h"

/* global preferences initialised with defaults */
struct_prefs prefs =
{
  /* toolbar stuff */
  DEF_TB, DEF_TT,
  /* startup stuff */
  DEF_XMIN, DEF_XMAX, DEF_YMIN, DEF_YMAX,
  DEF_WIDTH, DEF_HEIGHT,
  DEF_SPACING,
  /* misc stuff */
  DEF_ZOOM, DEF_SPACE,
  DEF_MINRES, DEF_MAXRES,
  DEF_INTERP, DEF_MAXFORM,
  /* color stuff */
  DEF_BACK_VALS, DEF_NUMB_VALS, DEF_AXES_VALS, DEF_SEL_VALS,
  /* font stuff */
  DEF_TEXT_FONT,
  DEF_NUMB_FONT
};

/* locally global data */
static gchar *rc_filename = NULL;
static GtkWidget *wi = NULL;
static GtkWidget *pt_bu, *po_bu, *to_bu, *tt_bu;
static GtkWidget *xmin_en, *xmax_en, *ymin_en, *ymax_en, *width_en, *height_en;
static GtkWidget *zoom_en, *space_en, *interp_en;
static GtkWidget *minres_en, *maxres_en, *maxform_en;
static GtkWidget *back_pr, *numb_pr, *axes_pr, *sel_pr;
static GtkWidget *dec_bu, *rad_bu;
static int skip_equals(char **buf);
static void atov(gdouble vals[3], char *buf);
static void ok_event(GtkWidget *widget, gpointer data);
static void save_event(GtkWidget *widget, gpointer data);
static void cancel_event(GtkWidget *widget, gpointer data);
static gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data);
static void widgets_to_prefs(GtkWidget *widget, gpointer data);
static void prefs_to_widgets(void);
static void compound_entry(gchar *title, GtkWidget **entry, GtkWidget *vbox);
static void compound_spin(gchar *title, GtkWidget **sb, GtkWidget *vbox,
			  gint min, gint max);
static void compound_preview(gchar *title, GtkWidget **preview,
                             GtkWidget *vbox, GtkSignalFunc callback);

/* ok_event, called by the ok button, realises the prefs and closes dialog  
 */
static void
ok_event(GtkWidget *widget, gpointer data)
{
  gtk_widget_destroy(wi);
  wi = NULL;
}

/* save_event, called by the save button, saves the preferences to file     
 */
static void
save_event(GtkWidget *widget, gpointer data)
{
  prefs_rc_write();
}

/* cancel_event, called by cancel button, closes the preferences dialog     
 */
static void
cancel_event(GtkWidget *widget, gpointer data)
{
  gtk_widget_destroy(wi);
  wi = NULL;
}

/* delete_event, internal event, not sure if it is correct GTK+ way          
 */
static gint
delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
  gtk_widget_destroy(wi);
  wi = NULL;
  return(TRUE);
}

/* prefs_event, called by preferences button in toolbar                      
 */
void
prefs_event(GtkWidget *widget, gpointer data)
{
  GtkWidget *temp_bu;
  GtkWidget *tb_hb, *tb_vb;
  GtkWidget *su_hb, *su_vb;
  GtkWidget *mi_hb, *mi_vb;
  GtkWidget *co_hb, *co_vb;
  GtkWidget *nb;
  GtkWidget *temp_la;
  GtkWidget *tb_fr, *su_fr, *mi_fr, *co_fr;
  GSList *tb_gr, *coords_gr;
  GtkSignalFunc realise_preferences;

  if(wi && wi->window) {
    gtk_widget_map(wi);
    gdk_window_raise(wi->window);
    return;
  }

  realise_preferences  = (GtkSignalFunc)data;

  wi = gtk_dialog_new();

  gtk_signal_connect(GTK_OBJECT(wi), "delete_event",
                     GTK_SIGNAL_FUNC(delete_event), wi);

  /* setup window properties */
  gtk_window_set_wmclass(GTK_WINDOW(wi), "preferences", "Geg");
  gtk_window_set_title(GTK_WINDOW(wi), "Preferences");
  gtk_window_set_policy(GTK_WINDOW(wi), FALSE, FALSE, FALSE);
  gtk_window_position(GTK_WINDOW(wi), GTK_WIN_POS_NONE);

  gtk_container_border_width(GTK_CONTAINER(GTK_DIALOG(wi)->vbox), 5);

  nb = gtk_notebook_new();
  gtk_notebook_set_tab_pos(GTK_NOTEBOOK(nb), GTK_POS_TOP);
  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(wi)->vbox), nb, TRUE, TRUE, 0);
  gtk_widget_show(nb);

  /* toolbar */
  tb_fr = gtk_frame_new("Show toolbar as:");
  gtk_widget_show(tb_fr);
  
  temp_la = gtk_label_new("Toolbar");
  gtk_notebook_append_page(GTK_NOTEBOOK(nb), tb_fr, temp_la);

  /* startup */
  su_fr = gtk_frame_new("Startup options:");
  gtk_widget_show(su_fr);

  temp_la = gtk_label_new("Startup");
  gtk_notebook_append_page(GTK_NOTEBOOK(nb), su_fr, temp_la);

  /* misc */
  mi_fr = gtk_frame_new("Miscellaneous options:");
  gtk_widget_show(mi_fr);

  temp_la = gtk_label_new("Miscellaneous");
  gtk_notebook_append_page(GTK_NOTEBOOK(nb), mi_fr, temp_la);

  /* color */
  co_fr = gtk_frame_new("Color options:");
  gtk_widget_show(co_fr);

  temp_la = gtk_label_new("Color");
  gtk_notebook_append_page(GTK_NOTEBOOK(nb), co_fr, temp_la);


  /* tool(bar/tips) stuff */
  tb_hb = gtk_hbox_new(TRUE, 0);
  tb_vb = gtk_vbox_new(TRUE, 0);
  gtk_container_add(GTK_CONTAINER(tb_fr), tb_hb);
  gtk_box_pack_start(GTK_BOX(tb_hb), tb_vb, TRUE, TRUE, 0);
  gtk_widget_show(tb_vb);
  gtk_widget_show(tb_hb);
  /* toolbar radio buttons (p&t, ponly, tonly) */
  pt_bu = gtk_radio_button_new_with_label(NULL, "Pictures and Text");
  tb_gr = gtk_radio_button_group(GTK_RADIO_BUTTON(pt_bu));
  po_bu = gtk_radio_button_new_with_label(tb_gr, "Pictures Only");
  tb_gr = gtk_radio_button_group(GTK_RADIO_BUTTON(po_bu));
  to_bu = gtk_radio_button_new_with_label(tb_gr, "Text Only");
  gtk_box_pack_start(GTK_BOX(tb_vb), pt_bu, TRUE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX(tb_vb), po_bu, TRUE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX(tb_vb), to_bu, TRUE, TRUE, 0);
  gtk_widget_show(pt_bu);
  gtk_widget_show(po_bu);
  gtk_widget_show(to_bu);
  /* toolbar check button (tooltips on/off) */
  tt_bu = gtk_check_button_new_with_label("Show Tooltips");
  gtk_box_pack_start(GTK_BOX(tb_hb), tt_bu, TRUE, TRUE, 0);
  gtk_widget_show(tt_bu);

  /* startup stuff */
  su_hb = gtk_hbox_new(TRUE, 0);
  gtk_container_add(GTK_CONTAINER(su_fr), su_hb);

  su_vb = gtk_vbox_new(TRUE, 0);
  gtk_box_pack_start(GTK_BOX(su_hb), su_vb, TRUE, TRUE, 0);
  compound_entry("Xmin:", &xmin_en, su_vb);
  compound_entry("Xmax:", &xmax_en, su_vb);
  compound_entry("Width:", &width_en, su_vb);
  gtk_widget_show(su_vb);

  su_vb = gtk_vbox_new(TRUE, 0);
  gtk_box_pack_start(GTK_BOX(su_hb), su_vb, TRUE, TRUE, 0);
  compound_entry("Ymin:", &ymin_en, su_vb);
  compound_entry("Ymax:", &ymax_en, su_vb);
  compound_entry("Height:", &height_en, su_vb);
  gtk_widget_show(su_vb);

  su_vb = gtk_vbox_new(TRUE, 0);
  gtk_box_pack_start(GTK_BOX(su_hb), su_vb, TRUE, TRUE, 0);
  dec_bu = gtk_radio_button_new_with_label(NULL, "Decimal Spacing");
  coords_gr = gtk_radio_button_group(GTK_RADIO_BUTTON(dec_bu));
  rad_bu = gtk_radio_button_new_with_label(coords_gr, "Radian Spacing");
  gtk_box_pack_start(GTK_BOX(su_vb), dec_bu, TRUE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX(su_vb), rad_bu, TRUE, TRUE, 0);
  gtk_widget_show(dec_bu);
  gtk_widget_show(rad_bu);
  gtk_widget_show(su_vb);

  gtk_widget_show(su_hb);

  /* misc stuff */
  mi_hb = gtk_hbox_new(TRUE, 0);
  gtk_container_add(GTK_CONTAINER(mi_fr), mi_hb);
  mi_vb = gtk_vbox_new(TRUE, 0);
  gtk_box_pack_start(GTK_BOX(mi_hb), mi_vb, FALSE, FALSE, 0);
  compound_entry("Zoom Factor:", &zoom_en, mi_vb);
  compound_entry("Notch Spacing:", &space_en, mi_vb);
  /* compound_entry("Interpolation:", &interp_en, mi_vb); */
  compound_spin("Interpolation:", &interp_en, mi_vb, 0, 5);
  gtk_widget_show(mi_vb);

  mi_vb = gtk_vbox_new(TRUE, 0);
  gtk_box_pack_start(GTK_BOX(mi_hb), mi_vb, FALSE, FALSE, 0);
  compound_entry("Min Resolution:", &minres_en, mi_vb);
  compound_entry("Max Resolution:", &maxres_en, mi_vb);
  compound_spin("Max Formulas:", &maxform_en, mi_vb, 1, 50);
  gtk_widget_show(mi_vb);

  gtk_widget_show(mi_hb);

  /* color stuff */
  co_hb = gtk_hbox_new(TRUE, 0);
  gtk_container_add(GTK_CONTAINER(co_fr), co_hb);
  co_vb = gtk_vbox_new(TRUE, 0);
  gtk_box_pack_start(GTK_BOX(co_hb), co_vb, TRUE, TRUE, 0);
  compound_preview("Background:", &back_pr, co_vb,
                   GTK_SIGNAL_FUNC(colorsel_event));
  compound_preview("Numbers:", &numb_pr, co_vb,
                   GTK_SIGNAL_FUNC(colorsel_event));
  gtk_widget_show(co_vb);

  co_vb = gtk_vbox_new(TRUE, 0);
  gtk_box_pack_start(GTK_BOX(co_hb), co_vb, TRUE, TRUE, 0);
  compound_preview("Axes:", &axes_pr, co_vb,
                   GTK_SIGNAL_FUNC(colorsel_event));
  compound_preview("Selection:", &sel_pr, co_vb,
                   GTK_SIGNAL_FUNC(colorsel_event));
  gtk_widget_show(co_vb);

  gtk_widget_show(co_hb);

  /* buttons */
  temp_bu = gtk_button_new_with_label("Ok");
  gtk_signal_connect(GTK_OBJECT(temp_bu), "clicked",
                     GTK_SIGNAL_FUNC(widgets_to_prefs), NULL); 
  gtk_signal_connect(GTK_OBJECT(temp_bu), "clicked",
                     realise_preferences, NULL);
  gtk_signal_connect(GTK_OBJECT(temp_bu), "clicked",
                     GTK_SIGNAL_FUNC(ok_event), NULL);
  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(wi)->action_area), temp_bu, 
                     TRUE, TRUE, 0);
  gtk_widget_show(temp_bu);

  temp_bu = gtk_button_new_with_label("Save");
  gtk_signal_connect(GTK_OBJECT(temp_bu), "clicked",
                     GTK_SIGNAL_FUNC(widgets_to_prefs), NULL);
  gtk_signal_connect(GTK_OBJECT(temp_bu), "clicked",
                      GTK_SIGNAL_FUNC(save_event), NULL);
  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(wi)->action_area),
                     temp_bu, TRUE, TRUE, 0);
  gtk_widget_show(temp_bu);

  temp_bu = gtk_button_new_with_label("Cancel");
  gtk_signal_connect(GTK_OBJECT(temp_bu), "clicked", 
                     GTK_SIGNAL_FUNC(cancel_event), NULL);
  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(wi)->action_area), temp_bu, 
                     TRUE, TRUE, 0);
  gtk_widget_show(temp_bu);
  gtk_widget_show(wi);
  prefs_to_widgets();
}

/* compound_entry, a convenience function to create a label and an entry in
 * a horizontal box, and pack it into the vbox provided                      
 */
static void
compound_entry(gchar *title, GtkWidget **entry, GtkWidget *vbox)
{
  GtkWidget *hbox, *label;

  hbox = gtk_hbox_new(FALSE, 0);
  *entry = gtk_entry_new();
  gtk_widget_set_usize(*entry, 75, -1);
  gtk_box_pack_end(GTK_BOX(hbox), *entry, FALSE, FALSE, 0);
  label = gtk_label_new(title);
  gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 5);
  gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  gtk_widget_show(label);
  gtk_widget_show(*entry);
  gtk_widget_show(hbox);
}

static void
compound_spin(gchar *title, GtkWidget **sb, GtkWidget *vbox,
		    gint min, gint max)
{
  GtkWidget *hbox, *label;
  GtkObject *adj;

  hbox = gtk_hbox_new(FALSE, 0);

  adj = gtk_adjustment_new(min, min, max, 1, 1, 1);
  *sb = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 1, 0);
  gtk_widget_set_usize(*sb, 75, -1);
  
  gtk_box_pack_end(GTK_BOX(hbox), *sb, FALSE, FALSE, 0);
  label = gtk_label_new(title);
  gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 5);
  gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  gtk_widget_show(label);
  gtk_widget_show(*sb);
  gtk_widget_show(hbox);

}


/* compound_preview, a convenience function to create a label and a preview
 * in a horizontal box, and pack it into the vbox provided
 */
static void
compound_preview(gchar *title, GtkWidget **preview, GtkWidget *vbox, GtkSignalFunc callback)
{
  GtkWidget *hbox, *label, *frame, *button;

  hbox = gtk_hbox_new(FALSE, 0);
  frame = gtk_frame_new(NULL);
  gtk_box_pack_end(GTK_BOX(hbox), frame, FALSE, FALSE, 0);
  *preview = gtk_preview_new(GTK_PREVIEW_COLOR);
  gtk_preview_set_expand(GTK_PREVIEW(*preview), TRUE);
  gtk_preview_size(GTK_PREVIEW(*preview), 75, -1);
  button = gtk_button_new_with_label("...");
  gtk_signal_connect(GTK_OBJECT(button), "clicked", callback, *preview);
  gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
  gtk_container_add(GTK_CONTAINER(frame), *preview);
  label = gtk_label_new(title);
  gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 5);
  gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
  gtk_widget_show(label);
  gtk_widget_show(button);
  gtk_widget_show(*preview);
  gtk_widget_show(frame);
  gtk_widget_show(hbox);
}

/* prefs_to_widgets, called explicitly by prefs_event, only after all the
 * widgets have been created, takes the information
 * in the prefs struct, and puts it into the appropriate widgets
 */
static void
prefs_to_widgets(void)
{
  /* show toolbar as: pics and text, pics only, text only */
  switch(prefs.tb) {
  case(GEG_RC_PICTURES_AND_TEXT):
    gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(pt_bu), TRUE);
    break;
  case(GEG_RC_PICTURES_ONLY):
    gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(po_bu), TRUE);
    break;
  case(GEG_RC_TEXT_ONLY):
    gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(to_bu), TRUE);
  }

  /* show tooltips: on, off */
  if(prefs.tt == GEG_RC_OFF)
    gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(tt_bu), FALSE);
  else if(prefs.tt == GEG_RC_ON)
    gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(tt_bu), TRUE);
  else
    g_assert_not_reached();

  /* startup options */
  gtk_entry_set_text(GTK_ENTRY(xmin_en), ftoa(prefs.xmin));
  gtk_entry_set_text(GTK_ENTRY(xmax_en), ftoa(prefs.xmax));
  gtk_entry_set_text(GTK_ENTRY(ymin_en), ftoa(prefs.ymin));
  gtk_entry_set_text(GTK_ENTRY(ymax_en), ftoa(prefs.ymax));
  gtk_entry_set_text(GTK_ENTRY(width_en), ltoa(prefs.width));
  gtk_entry_set_text(GTK_ENTRY(height_en), ltoa(prefs.height));

  if(prefs.spacing == GEG_RC_DECIMAL)
    gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(dec_bu), TRUE);
  else if(prefs.spacing == GEG_RC_RADIAN)
    gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(rad_bu), TRUE);
  else
    g_assert_not_reached();

  /* misc options */
  gtk_entry_set_text(GTK_ENTRY(zoom_en), ftoa(prefs.zoom));
  gtk_entry_set_text(GTK_ENTRY(space_en), ltoa(prefs.space));
  gtk_entry_set_text(GTK_ENTRY(interp_en), ltoa(prefs.interp));
  gtk_entry_set_text(GTK_ENTRY(minres_en), ftoa(prefs.minres));
  gtk_entry_set_text(GTK_ENTRY(maxres_en), ftoa(prefs.maxres));
  gtk_entry_set_text(GTK_ENTRY(maxform_en), ltoa(prefs.maxform));

  /* color options */
  show_color_in_preview(back_pr, prefs.back_vals);
  show_color_in_preview(numb_pr, prefs.numb_vals);
  show_color_in_preview(axes_pr, prefs.axes_vals);
  show_color_in_preview(sel_pr, prefs.sel_vals);
}

/* widgets_to_prefs, first callback for save button and ok button,
 * puts the information in the widgets into the prefs struct
 */
static void
widgets_to_prefs(GtkWidget *widget, gpointer data)
{
  /* toolbar stuff */
  if(GTK_TOGGLE_BUTTON(pt_bu)->active)
    prefs.tb = GEG_RC_PICTURES_AND_TEXT;
  else if(GTK_TOGGLE_BUTTON(po_bu)->active)
    prefs.tb = GEG_RC_PICTURES_ONLY;
  else
    prefs.tb = GEG_RC_TEXT_ONLY;

  /* tooltips stuff */
  if(GTK_TOGGLE_BUTTON(tt_bu)->active)
    prefs.tt = GEG_RC_ON;
  else
    prefs.tt = GEG_RC_OFF;

  /* misc options */
  prefs.zoom    = CLAMP(atof(gtk_entry_get_text(GTK_ENTRY(zoom_en))), 0.1, 5);
  prefs.space   = CLAMP(atol(gtk_entry_get_text(GTK_ENTRY(space_en))), 10, 500);
  prefs.minres  = ABS(atof(gtk_entry_get_text(GTK_ENTRY(minres_en))));
  prefs.maxres  = MAX(atof(gtk_entry_get_text(GTK_ENTRY(maxres_en))),
		      10 * prefs.minres);
  prefs.interp  = CLAMP(atol(gtk_entry_get_text(GTK_ENTRY(interp_en))), 0, 5);
  prefs.maxform = CLAMP(atol(gtk_entry_get_text(GTK_ENTRY(maxform_en))), 1, 50);

  /* startup options */
  prefs.xmin   = atof(gtk_entry_get_text(GTK_ENTRY(xmin_en)));
  prefs.xmax   = MAX(atof(gtk_entry_get_text(GTK_ENTRY(xmax_en))),
		     prefs.xmin + 10 * prefs.minres);
  prefs.ymin   = atof(gtk_entry_get_text(GTK_ENTRY(ymin_en)));
  prefs.ymax   = MAX(atof(gtk_entry_get_text(GTK_ENTRY(ymax_en))),
		     prefs.ymin + 10 * prefs.minres);
  prefs.width  = MAX(atol(gtk_entry_get_text(GTK_ENTRY(width_en))),
		     10 * prefs.minres);
  prefs.height = MAX(atol(gtk_entry_get_text(GTK_ENTRY(height_en))),
		     10 * prefs.minres);

  if(GTK_TOGGLE_BUTTON(dec_bu)->active)
    prefs.spacing = GEG_RC_DECIMAL;
  else if(GTK_TOGGLE_BUTTON(rad_bu)->active)
    prefs.spacing = GEG_RC_RADIAN;
  else
    g_assert_not_reached();

  /* color options */
  memcpy(&prefs.back_vals[0], gtk_object_get_data(GTK_OBJECT(back_pr),
         ValuesKey), 3 * sizeof(gdouble));
  memcpy(&prefs.numb_vals[0], gtk_object_get_data(GTK_OBJECT(numb_pr),
         ValuesKey), 3 * sizeof(gdouble));
  memcpy(&prefs.axes_vals[0], gtk_object_get_data(GTK_OBJECT(axes_pr),
         ValuesKey), 3 * sizeof(gdouble));
  memcpy(&prefs.sel_vals[0], gtk_object_get_data(GTK_OBJECT(sel_pr),
         ValuesKey), 3 * sizeof(gdouble));
}

/* atov, this function extracts the color values from the format:
 *     { %f, %f, %f }
 * and stores them in vals[]
 */
static void
atov(gdouble vals[3], char *buf)
{
  /* the whole function is essentially the following line */
  /* sscanf(buf, "{ %f, %f, %f }", &vals[0], &vals[1], &vals[2]); */

  while((*buf == ' ') || (*buf == '=') || (*buf == '{'))
    buf++;			/* skip to the first number (hopefully) */

  if(*buf == '\0')		/* test for string termination */
    return;

  vals[0] = atof(buf);		/* snag the first value */
  while(*buf != ',') {		/* get up to the comma */
    buf++;
    if(*buf == '\0')
      return;
  }

  while(*++buf == ' ');		/* skip possible whitespace */

  if(*buf == '\0')		/* test for string termination */
    return;

  vals[1] = atof(buf);		/* snag the second value */
  while(*buf != ',') {
    buf++;
    if(*buf == '\0')
      return;
  }

  while(*++buf == ' ');		/* skip possible whitespace */


  if(*buf == '\0')		/* test for string termination */
    return;

  vals[2] = atof(buf);		/* snag the third value */
}

/* skip_equals, skips to the first non-whitespace character after equals sign
 */
static int
skip_equals(char **buf)
{
  int i;

  for(i = 0; i < 200; i++) {
    if(**buf == '=') {
      (*buf)++;
      while(**buf == ' ')
      (*buf)++;
      return(TRUE);
    }
    (*buf)++;
  }

  g_warning("error in rcfile, expected equals");
  return(FALSE);
}

int
prefs_rc_parse(const gchar *filename)
{
  FILE *fp;
  char buf[256], *i;

  if(rc_filename)
    g_free(rc_filename);

  /* save the filename for when we write back the preferences */
  rc_filename = g_strdup(filename);

  fp = fopen(filename, "r");

  if(!fp)
    return(-1);

  while(fgets(buf, 256, fp)) {
    i = &buf[0];
    while(*i == ' ')
      i++;
    if((*i == '#') || (*i == '\n'))
      continue;

    /* work out what the setting is */
    if(!strncasecmp(i, "toolbar", 7)) {
      if(skip_equals(&i)) {
        if(!strncasecmp(i, "pictures_and_text", 17))
          prefs.tb = GEG_RC_PICTURES_AND_TEXT;
	else if(!strncasecmp(i, "pictures_only", 13))
          prefs.tb = GEG_RC_PICTURES_ONLY;
	else if(!strncasecmp(i, "text_only", 9))
          prefs.tb = GEG_RC_TEXT_ONLY;
	else
	  g_warning("error in rcfile %s: %s", filename, buf);
      }
    }
    else if(!strncasecmp(i, "tooltips", 8)) {
      if(skip_equals(&i)) {
        if(!strncasecmp(i, "on", 2))
          prefs.tt = GEG_RC_ON;
	else if(!strncasecmp(i, "off", 3))
          prefs.tt = GEG_RC_OFF;
	else
	  g_warning("error in rcfile %s: %s", filename, buf);
      }
    }
    else if(!strncasecmp(i, "xmin", 4)) {
      if(skip_equals(&i))
        prefs.xmin = atof(i);
    }
    else if(!strncasecmp(i, "xmax", 4)) {
      if(skip_equals(&i))
        prefs.xmax = atof(i);
    }
    else if(!strncasecmp(i, "ymin", 4)) {
      if(skip_equals(&i))
        prefs.ymin = atof(i);
    }
    else if(!strncasecmp(i, "ymax", 4)) {
      if(skip_equals(&i))
        prefs.ymax = atof(i);
    }
    else if(!strncasecmp(i, "graph_width", 11)) {
      if(skip_equals(&i))
        prefs.width = atol(i);
    }
    else if(!strncasecmp(i, "graph_height", 12)) {
      if(skip_equals(&i))
        prefs.height = atol(i);
    }
    else if(!strncasecmp(i, "spacing_type", 12)) {
      if(skip_equals(&i)) {
	if(!strncasecmp(i, "decimal", 7))
	  prefs.spacing = GEG_RC_DECIMAL;
	else if(!strncasecmp(i, "radian", 6))
	  prefs.spacing = GEG_RC_RADIAN;
	else
	  g_warning("error in rcfile %s: %s", filename, buf);
      }
    }
    else if(!strncasecmp(i, "zoom_factor", 11)) {
      if(skip_equals(&i))
        prefs.zoom = atof(i);
    }
    else if(!strncasecmp(i, "notch_spacing", 13)) {
      if(skip_equals(&i))
        prefs.space = atol(i);
    }
    else if(!strncasecmp(i, "minimum_resolution", 18)) {
      if(skip_equals(&i))
        prefs.minres = atof(i);
    }
    else if(!strncasecmp(i, "maximum_resolution", 18)) {
      if(skip_equals(&i))
        prefs.maxres = atof(i);
    }
    else if(!strncasecmp(i, "interpolation_factor", 19)) {
      if(skip_equals(&i))
        prefs.interp = atol(i);
    }
    else if(!strncasecmp(i, "maximum_formulas", 16)) {
      if(skip_equals(&i))
        prefs.maxform = atol(i);
    }
    else if(!strncasecmp(i, "background", 10)) {
      if(skip_equals(&i))
        atov(prefs.back_vals, i);
    }
    else if(!strncasecmp(i, "numbers", 7)) {
      if(skip_equals(&i))
	atov(prefs.numb_vals, i);
    }
    else if(!strncasecmp(i, "axes", 4)) {
      if(skip_equals(&i))
        atov(prefs.axes_vals, i);
    }
    else if(!strncasecmp(i, "selection", 9)) {
      if(skip_equals(&i))
	atov(prefs.sel_vals, i);
    }
    else
      g_warning("error in rcfile %s: %s", filename, buf);
  }

  fclose(fp);
  return(0);
}

/* prefs_rc_write, writes the user's preferences back to file
 */
gint
prefs_rc_write(void)
{
  FILE *fp;
  char *buf;

  fp = fopen(rc_filename, "w+");

  if(!fp)
    return(-1);

  /* write header */
  fprintf(fp, "# geg preferences file\n");
  fprintf(fp, "# all options can be changed within geg\n\n");

  /* toolbar */
  switch(prefs.tb) {
  case GEG_RC_PICTURES_AND_TEXT:
    buf = "pictures_and_text";
    break;
  case GEG_RC_PICTURES_ONLY:
    buf = "pictures_only";
    break;
  case GEG_RC_TEXT_ONLY:
    buf = "text_only";
    break;
  default:
    buf = NULL;
  }

  fprintf(fp, "toolbar = %s\n", buf);

  /* tooltips */
  if(prefs.tt == GEG_RC_ON)
    buf = "on";
  else if(prefs.tt == GEG_RC_OFF)
    buf = "off";
  else
    g_assert_not_reached();

  fprintf(fp, "tooltips = %s\n\n", buf);

  /* xmin, xmax, ymin, ymax, width, height, spacing_type */
  fprintf(fp, "xmin = %f\n", prefs.xmin);
  fprintf(fp, "xmax = %f\n", prefs.xmax);
  fprintf(fp, "ymin = %f\n", prefs.ymin);
  fprintf(fp, "ymax = %f\n\n", prefs.ymax);
  fprintf(fp, "graph_width = %d\n", prefs.width);
  fprintf(fp, "graph_height = %d\n", prefs.height);

  if(prefs.spacing == GEG_RC_DECIMAL)
    buf = "decimal";
  else if(prefs.spacing == GEG_RC_RADIAN)
    buf = "radian";
  else
    g_assert_not_reached();

  fprintf(fp, "spacing_type = %s\n\n", buf);

  /* zoom, space, minres, maxres */
  fprintf(fp, "zoom_factor = %f\n", prefs.zoom);
  fprintf(fp, "notch_spacing = %d\n", prefs.space);
  fprintf(fp, "minimum_resolution = %f\n", prefs.minres);
  fprintf(fp, "maximum_resolution = %f\n", prefs.maxres);
  fprintf(fp, "interpolation_factor = %d\n", prefs.interp);
  fprintf(fp, "maximum_formulas = %d\n\n", prefs.maxform);

  /* background, numbers, axes, selection */
  fprintf(fp, "background = { %f, %f, %f }\n",
          prefs.back_vals[0], prefs.back_vals[1], prefs.back_vals[2]);
  fprintf(fp, "numbers = { %f, %f, %f }\n",
          prefs.numb_vals[0], prefs.numb_vals[1], prefs.numb_vals[2]);
  fprintf(fp, "axes = { %f, %f, %f }\n",
          prefs.axes_vals[0], prefs.axes_vals[1], prefs.axes_vals[2]);
  fprintf(fp, "selection = { %f, %f, %f }\n",
          prefs.sel_vals[0], prefs.sel_vals[1], prefs.sel_vals[2]);
  
  fclose(fp);

  return(0);
}


syntax highlighted by Code2HTML, v. 0.9.1