replace *a lot* of file related calls by their GLib counterparts. This is necessary...
[obnox/wireshark/wip.git] / epan / prefs.c
index 8ab6342bfced8aca2774dc6add791e746abfdff7..70711e7609158c353c9029daf9f93da517a0c66a 100644 (file)
@@ -45,6 +45,7 @@
 #include <epan/proto.h>
 #include <epan/column.h>
 #include "print.h"
+#include "file_util.h"
 
 #include <epan/prefs-int.h>
 
@@ -63,7 +64,7 @@ static void   free_col_info(e_prefs *);
 #define PF_NAME                "preferences"
 #define OLD_GPF_NAME   "ethereal.conf" /* old name for global preferences file */
 
-static gboolean init_prefs = TRUE;
+static gboolean prefs_initialized = FALSE;
 static gchar *gpf_path = NULL;
 
 /*
@@ -77,27 +78,27 @@ static int mgcp_udp_port_count;
 
 e_prefs prefs;
 
-static gchar   *gui_ptree_line_style_text[] =
+static const gchar     *gui_ptree_line_style_text[] =
        { "NONE", "SOLID", "DOTTED", "TABBED", NULL };
 
-static gchar   *gui_ptree_expander_style_text[] =
+static const gchar     *gui_ptree_expander_style_text[] =
        { "NONE", "SQUARE", "TRIANGLE", "CIRCULAR", NULL };
 
-static gchar   *gui_hex_dump_highlight_style_text[] =
+static const gchar     *gui_hex_dump_highlight_style_text[] =
        { "BOLD", "INVERSE", NULL };
 
-static gchar   *gui_console_open_text[] =
+static const gchar     *gui_console_open_text[] =
        { "NEVER", "AUTOMATIC", "ALWAYS", NULL };
 
-static gchar   *gui_fileopen_style_text[] =
+static const gchar     *gui_fileopen_style_text[] =
        { "LAST_OPENED", "SPECIFIED", NULL };
 
 /* GTK knows of two ways representing "both", vertical and horizontal aligned.
  * as this may not work on other guis, we use only "both" in general here */
-static gchar   *gui_toolbar_style_text[] =
+static const gchar     *gui_toolbar_style_text[] =
        { "ICONS", "TEXT", "BOTH", NULL };
 
-static gchar   *gui_layout_content_text[] =
+static const gchar     *gui_layout_content_text[] =
        { "NONE", "PLIST", "PDETAILS", "PBYTES", NULL };
 
 /*
@@ -311,7 +312,7 @@ find_module(const char *name)
 {
        GList *list_entry;
 
-       list_entry = g_list_find_custom(modules, (gpointer)name, module_match);
+       list_entry = g_list_find_custom(modules, name, module_match);
        if (list_entry == NULL)
                return NULL;    /* no such module */
        return (module_t *) list_entry->data;
@@ -404,7 +405,7 @@ register_preference(module_t *module, const char *name, const char *title,
     const char *description, pref_type_t type)
 {
        pref_t *preference;
-       const guchar *p;
+       const gchar *p;
 
        preference = g_malloc(sizeof (pref_t));
        preference->name = name;
@@ -427,8 +428,8 @@ register_preference(module_t *module, const char *name, const char *title,
         * and shouldn't require quoting, shifting, etc.
         */
        for (p = name; *p != '\0'; p++)
-               g_assert(isascii(*p) &&
-                   (islower(*p) || isdigit(*p) || *p == '_' || *p == '.'));
+               g_assert(isascii((guchar)*p) &&
+                   (islower((guchar)*p) || isdigit((guchar)*p) || *p == '_' || *p == '.'));
 
        /*
         * Make sure there's not already a preference with that
@@ -476,7 +477,7 @@ find_preference(module_t *module, const char *name)
 {
        GList *list_entry;
 
-       list_entry = g_list_find_custom(module->prefs, (gpointer)name,
+       list_entry = g_list_find_custom(module->prefs, name,
            preference_match);
        if (list_entry == NULL)
                return NULL;    /* no such preference */
@@ -487,7 +488,7 @@ find_preference(module_t *module, const char *name)
  * Returns TRUE if the given protocol has registered preferences
  */
 gboolean
-prefs_is_registered_protocol(char *name)
+prefs_is_registered_protocol(const char *name)
 {
        module_t *m = find_module(name);
 
@@ -498,7 +499,7 @@ prefs_is_registered_protocol(char *name)
  * Returns the module title of a registered protocol
  */
 const char *
-prefs_get_title_by_name(char *name)
+prefs_get_title_by_name(const char *name)
 {
        module_t *m = find_module(name);
 
@@ -556,7 +557,7 @@ prefs_register_enum_preference(module_t *module, const char *name,
  */
 void
 prefs_register_string_preference(module_t *module, const char *name,
-    const char *title, const char *description, char **var)
+    const char *title, const char *description, const char **var)
 {
        pref_t *preference;
 
@@ -867,7 +868,7 @@ find_val_for_string(const char *needle, const enum_val_t *haystack,
  * default value that was passed as the third argument is returned.
  */
 static int
-find_index_from_string_array(char *needle, char **haystack, int default_value)
+find_index_from_string_array(char *needle, const char **haystack, int default_value)
 {
        int i = 0;
 
@@ -897,6 +898,160 @@ print.file: /a/very/long/path/
 
 #define DEF_NUM_COLS    6
 
+/* Initialize preferences to wired-in default values.
+ * They may be overridden by the global preferences file or the
+ *  user's preferences file.
+ */
+static void
+init_prefs(void) {
+  int         i;
+  fmt_data    *cfmt;
+  const gchar *col_fmt[] = {"No.",      "%m", "Time",        "%t",
+                           "Source",   "%s", "Destination", "%d",
+                           "Protocol", "%p", "Info",        "%i"};
+
+  if (prefs_initialized)
+    return;
+
+  prefs.pr_format  = PR_FMT_TEXT;
+  prefs.pr_dest    = PR_DEST_CMD;
+  prefs.pr_file    = g_strdup("ethereal.out");
+  prefs.pr_cmd     = g_strdup("lpr");
+  prefs.col_list = NULL;
+  for (i = 0; i < DEF_NUM_COLS; i++) {
+    cfmt = (fmt_data *) g_malloc(sizeof(fmt_data));
+    cfmt->title = g_strdup(col_fmt[i * 2]);
+    cfmt->fmt   = g_strdup(col_fmt[(i * 2) + 1]);
+    prefs.col_list = g_list_append(prefs.col_list, cfmt);
+  }
+  prefs.num_cols  = DEF_NUM_COLS;
+  prefs.st_client_fg.pixel =     0;
+  prefs.st_client_fg.red   = 32767;
+  prefs.st_client_fg.green =     0;
+  prefs.st_client_fg.blue  =     0;
+  prefs.st_client_bg.pixel =     0;
+  prefs.st_client_bg.red   = 64507;
+  prefs.st_client_bg.green = 60909;
+  prefs.st_client_bg.blue  = 60909;
+  prefs.st_server_fg.pixel =     0;
+  prefs.st_server_fg.red   =     0;
+  prefs.st_server_fg.green =     0;
+  prefs.st_server_fg.blue  = 32767;
+  prefs.st_server_bg.pixel =     0;
+  prefs.st_server_bg.red   = 60909;
+  prefs.st_server_bg.green = 60909;
+  prefs.st_server_bg.blue  = 64507;
+  prefs.gui_scrollbar_on_right = TRUE;
+  prefs.gui_plist_sel_browse = FALSE;
+  prefs.gui_ptree_sel_browse = FALSE;
+  prefs.gui_altern_colors = FALSE;
+  prefs.gui_ptree_line_style = 0;
+  prefs.gui_ptree_expander_style = 1;
+  prefs.gui_hex_dump_highlight_style = 1;
+  prefs.filter_toolbar_show_in_statusbar = FALSE;
+  prefs.gui_toolbar_main_style = TB_STYLE_ICONS;
+#ifdef _WIN32
+  /* XXX - not sure, if it must be "Lucida Console" or "lucida console"
+   * for gui_font_name1. Maybe it's dependant on the windows version running?!
+   * verified on XP: "Lucida Console"
+   * unknown for other windows versions.
+   *
+   * Problem: if we have no preferences file, and the default font name is unknown, 
+   * we cannot save Preferences as an error dialog pops up "You have not selected a font".
+   */
+  prefs.gui_font_name1 = g_strdup("-*-Lucida Console-medium-r-*-*-*-100-*-*-*-*-*-*");
+  prefs.gui_font_name2 = g_strdup("Lucida Console 10");
+#else
+  /*
+   * XXX - for now, we make the initial font name a pattern that matches
+   * only ISO 8859/1 fonts, so that we don't match 2-byte fonts such
+   * as ISO 10646 fonts.
+   *
+   * Users in locales using other one-byte fonts will have to choose
+   * a different font from the preferences dialog - or put the font
+   * selection in the global preferences file to make that font the
+   * default for all users who don't explicitly specify a different
+   * font.
+   *
+   * Making this a font set rather than a font has two problems:
+   *
+   *   1) as far as I know, you can't select font sets with the
+   *      font selection dialog;
+   *
+   *  2) if you use a font set, the text to be drawn must be a
+   *      multi-byte string in the appropriate locale, but
+   *      Ethereal does *NOT* guarantee that's the case - in
+   *      the hex-dump window, each character in the text portion
+   *      of the display must be a *single* byte, and in the
+   *      packet-list and protocol-tree windows, text extracted
+   *      from the packet is not necessarily in the right format.
+   *
+   * "Doing this right" may, for the packet-list and protocol-tree
+   * windows, require that dissectors know what the locale is
+   * *AND* know what locale and text representation is used in
+   * the packets they're dissecting, and may be impossible in
+   * the hex-dump window (except by punting and displaying only
+   * ASCII characters).
+   *
+   * GTK+ 2.0 may simplify part of the problem, as it will, as I
+   * understand it, use UTF-8-encoded Unicode as its internal
+   * character set; however, we'd still have to know whatever
+   * character set and encoding is used in the packet (which
+   * may differ for different protocols, e.g. SMB might use
+   * PC code pages for some strings and Unicode for others, whilst
+   * NFS might use some UNIX character set encoding, e.g. ISO 8859/x,
+   * or one of the EUC character sets for Asian languages, or one
+   * of the other multi-byte character sets, or UTF-8, or...).
+   *
+   * I.e., as far as I can tell, "internationalizing" the packet-list,
+   * protocol-tree, and hex-dump windows involves a lot more than, say,
+   * just using font sets rather than fonts.
+   */
+  prefs.gui_font_name1 = g_strdup("-misc-fixed-medium-r-semicondensed-*-*-100-*-*-*-*-iso8859-1");
+  /* XXX- is this the correct default font name for GTK2 none win32? */
+  prefs.gui_font_name2 = g_strdup("Monospace 10");
+#endif
+  prefs.gui_marked_fg.pixel        =     65535;
+  prefs.gui_marked_fg.red          =     65535;
+  prefs.gui_marked_fg.green        =     65535;
+  prefs.gui_marked_fg.blue         =     65535;
+  prefs.gui_marked_bg.pixel        =         0;
+  prefs.gui_marked_bg.red          =         0;
+  prefs.gui_marked_bg.green        =         0;
+  prefs.gui_marked_bg.blue         =         0;
+  prefs.gui_geometry_save_position =         0;
+  prefs.gui_geometry_save_size     =         1;
+  prefs.gui_geometry_save_maximized=         1;
+  prefs.gui_console_open           = console_open_never;
+  prefs.gui_fileopen_style         = FO_STYLE_LAST_OPENED;
+  prefs.gui_recent_files_count_max = 10;
+  prefs.gui_fileopen_dir           = g_strdup("");
+  prefs.gui_fileopen_preview       = 3;
+  prefs.gui_ask_unsaved            = TRUE;
+  prefs.gui_find_wrap              = TRUE;
+  prefs.gui_webbrowser             = g_strdup(HTML_VIEWER " %s");
+  prefs.gui_window_title           = g_strdup("");
+  prefs.gui_layout_type            = layout_type_5;
+  prefs.gui_layout_content_1       = layout_pane_content_plist;
+  prefs.gui_layout_content_2       = layout_pane_content_pdetails;
+  prefs.gui_layout_content_3       = layout_pane_content_pbytes;
+  prefs.console_log_level          =
+      G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR;
+
+/* set the default values for the capture dialog box */
+  prefs.capture_device           = NULL;
+  prefs.capture_devices_descr    = NULL;
+  prefs.capture_devices_hide     = NULL;
+  prefs.capture_prom_mode        = TRUE;
+  prefs.capture_real_time        = FALSE;
+  prefs.capture_auto_scroll      = FALSE;
+  prefs.capture_show_info        = TRUE;
+  prefs.name_resolve             = RESOLV_ALL ^ RESOLV_NETWORK;
+  prefs.name_resolve_concurrency = 500;
+
+  prefs_initialized = TRUE;
+}
+
 
 /* Read the preferences file, fill in "prefs", and return a pointer to it.
 
@@ -914,154 +1069,11 @@ read_prefs(int *gpf_errno_return, int *gpf_read_errno_return,
           char **gpf_path_return, int *pf_errno_return,
           int *pf_read_errno_return, char **pf_path_return)
 {
-  int         i;
   int         err;
-  char       *pf_path;
-  FILE       *pf;
-  fmt_data   *cfmt;
-  gchar      *col_fmt[] = {"No.",      "%m", "Time",        "%t",
-                           "Source",   "%s", "Destination", "%d",
-                           "Protocol", "%p", "Info",        "%i"};
-
-  if (init_prefs) {
-    /* Initialize preferences to wired-in default values.
-       They may be overridden by the global preferences file or the
-       user's preferences file. */
-    init_prefs       = FALSE;
-    prefs.pr_format  = PR_FMT_TEXT;
-    prefs.pr_dest    = PR_DEST_CMD;
-    prefs.pr_file    = g_strdup("ethereal.out");
-    prefs.pr_cmd     = g_strdup("lpr");
-    prefs.col_list = NULL;
-    for (i = 0; i < DEF_NUM_COLS; i++) {
-      cfmt = (fmt_data *) g_malloc(sizeof(fmt_data));
-      cfmt->title = g_strdup(col_fmt[i * 2]);
-      cfmt->fmt   = g_strdup(col_fmt[(i * 2) + 1]);
-      prefs.col_list = g_list_append(prefs.col_list, cfmt);
-    }
-    prefs.num_cols  = DEF_NUM_COLS;
-    prefs.st_client_fg.pixel =     0;
-    prefs.st_client_fg.red   = 32767;
-    prefs.st_client_fg.green =     0;
-    prefs.st_client_fg.blue  =     0;
-    prefs.st_client_bg.pixel =     0;
-    prefs.st_client_bg.red   = 64507;
-    prefs.st_client_bg.green = 60909;
-    prefs.st_client_bg.blue  = 60909;
-    prefs.st_server_fg.pixel =     0;
-    prefs.st_server_fg.red   =     0;
-    prefs.st_server_fg.green =     0;
-    prefs.st_server_fg.blue  = 32767;
-    prefs.st_server_bg.pixel =     0;
-    prefs.st_server_bg.red   = 60909;
-    prefs.st_server_bg.green = 60909;
-    prefs.st_server_bg.blue  = 64507;
-    prefs.gui_scrollbar_on_right = TRUE;
-    prefs.gui_plist_sel_browse = FALSE;
-    prefs.gui_ptree_sel_browse = FALSE;
-    prefs.gui_altern_colors = FALSE;
-    prefs.gui_ptree_line_style = 0;
-    prefs.gui_ptree_expander_style = 1;
-    prefs.gui_hex_dump_highlight_style = 1;
-    prefs.filter_toolbar_show_in_statusbar = FALSE;
-    prefs.gui_toolbar_main_style = TB_STYLE_ICONS;
-#ifdef _WIN32
-    /* XXX - not sure, if it must be "Lucida Console" or "lucida console"
-     * for gui_font_name1. Maybe it's dependant on the windows version running?!
-     * verified on XP: "Lucida Console"
-     * unknown for other windows versions.
-     *
-     * Problem: if we have no preferences file, and the default font name is unknown, 
-     * we cannot save Preferences as an error dialog pops up "You have not selected a font".
-     */
-    prefs.gui_font_name1 = g_strdup("-*-Lucida Console-medium-r-*-*-*-100-*-*-*-*-*-*");
-    prefs.gui_font_name2 = g_strdup("Lucida Console 10");
-#else
-    /*
-     * XXX - for now, we make the initial font name a pattern that matches
-     * only ISO 8859/1 fonts, so that we don't match 2-byte fonts such
-     * as ISO 10646 fonts.
-     *
-     * Users in locales using other one-byte fonts will have to choose
-     * a different font from the preferences dialog - or put the font
-     * selection in the global preferences file to make that font the
-     * default for all users who don't explicitly specify a different
-     * font.
-     *
-     * Making this a font set rather than a font has two problems:
-     *
-     * 1) as far as I know, you can't select font sets with the
-     *    font selection dialog;
-     *
-     *  2) if you use a font set, the text to be drawn must be a
-     *    multi-byte string in the appropriate locale, but
-     *    Ethereal does *NOT* guarantee that's the case - in
-     *    the hex-dump window, each character in the text portion
-     *    of the display must be a *single* byte, and in the
-     *    packet-list and protocol-tree windows, text extracted
-     *    from the packet is not necessarily in the right format.
-     *
-     * "Doing this right" may, for the packet-list and protocol-tree
-     * windows, require that dissectors know what the locale is
-     * *AND* know what locale and text representation is used in
-     * the packets they're dissecting, and may be impossible in
-     * the hex-dump window (except by punting and displaying only
-     * ASCII characters).
-     *
-     * GTK+ 2.0 may simplify part of the problem, as it will, as I
-     * understand it, use UTF-8-encoded Unicode as its internal
-     * character set; however, we'd still have to know whatever
-     * character set and encoding is used in the packet (which
-     * may differ for different protocols, e.g. SMB might use
-     * PC code pages for some strings and Unicode for others, whilst
-     * NFS might use some UNIX character set encoding, e.g. ISO 8859/x,
-     * or one of the EUC character sets for Asian languages, or one
-     * of the other multi-byte character sets, or UTF-8, or...).
-     *
-     * I.e., as far as I can tell, "internationalizing" the packet-list,
-     * protocol-tree, and hex-dump windows involves a lot more than, say,
-     * just using font sets rather than fonts.
-     */
-    prefs.gui_font_name1 = g_strdup("-misc-fixed-medium-r-semicondensed-*-*-120-*-*-*-*-iso8859-1");
-    /* XXX- is this the correct default font name for GTK2 none win32? */
-    prefs.gui_font_name2 = g_strdup("fixed medium 12");
-#endif
-    prefs.gui_marked_fg.pixel        =     65535;
-    prefs.gui_marked_fg.red          =     65535;
-    prefs.gui_marked_fg.green        =     65535;
-    prefs.gui_marked_fg.blue         =     65535;
-    prefs.gui_marked_bg.pixel        =         0;
-    prefs.gui_marked_bg.red          =         0;
-    prefs.gui_marked_bg.green        =         0;
-    prefs.gui_marked_bg.blue         =         0;
-    prefs.gui_geometry_save_position =         0;
-    prefs.gui_geometry_save_size     =         1;
-    prefs.gui_geometry_save_maximized=         1;
-    prefs.gui_console_open           = console_open_never;
-    prefs.gui_fileopen_style         = FO_STYLE_LAST_OPENED;
-    prefs.gui_recent_files_count_max = 10;
-    prefs.gui_fileopen_dir           = g_strdup("");
-    prefs.gui_fileopen_preview       = 3;
-    prefs.gui_ask_unsaved            = TRUE;
-    prefs.gui_find_wrap              = TRUE;
-    prefs.gui_webbrowser             = g_strdup("mozilla %s");
-    prefs.gui_window_title           = g_strdup("");
-    prefs.gui_layout_type            = layout_type_5;
-    prefs.gui_layout_content_1       = layout_pane_content_plist;
-    prefs.gui_layout_content_2       = layout_pane_content_pdetails;
-    prefs.gui_layout_content_3       = layout_pane_content_pbytes;
+  char        *pf_path;
+  FILE        *pf;
 
-/* set the default values for the capture dialog box */
-    prefs.capture_device           = NULL;
-    prefs.capture_devices_descr    = NULL;
-    prefs.capture_devices_hide     = NULL;
-    prefs.capture_prom_mode        = TRUE;
-    prefs.capture_real_time        = FALSE;
-    prefs.capture_auto_scroll      = FALSE;
-    prefs.capture_show_info        = TRUE;
-    prefs.name_resolve             = RESOLV_ALL ^ RESOLV_NETWORK;
-    prefs.name_resolve_concurrency = 500;
-  }
+  init_prefs();
 
   /*
    * If we don't already have the pathname of the global preferences
@@ -1073,19 +1085,19 @@ read_prefs(int *gpf_errno_return, int *gpf_read_errno_return,
      * file doesn't exist, try the old path.
      */
     gpf_path = get_datafile_path(PF_NAME);
-    if ((pf = fopen(gpf_path, "r")) == NULL && errno == ENOENT) {
+    if ((pf = eth_fopen(gpf_path, "r")) == NULL && errno == ENOENT) {
       /*
        * It doesn't exist by the new name; try the old name.
        */
       g_free(gpf_path);
       gpf_path = get_datafile_path(OLD_GPF_NAME);
-      pf = fopen(gpf_path, "r");
+      pf = eth_fopen(gpf_path, "r");
     }
   } else {
     /*
      * We have the path; try it.
      */
-    pf = fopen(gpf_path, "r");
+    pf = eth_fopen(gpf_path, "r");
   }
 
   /*
@@ -1128,7 +1140,7 @@ read_prefs(int *gpf_errno_return, int *gpf_read_errno_return,
 
   /* Read the user's preferences file, if it exists. */
   *pf_path_return = NULL;
-  if ((pf = fopen(pf_path, "r")) != NULL) {
+  if ((pf = eth_fopen(pf_path, "r")) != NULL) {
     /*
      * Start out the counters of "mgcp.{tcp,udp}.port" entries we've
      * seen.
@@ -1169,49 +1181,28 @@ read_prefs_file(const char *pf_path, FILE *pf, pref_set_pair_cb pref_set_pair_fc
 {
   enum { START, IN_VAR, PRE_VAL, IN_VAL, IN_SKIP };
   int       got_c, state = START;
-  static guint  cur_pref_val_size;
-  static gchar* cur_val = NULL;
-  static guint  cur_pref_var_size;
-  static gchar* cur_var = NULL;
+  GString  *cur_val;
+  GString  *cur_var;
   gboolean  got_val = FALSE;
-  gint      var_len = 0, val_len = 0, fline = 1, pline = 1;
+  gint      fline = 1, pline = 1;
   gchar     hint[] = "(saving your preferences once should remove this warning)";
 
-  if (! cur_val) {
-         cur_pref_val_size = 128;
-         cur_val = g_malloc(cur_pref_val_size);
-  }
-  
-  if (! cur_var) {
-         cur_pref_var_size = 128;
-         cur_var = g_malloc(cur_pref_var_size);
-  }
-  
+  cur_val = g_string_new("");
+  cur_var = g_string_new("");
+
   while ((got_c = getc(pf)) != EOF) {
     if (got_c == '\n') {
       state = START;
       fline++;
       continue;
     }
-    if (var_len >= cur_pref_var_size) {
-               cur_pref_var_size *= 2;
-               cur_var = g_realloc(cur_var,cur_pref_val_size);
-      continue;
-    }
-    if (val_len >= cur_pref_val_size) {
-               cur_pref_val_size *= 2;
-               cur_val = g_realloc(cur_val,cur_pref_val_size);
-      continue;
-    }
 
     switch (state) {
       case START:
         if (isalnum(got_c)) {
-          if (var_len > 0) {
+          if (cur_var->len > 0) {
             if (got_val) {
-              cur_var[var_len] = '\0';
-              cur_val[val_len] = '\0';
-              switch (pref_set_pair_fct(cur_var, cur_val)) {
+              switch (pref_set_pair_fct(cur_var->str, cur_val->str)) {
 
              case PREFS_SET_SYNTAX_ERR:
                 g_warning ("%s line %d: Syntax error %s", pf_path, pline, hint);
@@ -1219,7 +1210,7 @@ read_prefs_file(const char *pf_path, FILE *pf, pref_set_pair_cb pref_set_pair_fc
 
              case PREFS_SET_NO_SUCH_PREF:
                 g_warning ("%s line %d: No such preference \"%s\" %s", pf_path,
-                               pline, cur_var, hint);
+                               pline, cur_var->str, hint);
                 break;
 
              case PREFS_SET_OBSOLETE:
@@ -1235,10 +1226,10 @@ read_prefs_file(const char *pf_path, FILE *pf, pref_set_pair_cb pref_set_pair_fc
           }
           state      = IN_VAR;
           got_val    = FALSE;
-          cur_var[0] = got_c;
-          var_len    = 1;
+          g_string_truncate(cur_var, 0);
+          g_string_append_c(cur_var, (gchar) got_c);
           pline = fline;
-        } else if (isspace(got_c) && var_len > 0 && got_val) {
+        } else if (isspace(got_c) && cur_var->len > 0 && got_val) {
           state = PRE_VAL;
         } else if (got_c == '#') {
           state = IN_SKIP;
@@ -1248,38 +1239,33 @@ read_prefs_file(const char *pf_path, FILE *pf, pref_set_pair_cb pref_set_pair_fc
         break;
       case IN_VAR:
         if (got_c != ':') {
-          cur_var[var_len] = got_c;
-          var_len++;
+          g_string_append_c(cur_var, (gchar) got_c);
         } else {
           state   = PRE_VAL;
-          val_len = 0;
+          g_string_truncate(cur_val, 0);
           got_val = TRUE;
         }
         break;
       case PRE_VAL:
         if (!isspace(got_c)) {
           state = IN_VAL;
-          cur_val[val_len] = got_c;
-          val_len++;
+          g_string_append_c(cur_val, (gchar) got_c);
         }
         break;
       case IN_VAL:
         if (got_c != '#')  {
-          cur_val[val_len] = got_c;
-          val_len++;
+          g_string_append_c(cur_val, (gchar) got_c);
         } else {
-          while (isspace((guchar)cur_val[val_len]) && val_len > 0)
-            val_len--;
+          while (isspace((guchar)cur_val->str[cur_val->len]) && cur_val->len > 0)
+            g_string_truncate(cur_val, cur_val->len - 1);
           state = IN_SKIP;
         }
         break;
     }
   }
-  if (var_len > 0) {
+  if (cur_var->len > 0) {
     if (got_val) {
-      cur_var[var_len] = '\0';
-      cur_val[val_len] = '\0';
-      switch (pref_set_pair_fct(cur_var, cur_val)) {
+      switch (pref_set_pair_fct(cur_var->str, cur_val->str)) {
 
       case PREFS_SET_SYNTAX_ERR:
         g_warning ("%s line %d: Syntax error %s", pf_path, pline, hint);
@@ -1287,7 +1273,7 @@ read_prefs_file(const char *pf_path, FILE *pf, pref_set_pair_cb pref_set_pair_fc
 
       case PREFS_SET_NO_SUCH_PREF:
         g_warning ("%s line %d: No such preference \"%s\" %s", pf_path,
-                       pline, cur_var, hint);
+                       pline, cur_var->str, hint);
         break;
 
       case PREFS_SET_OBSOLETE:
@@ -1300,6 +1286,10 @@ read_prefs_file(const char *pf_path, FILE *pf, pref_set_pair_cb pref_set_pair_fc
       g_warning ("%s line %d: Incomplete preference %s", pf_path, pline, hint);
     }
   }
+
+  g_string_free(cur_val, TRUE);
+  g_string_free(cur_var, TRUE);
+
   if (ferror(pf))
     return errno;
   else
@@ -1315,7 +1305,7 @@ read_prefs_file(const char *pf_path, FILE *pf, pref_set_pair_cb pref_set_pair_fc
 int
 prefs_set_pref(char *prefarg)
 {
-       guchar *p, *colonp;
+       gchar *p, *colonp;
        int ret;
 
        /*
@@ -1340,7 +1330,7 @@ prefs_set_pref(char *prefarg)
         * as we allow it in the preferences file, we might as well
         * allow it here).
         */
-       while (isspace(*p))
+       while (isspace((guchar)*p))
                p++;
        if (*p == '\0') {
                /*
@@ -1401,6 +1391,7 @@ prefs_set_pref(char *prefarg)
 #define PRS_GUI_LAYOUT_CONTENT_1         "gui.layout_content_1"
 #define PRS_GUI_LAYOUT_CONTENT_2         "gui.layout_content_2"
 #define PRS_GUI_LAYOUT_CONTENT_3         "gui.layout_content_3"
+#define PRS_CONSOLE_LOG_LEVEL           "console.log.level"
 
 /*
  * This applies to more than just captures, so it's not "capture.name_resolve";
@@ -1426,8 +1417,8 @@ prefs_set_pref(char *prefarg)
 #define GREEN_COMPONENT(x) (guint16) (((((x) >>  8) & 0xff) * 65535 / 255))
 #define BLUE_COMPONENT(x)  (guint16) ( (((x)        & 0xff) * 65535 / 255))
 
-static gchar *pr_formats[] = { "text", "postscript" };
-static gchar *pr_dests[]   = { "command", "file" };
+static const gchar *pr_formats[] = { "text", "postscript" };
+static const gchar *pr_dests[]   = { "command", "file" };
 
 typedef struct {
   char    letter;
@@ -1443,7 +1434,7 @@ static name_resolve_opt_t name_resolve_opt[] = {
 
 #define N_NAME_RESOLVE_OPT     (sizeof name_resolve_opt / sizeof name_resolve_opt[0])
 
-static char *
+static const char *
 name_resolve_to_string(guint32 name_resolve)
 {
   static char string[N_NAME_RESOLVE_OPT+1];
@@ -1753,7 +1744,9 @@ set_pref(gchar *pref_name, gchar *value)
   } else if (strcmp(pref_name, PRS_GUI_LAYOUT_CONTENT_3) == 0) {
     prefs.gui_layout_content_3 =
        find_index_from_string_array(value, gui_layout_content_text, 0);
-
+  } else if (strcmp(pref_name, PRS_CONSOLE_LOG_LEVEL) == 0) {
+    prefs.console_log_level = strtoul(value, NULL, 10);
+        
 /* handle the capture options */
   } else if (strcmp(pref_name, PRS_CAP_DEVICE) == 0) {
     if (prefs.capture_device != NULL)
@@ -2068,7 +2061,7 @@ set_pref(gchar *pref_name, gchar *value)
     case PREF_STRING:
       if (strcmp(*pref->varp.string, value) != 0) {
         module->prefs_changed = TRUE;
-        g_free(*pref->varp.string);
+        g_free((void *)*pref->varp.string);
         *pref->varp.string = g_strdup(value);
       }
       break;
@@ -2199,7 +2192,6 @@ write_pref(gpointer data, gpointer user_data)
                fprintf(arg->pf, "# A string denoting an positive integer range (e.g., \"1-20,30-40\").\n");
                fprintf(arg->pf, "%s.%s: %s\n", arg->module->name, pref->name,
                        range_string);
-               g_free(range_string);
                break;
        }
 
@@ -2221,6 +2213,8 @@ write_module_prefs(gpointer data, gpointer user_data)
 
 /* Write out "prefs" to the user's preferences file, and return 0.
 
+   If the preferences file path is NULL, write to stdout.
+
    If we got an error, stuff a pointer to the path of the preferences file
    into "*pf_path_return", and return the errno. */
 int
@@ -2231,16 +2225,23 @@ write_prefs(char **pf_path_return)
   GList       *clp, *col_l;
   fmt_data    *cfmt;
 
+  /* Needed for "-G defaultprefs" */
+  init_prefs();
+
   /* To do:
    * - Split output lines longer than MAX_VAL_LEN
    * - Create a function for the preference directory check/creation
    *   so that duplication can be avoided with filter.c
    */
 
-  pf_path = get_persconffile_path(PF_NAME, TRUE);
-  if ((pf = fopen(pf_path, "w")) == NULL) {
-    *pf_path_return = pf_path;
-    return errno;
+  if (pf_path_return != NULL) {
+    pf_path = get_persconffile_path(PF_NAME, TRUE);
+    if ((pf = eth_fopen(pf_path, "w")) == NULL) {
+      *pf_path_return = pf_path;
+      return errno;
+    }
+  } else {
+    pf = stdout;
   }
 
   fputs("# Configuration file for Ethereal " VERSION ".\n"
@@ -2427,6 +2428,19 @@ write_prefs(char **pf_path_return)
     (prefs.st_server_bg.green * 255 / 65535),
     (prefs.st_server_bg.blue * 255 / 65535));
 
+  fprintf(pf, "\n######## Console: logging level ########\n");
+  fprintf(pf, "# (debugging only, not in the Preferences dialog)\n");
+  fprintf(pf, "# A bitmask of glib log levels:\n"
+          "# G_LOG_LEVEL_ERROR    = 4\n"
+          "# G_LOG_LEVEL_CRITICAL = 8\n"
+          "# G_LOG_LEVEL_WARNING  = 16\n"
+          "# G_LOG_LEVEL_MESSAGE  = 32\n"
+          "# G_LOG_LEVEL_INFO     = 64\n"
+          "# G_LOG_LEVEL_DEBUG    = 128\n");
+
+  fprintf(pf, PRS_CONSOLE_LOG_LEVEL ": %u\n",
+          prefs.console_log_level);
+
   fprintf(pf, "\n####### Capture ########\n");
   
   if (prefs.capture_device != NULL) {
@@ -2559,6 +2573,7 @@ copy_prefs(e_prefs *dest, e_prefs *src)
   dest->gui_geometry_save_maximized = src->gui_geometry_save_maximized;
   dest->gui_webbrowser = g_strdup(src->gui_webbrowser);
   dest->gui_window_title = g_strdup(src->gui_window_title);
+  dest->console_log_level = src->console_log_level;
 /*  values for the capture dialog box */
   dest->capture_device = g_strdup(src->capture_device);
   dest->capture_devices_descr = g_strdup(src->capture_devices_descr);