Add support for a global "ethereal.conf" preferences file, stored in the

same directory as the "manuf" file ("/etc" or "/usr/local/etc", most
likely).

Add a mechanism to allow modules (e.g., dissectors) to register
preference values, which:

	can be put into the global or the user's preference file;

	can be set from the command line, with arguments to the "-o"
	flag;

	can be set from tabs in the "Preferences" dialog box.

Use that mechanism to register the "Decode IPv4 TOS field as DiffServ
field" variable for IP as a preference.

Stuff that still needs to be done:

	documenting the API for registering preferences;

	documenting the "-o" values in the man page (probably needs a
	flag similar to "-G", and a Perl script to turn the output into
	documentation as is done with the list of field);

	handling error checking for numeric values (range checking,
	making sure that if the user changes the variable from the GUI
	they change it to a valid numeric value);

	using the callbacks to, for example, update the display when
	preferences are changed (could be expensive);

	panic if the user specifies a numeric value with a base other
	than 10, 8, or 16.

We may also want to clean up the existing wired-in preferences not to
take effect the instant you tweak the widget, and to add an "Apply"
button to the "Preferences" dialog.

svn path=/trunk/; revision=2117
This commit is contained in:
Guy Harris 2000-07-05 09:41:07 +00:00
parent ed5651a909
commit b1f950b377
8 changed files with 1112 additions and 91 deletions

View File

@ -1,7 +1,7 @@
# Makefile.am
# Automake file for Ethereal
#
# $Id: Makefile.am,v 1.206 2000/06/22 06:37:59 guy Exp $
# $Id: Makefile.am,v 1.207 2000/07/05 09:40:37 guy Exp $
#
# Ethereal - Network traffic analyzer
# By Gerald Combs <gerald@zing.org>
@ -274,6 +274,7 @@ ETHEREAL_COMMON_SOURCES = \
ppptypes.h \
prefs.c \
prefs.h \
prefs-int.h \
print.c \
print.h \
proto.c \

View File

@ -1,6 +1,6 @@
/* main.c
*
* $Id: main.c,v 1.127 2000/07/05 02:04:16 guy Exp $
* $Id: main.c,v 1.128 2000/07/05 09:41:04 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -1144,15 +1144,16 @@ print_usage(void) {
fprintf(stderr, "%s [ -vh ] [ -kQS ] [ -b <bold font> ] [ -B <byte view height> ]\n",
PACKAGE);
fprintf(stderr, "\t[ -c count ] [ -D ] [ -f <capture filter> ] [ -i interface ]\n");
fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
fprintf(stderr, "\t[ -R <read filter> ] [ -s snaplen ] [ -t <time stamp format> ]\n");
fprintf(stderr, "\t[ -T <tree view height> ] [ -w savefile ]\n");
fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -o <preference setting> ] ...\n");
fprintf(stderr, "\t[ -P <packet list height> ] [ -r infile ] [ -R <read filter> ]\n");
fprintf(stderr, "\t[ -s snaplen ] [ -t <time stamp format> ] [ -T <tree view height> ]\n");
fprintf(stderr, "\t[ -w savefile ]\n");
#else
fprintf(stderr, "%s [ -vh ] [ -b <bold font> ] [ -B <byte view height> ]\n",
PACKAGE);
fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
fprintf(stderr, "\t[ -R <read filter> ] [ -t <time stamp format> ]\n");
fprintf(stderr, "\t[ -T <tree view height> ]\n");
fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -o <preference setting ] ...\n");
fprintf(stderr, "\t[ -P <packet list height> ] [ -r infile ] [ -R <read filter> ]\n");
fprintf(stderr, "\t[ -t <time stamp format> ] [ -T <tree view height> ]\n");
#endif
}
@ -1175,8 +1176,8 @@ main(int argc, char *argv[])
extern char pcap_version[];
#endif
#endif
char *pf_path;
int pf_open_errno = 0;
char *gpf_path, *pf_path;
int gpf_open_errno, pf_open_errno;
int err;
#ifdef HAVE_LIBPCAP
gboolean start_capture = FALSE;
@ -1201,6 +1202,16 @@ main(int argc, char *argv[])
capture_child = (strcmp(command_name, CHILD_NAME) == 0);
#endif
/* Register all dissectors; we must do this before checking for the
"-G" flag, as the "-G" flag dumps a list of fields registered
by the dissectors, and we must do it before we read the preferences,
in case any dissectors register preferences. */
dissect_init();
/* Now register the preferences for any non-dissector modules.
We must do that before we read the preferences as well. */
prefs_register_modules();
/* If invoked with the "-G" flag, we dump out a glossary of
display filter symbols.
@ -1221,7 +1232,6 @@ main(int argc, char *argv[])
any arguments after the "-G" flag will not be used. */
if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
dissect_init();
proto_registrar_dump();
exit(0);
}
@ -1235,13 +1245,7 @@ main(int argc, char *argv[])
/* Let GTK get its args */
gtk_init (&argc, &argv);
prefs = read_prefs(&pf_path);
if (pf_path != NULL) {
/* The preferences file exists, but couldn't be opened; "pf_path" is
its pathname. Remember "errno", as that says why the attempt
failed. */
pf_open_errno = errno;
}
prefs = read_prefs(&gpf_open_errno, &gpf_path, &pf_open_errno, &pf_path);
/* Initialize the capture file struct */
cfile.plist = NULL;
@ -1312,7 +1316,7 @@ main(int argc, char *argv[])
);
/* Now get our args */
while ((opt = getopt(argc, argv, "b:B:c:Df:hi:km:nP:Qr:R:Ss:t:T:w:W:vZ:")) != EOF) {
while ((opt = getopt(argc, argv, "b:B:c:Df:hi:km:no:P:Qr:R:Ss:t:T:w:W:vZ:")) != EOF) {
switch (opt) {
case 'b': /* Bold font */
bold_font = g_strdup(optarg);
@ -1367,6 +1371,21 @@ main(int argc, char *argv[])
case 'n': /* No name resolution */
g_resolving_actif = 0;
break;
case 'o': /* Override preference from command line */
switch (prefs_set_pref(optarg)) {
case PREFS_SET_SYNTAX_ERR:
fprintf(stderr, "ethereal: Invalid -o flag \"%s\"\n", optarg);
exit(1);
break;
case PREFS_SET_NO_SUCH_PREF:
fprintf(stderr, "ethereal: -o flag \"%s\" specifies unknown preference\n",
optarg);
exit(1);
break;
}
break;
case 'P': /* Packet list pane height */
pl_size = atoi(optarg);
break;
@ -1541,12 +1560,6 @@ main(int argc, char *argv[])
create_main_window(pl_size, tv_size, bv_size, prefs);
/*
Hmmm should we do it here
*/
dissect_init(); /* Init anything that needs initializing */
#ifdef HAVE_LIBPCAP
/* Is this a "child" ethereal, which is only supposed to pop up a
capture box to let us stop the capture, and run a capture
@ -1611,12 +1624,21 @@ main(int argc, char *argv[])
}
#endif
/* If we failed to open the preferences file, pop up an alert box;
we defer it until now, so that the alert box is more likely to
come up on top of the main window. */
/* If the global preferences file exists but we failed to open it,
pop up an alert box; we defer that until now, so that the alert
box is more likely to come up on top of the main window. */
if (gpf_path != NULL) {
simple_dialog(ESD_TYPE_WARN, NULL,
"Could not open global preferences file\n\"%s\": %s.", gpf_path,
strerror(gpf_open_errno));
}
/* If the user's preferences file exists but we failed to open it,
pop up an alert box; we defer that until now, so that the alert
box is more likely to come up on top of the main window. */
if (pf_path != NULL) {
simple_dialog(ESD_TYPE_WARN, NULL,
"Could not open preferences file\n\"%s\": %s.", pf_path,
"Could not open your preferences file\n\"%s\": %s.", pf_path,
strerror(pf_open_errno));
}

View File

@ -1,7 +1,7 @@
/* prefs_dlg.c
* Routines for handling preferences
*
* $Id: prefs_dlg.c,v 1.13 2000/07/05 06:33:02 guy Exp $
* $Id: prefs_dlg.c,v 1.14 2000/07/05 09:41:07 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -59,6 +59,8 @@
#include "dlg_utils.h"
#include "simple_dialog.h"
#include "prefs-int.h"
static void prefs_main_ok_cb(GtkWidget *, gpointer);
static void prefs_main_save_cb(GtkWidget *, gpointer);
static void prefs_main_cancel_cb(GtkWidget *, gpointer);
@ -78,6 +80,154 @@ static void prefs_main_destroy_cb(GtkWidget *, gpointer);
*/
static GtkWidget *prefs_w;
static void
pref_show(pref_t *pref, gpointer user_data)
{
GtkWidget *main_tb = user_data;
const char *title;
char *label_string;
GtkWidget *label, *menu, *menu_item, *widget, *button;
GSList *rb_group;
char uint_str[10+1];
const enum_val *enum_valp;
int menu_index, index;
/* Give this preference a label which is its title, followed by a colon,
and left-align it. */
title = pref->title;
label_string = g_malloc(strlen(title) + 2);
strcpy(label_string, title);
strcat(label_string, ":");
label = gtk_label_new(label_string);
g_free(label_string);
gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
/* Attach it to the table. */
gtk_table_attach_defaults(GTK_TABLE(main_tb), label, 0, 1, pref->ordinal,
pref->ordinal+1);
/* Save the current value of the preference, so that we can revert it if
the user does "Apply" and then "Cancel", and create the control for
editing the preference. */
switch (pref->type) {
case PREF_UINT:
pref->saved_val.uint = *pref->varp.uint;
/* XXX - there are no uint spinbuttons, so we can't use a spinbutton.
Even more annoyingly, even if there were, GLib doesn't define
G_MAXUINT - but I think ANSI C may define UINT_MAX, so we could
use that. */
widget = gtk_entry_new();
switch (pref->info.base) {
case 10:
sprintf(uint_str, "%u", pref->saved_val.uint);
break;
case 8:
sprintf(uint_str, "%o", pref->saved_val.uint);
break;
case 16:
sprintf(uint_str, "%x", pref->saved_val.uint);
break;
}
gtk_entry_set_text(GTK_ENTRY(widget), uint_str);
pref->control = widget;
break;
case PREF_BOOL:
pref->saved_val.bool = *pref->varp.bool;
widget = gtk_check_button_new();
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(widget), pref->saved_val.bool);
pref->control = widget;
break;
case PREF_ENUM:
pref->saved_val.enumval = *pref->varp.enump;
if (pref->info.enum_info.radio_buttons) {
/* Show it as radio buttons. */
widget = gtk_hbox_new(FALSE, 0);
rb_group = NULL;
for (enum_valp = pref->info.enum_info.enumvals, index = 0;
enum_valp->name != NULL; enum_valp++, index++) {
button = gtk_radio_button_new_with_label(rb_group, enum_valp->name);
if (rb_group == NULL)
rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
gtk_box_pack_start(GTK_BOX(widget), button, FALSE, FALSE, 10);
if (enum_valp->value == pref->saved_val.enumval)
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE);
pref->control = button;
}
} else {
/* Show it as an option menu. */
menu = gtk_menu_new();
menu_index = -1;
for (enum_valp = pref->info.enum_info.enumvals, index = 0;
enum_valp->name != NULL; enum_valp++, index++) {
menu_item = gtk_menu_item_new_with_label(enum_valp->name);
gtk_menu_append(GTK_MENU(menu), menu_item);
if (enum_valp->value == pref->saved_val.enumval)
menu_index = index;
}
/* Create the option menu from the option */
widget = gtk_option_menu_new();
gtk_option_menu_set_menu(GTK_OPTION_MENU(widget), menu);
/* Set its current value to the variable's current value */
if (menu_index != -1)
gtk_option_menu_set_history(GTK_OPTION_MENU(widget), menu_index);
pref->control = widget;
}
break;
case PREF_STRING:
widget = gtk_entry_new();
if (pref->saved_val.string != NULL)
g_free(pref->saved_val.string);
pref->saved_val.string = g_strdup(*pref->varp.string);
gtk_entry_set_text(GTK_ENTRY(widget), pref->saved_val.string);
pref->control = widget;
break;
default:
g_assert_not_reached();
widget = NULL;
break;
}
gtk_table_attach_defaults(GTK_TABLE(main_tb), widget, 1, 2, pref->ordinal,
pref->ordinal+1);
}
static void
module_prefs_show(module_t *module, gpointer user_data)
{
GtkWidget *prefs_nb = user_data;
GtkWidget *main_vb, *main_tb, *label;
/* Main vertical box */
main_vb = gtk_vbox_new(FALSE, 5);
gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
/* Main table */
main_tb = gtk_table_new(module->numprefs, 2, FALSE);
gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
/* Add items for each of the preferences */
prefs_pref_foreach(module, pref_show, main_tb);
label = gtk_label_new(module->title);
gtk_notebook_append_page(GTK_NOTEBOOK(prefs_nb), main_vb, label);
/* Show 'em what we got */
gtk_widget_show_all(main_vb);
}
void
prefs_cb(GtkWidget *w, gpointer dummy) {
GtkWidget *main_vb, *top_hb, *bbox, *prefs_nb,
@ -136,6 +286,9 @@ prefs_cb(GtkWidget *w, gpointer dummy) {
label = gtk_label_new ("GUI");
gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), gui_pg, label);
/* Registered prefs */
prefs_module_foreach(module_prefs_show, prefs_nb);
/* Button row: OK and cancel buttons */
bbox = gtk_hbutton_box_new();
gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
@ -173,6 +326,109 @@ prefs_cb(GtkWidget *w, gpointer dummy) {
gtk_widget_show(prefs_w);
}
static void
pref_fetch(pref_t *pref, gpointer user_data)
{
GtkWidget *label;
char *label_string;
char *str_val;
char *p;
guint uval;
GSList *rb_entry;
GtkWidget *button;
/* Fetch the value of the preference, and set the appropriate variable
to it. */
switch (pref->type) {
case PREF_UINT:
str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
uval = strtoul(str_val, &p, pref->info.base);
#if 0
if (p == value || *p != '\0')
return PREFS_SET_SYNTAX_ERR; /* number was bad */
#endif
*pref->varp.uint = uval;
break;
case PREF_BOOL:
*pref->varp.bool = GTK_TOGGLE_BUTTON(pref->control)->active;
break;
case PREF_ENUM:
if (pref->info.enum_info.radio_buttons) {
/* Go through the list of of radio buttons in the group, and find
the first one that's active. */
button = NULL;
for (rb_entry = gtk_radio_button_group(GTK_RADIO_BUTTON(pref->control));
rb_entry != NULL;
rb_entry = g_slist_next(rb_entry)) {
button = rb_entry->data;
if (GTK_TOGGLE_BUTTON(button)->active)
break;
}
/* OK, now find that button's label. */
label = GTK_BIN(button)->child;
} else {
/* Get the label for the currently active entry in the option menu.
Yes, this is how you do it. See FAQ 6.8 in the GTK+ FAQ. */
label = GTK_BIN(pref->control)->child;
}
/* Get the label, and translate it to a value. */
gtk_label_get(GTK_LABEL(label), &label_string);
*pref->varp.enump = find_val_for_string(label_string,
pref->info.enum_info.enumvals, 1);
break;
case PREF_STRING:
str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
if (*pref->varp.string != NULL)
g_free(*pref->varp.string);
*pref->varp.string = g_strdup(str_val);
break;
}
}
static void
module_prefs_fetch(module_t *module, gpointer user_data)
{
/* For all preferences in this module, fetch its value from this
module's notebook page. */
prefs_pref_foreach(module, pref_fetch, NULL);
}
static void
pref_clean(pref_t *pref, gpointer user_data)
{
switch (pref->type) {
case PREF_UINT:
break;
case PREF_BOOL:
break;
case PREF_ENUM:
break;
case PREF_STRING:
if (pref->saved_val.string != NULL) {
g_free(pref->saved_val.string);
pref->saved_val.string = NULL;
}
break;
}
}
static void
module_prefs_clean(module_t *module, gpointer user_data)
{
/* For all preferences in this module, clean up any cruft allocated for
use by the GUI code. */
prefs_pref_foreach(module, pref_clean, NULL);
}
static void
prefs_main_ok_cb(GtkWidget *ok_bt, gpointer parent_w)
{
@ -180,6 +436,8 @@ prefs_main_ok_cb(GtkWidget *ok_bt, gpointer parent_w)
column_prefs_ok(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
stream_prefs_ok(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
gui_prefs_ok(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
prefs_module_foreach(module_prefs_fetch, NULL);
prefs_module_foreach(module_prefs_clean, NULL);
gtk_widget_destroy(GTK_WIDGET(parent_w));
}
@ -193,6 +451,7 @@ prefs_main_save_cb(GtkWidget *save_bt, gpointer parent_w)
column_prefs_save(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
stream_prefs_save(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
gui_prefs_save(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
prefs_module_foreach(module_prefs_fetch, NULL);
err = write_prefs(&pf_path);
if (err != 0) {
simple_dialog(ESD_TYPE_WARN, NULL,
@ -201,6 +460,41 @@ prefs_main_save_cb(GtkWidget *save_bt, gpointer parent_w)
}
}
static void
pref_revert(pref_t *pref, gpointer user_data)
{
/* Fetch the value of the preference, and set the appropriate variable
to it. */
switch (pref->type) {
case PREF_UINT:
*pref->varp.uint = pref->saved_val.uint;
break;
case PREF_BOOL:
*pref->varp.bool = pref->saved_val.bool;
break;
case PREF_ENUM:
*pref->varp.enump = pref->saved_val.enumval;
break;
case PREF_STRING:
if (*pref->varp.string != NULL)
g_free(*pref->varp.string);
*pref->varp.string = g_strdup(pref->saved_val.string);
break;
}
}
static void
module_prefs_revert(module_t *module, gpointer user_data)
{
/* For all preferences in this module, revert its value to the value
it had when we popped up the Preferences dialog. */
prefs_pref_foreach(module, pref_revert, NULL);
}
static void
prefs_main_cancel_cb(GtkWidget *cancel_bt, gpointer parent_w)
{
@ -208,6 +502,7 @@ prefs_main_cancel_cb(GtkWidget *cancel_bt, gpointer parent_w)
column_prefs_cancel(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
stream_prefs_cancel(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
gui_prefs_cancel(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
prefs_module_foreach(module_prefs_revert, NULL);
gtk_widget_destroy(GTK_WIDGET(parent_w));
}

View File

@ -1,7 +1,7 @@
/* packet-ip.c
* Routines for IP and miscellaneous IP protocol packet disassembly
*
* $Id: packet-ip.c,v 1.94 2000/06/20 13:21:55 gram Exp $
* $Id: packet-ip.c,v 1.95 2000/07/05 09:40:38 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -40,6 +40,7 @@
#include <glib.h>
#include "packet.h"
#include "resolv.h"
#include "prefs.h"
#ifdef NEED_SNPRINTF_H
# ifdef HAVE_STDARG_H
@ -1390,6 +1391,7 @@ proto_register_ip(void)
&ett_ip_option_route,
&ett_ip_option_timestamp,
};
module_t *ip_module;
proto_ip = proto_register_protocol ("Internet Protocol", "ip");
proto_register_field_array(proto_ip, hf, array_length(hf));
@ -1397,6 +1399,13 @@ proto_register_ip(void)
/* subdissector code */
ip_dissector_table = register_dissector_table("ip.proto");
/* Register a configuration option for decoding TOS as DSCP */
ip_module = prefs_register_module("ip", "IP", NULL);
prefs_register_bool_preference(ip_module, "decode_tos_as_diffserv",
"Decode IPv4 TOS field as DiffServ field",
"Whether the IPv4 type-of-service field should be decoded as a Differentiated Services field",
&g_ip_dscp_actif);
}
void

79
prefs-int.h Normal file
View File

@ -0,0 +1,79 @@
/* prefs-int.h
* Definitions for implementation of preference handling routines;
* used by "friends" of the preferences type.
*
* $Id: prefs-int.h,v 1.1 2000/07/05 09:40:40 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
* Copyright 1998 Gerald Combs
*
*
* 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 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.
*/
#ifndef __PREFS_INT_H__
#define __PREFS_INT_H__
struct pref_module {
const char *name; /* name of module */
const char *title; /* title of module (displayed in preferences notebook) */
void (*apply_cb)(void); /* routine to call when preferences applied */
GList *prefs; /* list of its preferences */
int numprefs; /* number of preferences */
};
typedef enum {
PREF_UINT,
PREF_BOOL,
PREF_ENUM,
PREF_STRING
} pref_type_t;
struct preference {
const char *name; /* name of preference */
const char *title; /* title to use in GUI */
const char *description; /* human-readable description of preference */
int ordinal; /* ordinal number of this preference */
pref_type_t type; /* type of that preference */
union {
guint *uint;
gboolean *bool;
gint *enump;
char **string;
} varp; /* pointer to variable storing the value */
union {
guint uint;
gboolean bool;
gint enumval;
char *string;
} saved_val; /* original value, when editing from the GUI */
union {
guint base; /* input/output base, for PREF_UINT */
struct {
const enum_val *enumvals; /* list of name & values */
gboolean radio_buttons; /* TRUE if it should be shown as
radio buttons rather than as an
option menu or combo box in
the preferences tab */
} enum_info; /* for PREF_ENUM */
} info; /* display/text file information */
void *control; /* handle for GUI control for this preference */
};
gint find_val_for_string(const char *needle, const enum_val *haystack,
gint default_value);
#endif /* prefs-int.h */

585
prefs.c
View File

@ -1,7 +1,7 @@
/* prefs.c
* Routines for handling preferences
*
* $Id: prefs.c,v 1.30 2000/01/29 16:41:14 gram Exp $
* $Id: prefs.c,v 1.31 2000/07/05 09:40:41 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -36,6 +36,7 @@
#endif
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
@ -53,6 +54,8 @@
#include "print.h"
#include "util.h"
#include "prefs-int.h"
/* Internal functions */
static int set_pref(gchar*, gchar*);
static GList *get_string_list(gchar *);
@ -60,7 +63,9 @@ static void clear_string_list(GList *);
#define PF_NAME "preferences"
static int init_prefs = 1;
#define GPF_PATH DATAFILE_DIR "/ethereal.conf"
static gboolean init_prefs = TRUE;
static gchar *pf_path = NULL;
e_prefs prefs;
@ -72,6 +77,244 @@ gchar *gui_ptree_expander_style_text[] =
{ "NONE", "SQUARE", "TRIANGLE", "CIRCULAR", NULL };
/*
* List of modules with preference settings.
*/
static GList *modules;
/*
* Register a module that will have preferences.
* Specify the name used for the module in the preferences file, the
* title used in the tab for it in a preferences dialog box, and a
* routine to call back when we apply the preferences.
*/
module_t *
prefs_register_module(const char *name, const char *title,
void (*apply_cb)(void))
{
module_t *module;
module = g_malloc(sizeof (module_t));
module->name = name;
module->title = title;
module->apply_cb = apply_cb;
module->prefs = NULL; /* no preferences, to start */
module->numprefs = 0;
modules = g_list_append(modules, module);
return module;
}
/*
* Find a module, given its name.
*/
static gint
module_match(gconstpointer a, gconstpointer b)
{
const module_t *module = a;
const char *name = b;
return strcmp(name, module->name);
}
static module_t *
find_module(char *name)
{
GList *list_entry;
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;
}
typedef struct {
module_cb callback;
gpointer user_data;
} module_cb_arg_t;
static void
do_module_callback(gpointer data, gpointer user_data)
{
module_t *module = data;
module_cb_arg_t *arg = user_data;
(*arg->callback)(module, arg->user_data);
}
/*
* Call a callback function, with a specified argument, for each module.
*/
void
prefs_module_foreach(module_cb callback, gpointer user_data)
{
module_cb_arg_t arg;
arg.callback = callback;
arg.user_data = user_data;
g_list_foreach(modules, do_module_callback, &arg);
}
static void
call_apply_cb(gpointer data, gpointer user_data)
{
module_t *module = data;
(*module->apply_cb)();
}
/*
* Call the "apply" callback function for each module.
*/
void
prefs_apply_all(void)
{
g_list_foreach(modules, call_apply_cb, NULL);
}
/*
* Register a preference in a module's list of preferences.
*/
static pref_t *
register_preference(module_t *module, const char *name, const char *title,
const char *description)
{
pref_t *preference;
preference = g_malloc(sizeof (pref_t));
preference->name = name;
preference->title = title;
preference->description = description;
preference->ordinal = module->numprefs;
module->prefs = g_list_append(module->prefs, preference);
module->numprefs++;
return preference;
}
/*
* Find a preference in a module's list of preferences, given the module
* and the preference's name.
*/
static gint
preference_match(gconstpointer a, gconstpointer b)
{
const pref_t *pref = a;
const char *name = b;
return strcmp(name, pref->name);
}
static struct preference *
find_preference(module_t *module, char *name)
{
GList *list_entry;
list_entry = g_list_find_custom(module->prefs, name, preference_match);
if (list_entry == NULL)
return NULL; /* no such preference */
return (struct preference *) list_entry->data;
}
/*
* Register a preference with an unsigned integral value.
*/
void
prefs_register_uint_preference(module_t *module, const char *name,
const char *title, const char *description, guint base, guint *var)
{
pref_t *preference;
preference = register_preference(module, name, title, description);
preference->type = PREF_UINT;
preference->varp.uint = var;
preference->info.base = base;
}
/*
* Register a preference with an Boolean value.
*/
void
prefs_register_bool_preference(module_t *module, const char *name,
const char *title, const char *description, gboolean *var)
{
pref_t *preference;
preference = register_preference(module, name, title, description);
preference->type = PREF_BOOL;
preference->varp.bool = var;
}
/*
* Register a preference with an enumerated value.
*/
void
prefs_register_enum_preference(module_t *module, const char *name,
const char *title, const char *description, gint *var,
const enum_val *enumvals, gboolean radio_buttons)
{
pref_t *preference;
preference = register_preference(module, name, title, description);
preference->type = PREF_ENUM;
preference->varp.enump = var;
preference->info.enum_info.enumvals = enumvals;
preference->info.enum_info.radio_buttons = radio_buttons;
}
/*
* Register a preference with a character-string value.
*/
void
prefs_register_string_preference(module_t *module, const char *name,
const char *title, const char *description, char **var)
{
pref_t *preference;
preference = register_preference(module, name, title, description);
preference->type = PREF_STRING;
preference->varp.string = var;
preference->saved_val.string = NULL;
}
typedef struct {
pref_cb callback;
gpointer user_data;
} pref_cb_arg_t;
static void
do_pref_callback(gpointer data, gpointer user_data)
{
pref_t *pref = data;
pref_cb_arg_t *arg = user_data;
(*arg->callback)(pref, arg->user_data);
}
/*
* Call a callback function, with a specified argument, for each preference
* in a given module.
*/
void
prefs_pref_foreach(module_t *module, pref_cb callback, gpointer user_data)
{
pref_cb_arg_t arg;
arg.callback = callback;
arg.user_data = user_data;
g_list_foreach(module->prefs, do_pref_callback, &arg);
}
/*
* Register all non-dissector modules' preferences.
*/
void
prefs_register_modules(void)
{
}
/* Parse through a list of comma-separated, quoted strings. Return a
list of the string data */
static GList *
@ -129,6 +372,29 @@ clear_string_list(GList *sl) {
}
}
/*
* Takes a string, a pointer to an array of "enum_val"s, and a default gint
* value.
* The array must be terminated by an entry with a null "name" string.
* If the string matches a "name" strings in an entry, the value from that
* entry is returned. Otherwise, the default value that was passed as the
* third argument is returned.
*/
gint
find_val_for_string(const char *needle, const enum_val *haystack,
gint default_value)
{
int i = 0;
while (haystack[i].name != NULL) {
if (strcasecmp(needle, haystack[i].name) == 0) {
return haystack[i].value;
}
i++;
}
return default_value;
}
/* Takes an string and a pointer to an array of strings, and a default int value.
* The array must be terminated by a NULL string. If the string is found in the array
* of strings, the index of that string in the array is returned. Otherwise, the
@ -167,24 +433,26 @@ print.file: /a/very/long/path/
#define MAX_VAL_LEN 1024
#define DEF_NUM_COLS 6
static void read_prefs_file(const char *pf_path, FILE *pf);
e_prefs *
read_prefs(char **pf_path_return) {
enum { START, IN_VAR, PRE_VAL, IN_VAL, IN_SKIP };
read_prefs(int *gpf_errno_return, char **gpf_path_return,
int *pf_errno_return, char **pf_path_return)
{
int i;
FILE *pf;
gchar cur_var[MAX_VAR_LEN], cur_val[MAX_VAL_LEN];
int got_c, state = START, i;
gint var_len = 0, val_len = 0, fline = 1, pline = 1;
gboolean got_val = FALSE;
fmt_data *cfmt;
gchar *col_fmt[] = {"No.", "%m", "Time", "%t",
"Source", "%s", "Destination", "%d",
"Protocol", "%p", "Info", "%i"};
/* Initialize preferences. With any luck, these values will be
overwritten below. */
if (init_prefs) {
init_prefs = 0;
/* Initialize preferences to wired-in default values.
They may be overridded 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");
@ -220,19 +488,57 @@ read_prefs(char **pf_path_return) {
prefs.gui_ptree_expander_style = 1;
}
/* Read the global preferences file, if it exists. */
*gpf_path_return = NULL;
if ((pf = fopen(GPF_PATH, "r")) != NULL) {
/* We succeeded in opening it; read it. */
read_prefs_file(GPF_PATH, pf);
fclose(pf);
} else {
/* We failed to open it. If we failed for some reason other than
"it doesn't exist", return the errno and the pathname, so our
caller can report the error. */
if (errno != ENOENT) {
*gpf_errno_return = errno;
*gpf_path_return = GPF_PATH;
}
}
/* Construct the pathname of the user's preferences file. */
if (! pf_path) {
pf_path = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(PF_DIR) +
strlen(PF_NAME) + 4);
sprintf(pf_path, "%s/%s/%s", get_home_dir(), PF_DIR, PF_NAME);
}
/* Read the user's preferences file, if it exists. */
*pf_path_return = NULL;
if ((pf = fopen(pf_path, "r")) == NULL) {
if (errno != ENOENT)
if ((pf = fopen(pf_path, "r")) != NULL) {
/* We succeeded in opening it; read it. */
read_prefs_file(pf_path, pf);
fclose(pf);
} else {
/* We failed to open it. If we failed for some reason other than
"it doesn't exist", return the errno and the pathname, so our
caller can report the error. */
if (errno != ENOENT) {
*pf_errno_return = errno;
*pf_path_return = pf_path;
return &prefs;
}
}
return &prefs;
}
static void
read_prefs_file(const char *pf_path, FILE *pf)
{
enum { START, IN_VAR, PRE_VAL, IN_VAL, IN_SKIP };
gchar cur_var[MAX_VAR_LEN], cur_val[MAX_VAL_LEN];
int got_c, state = START;
gboolean got_val = FALSE;
gint var_len = 0, val_len = 0, fline = 1, pline = 1;
while ((got_c = getc(pf)) != EOF) {
if (got_c == '\n') {
state = START;
@ -259,8 +565,17 @@ read_prefs(char **pf_path_return) {
if (got_val) {
cur_var[var_len] = '\0';
cur_val[val_len] = '\0';
if (! set_pref(cur_var, cur_val))
g_warning ("%s line %d: Bogus preference", pf_path, pline);
switch (set_pref(cur_var, cur_val)) {
case PREFS_SET_SYNTAX_ERR:
g_warning ("%s line %d: Syntax error", pf_path, pline);
break;
case PREFS_SET_NO_SUCH_PREF:
g_warning ("%s line %d: No such preference \"%s\"", pf_path,
pline, cur_var);
break;
}
} else {
g_warning ("%s line %d: Incomplete preference", pf_path, pline);
}
@ -311,15 +626,62 @@ read_prefs(char **pf_path_return) {
if (got_val) {
cur_var[var_len] = '\0';
cur_val[val_len] = '\0';
if (! set_pref(cur_var, cur_val))
g_warning ("%s line %d: Bogus preference", pf_path, pline);
switch (set_pref(cur_var, cur_val)) {
case PREFS_SET_SYNTAX_ERR:
g_warning ("%s line %d: Syntax error", pf_path, pline);
break;
case PREFS_SET_NO_SUCH_PREF:
g_warning ("%s line %d: No such preference \"%s\"", pf_path,
pline, cur_var);
break;
}
} else {
g_warning ("%s line %d: Incomplete preference", pf_path, pline);
}
}
fclose(pf);
return &prefs;
}
/*
* Given a string of the form "<pref name>:<pref value>", as might appear
* as an argument to a "-o" option, parse it and set the preference in
* question. Return an indication of whether it succeeded or failed
* in some fashion.
*/
int
prefs_set_pref(char *prefarg)
{
u_char *p, *colonp;
int ret;
colonp = strchr(prefarg, ':');
if (colonp == NULL)
return PREFS_SET_SYNTAX_ERR;
p = colonp;
*p++ = '\0';
/*
* Skip over any white space (there probably won't be any, but
* as we allow it in the preferences file, we might as well
* allow it here).
*/
while (isspace(*p))
p++;
if (*p == '\0') {
/*
* Put the colon back, so if our caller uses, in an
* error message, the string they passed us, the message
* looks correct.
*/
*colonp = ':';
return PREFS_SET_SYNTAX_ERR;
}
ret = set_pref(prefarg, p);
*colonp = ':'; /* put the colon back */
return ret;
}
#define PRS_PRINT_FMT "print.format"
@ -344,36 +706,42 @@ read_prefs(char **pf_path_return) {
static gchar *pr_formats[] = { "text", "postscript" };
static gchar *pr_dests[] = { "command", "file" };
int
set_pref(gchar *pref, gchar *value) {
static int
set_pref(gchar *pref_name, gchar *value)
{
GList *col_l;
gint llen;
fmt_data *cfmt;
unsigned long int cval;
guint uval;
char *p;
gchar *dotp;
module_t *module;
pref_t *pref;
if (strcmp(pref, PRS_PRINT_FMT) == 0) {
if (strcmp(pref_name, PRS_PRINT_FMT) == 0) {
if (strcmp(value, pr_formats[PR_FMT_TEXT]) == 0) {
prefs.pr_format = PR_FMT_TEXT;
} else if (strcmp(value, pr_formats[PR_FMT_PS]) == 0) {
prefs.pr_format = PR_FMT_PS;
} else {
return 0;
return PREFS_SET_SYNTAX_ERR;
}
} else if (strcmp(pref, PRS_PRINT_DEST) == 0) {
} else if (strcmp(pref_name, PRS_PRINT_DEST) == 0) {
if (strcmp(value, pr_dests[PR_DEST_CMD]) == 0) {
prefs.pr_dest = PR_DEST_CMD;
} else if (strcmp(value, pr_dests[PR_DEST_FILE]) == 0) {
prefs.pr_dest = PR_DEST_FILE;
} else {
return 0;
return PREFS_SET_SYNTAX_ERR;
}
} else if (strcmp(pref, PRS_PRINT_FILE) == 0) {
} else if (strcmp(pref_name, PRS_PRINT_FILE) == 0) {
if (prefs.pr_file) g_free(prefs.pr_file);
prefs.pr_file = g_strdup(value);
} else if (strcmp(pref, PRS_PRINT_CMD) == 0) {
} else if (strcmp(pref_name, PRS_PRINT_CMD) == 0) {
if (prefs.pr_cmd) g_free(prefs.pr_cmd);
prefs.pr_cmd = g_strdup(value);
} else if (strcmp(pref, PRS_COL_FMT) == 0) {
} else if (strcmp(pref_name, PRS_COL_FMT) == 0) {
if ((col_l = get_string_list(value)) && (g_list_length(col_l) % 2) == 0) {
while (prefs.col_list) {
cfmt = prefs.col_list->data;
@ -396,66 +764,195 @@ set_pref(gchar *pref, gchar *value) {
/* To do: else print some sort of error? */
}
clear_string_list(col_l);
} else if (strcmp(pref, PRS_STREAM_CL_FG) == 0) {
} else if (strcmp(pref_name, PRS_STREAM_CL_FG) == 0) {
cval = strtoul(value, NULL, 16);
prefs.st_client_fg.pixel = 0;
prefs.st_client_fg.red = RED_COMPONENT(cval);
prefs.st_client_fg.green = GREEN_COMPONENT(cval);
prefs.st_client_fg.blue = BLUE_COMPONENT(cval);
} else if (strcmp(pref, PRS_STREAM_CL_BG) == 0) {
} else if (strcmp(pref_name, PRS_STREAM_CL_BG) == 0) {
cval = strtoul(value, NULL, 16);
prefs.st_client_bg.pixel = 0;
prefs.st_client_bg.red = RED_COMPONENT(cval);
prefs.st_client_bg.green = GREEN_COMPONENT(cval);
prefs.st_client_bg.blue = BLUE_COMPONENT(cval);
} else if (strcmp(pref, PRS_STREAM_SR_FG) == 0) {
} else if (strcmp(pref_name, PRS_STREAM_SR_FG) == 0) {
cval = strtoul(value, NULL, 16);
prefs.st_server_fg.pixel = 0;
prefs.st_server_fg.red = RED_COMPONENT(cval);
prefs.st_server_fg.green = GREEN_COMPONENT(cval);
prefs.st_server_fg.blue = BLUE_COMPONENT(cval);
} else if (strcmp(pref, PRS_STREAM_SR_BG) == 0) {
} else if (strcmp(pref_name, PRS_STREAM_SR_BG) == 0) {
cval = strtoul(value, NULL, 16);
prefs.st_server_bg.pixel = 0;
prefs.st_server_bg.red = RED_COMPONENT(cval);
prefs.st_server_bg.green = GREEN_COMPONENT(cval);
prefs.st_server_bg.blue = BLUE_COMPONENT(cval);
} else if (strcmp(pref, PRS_GUI_SCROLLBAR_ON_RIGHT) == 0) {
} else if (strcmp(pref_name, PRS_GUI_SCROLLBAR_ON_RIGHT) == 0) {
if (strcmp(value, "TRUE") == 0) {
prefs.gui_scrollbar_on_right = TRUE;
}
else {
prefs.gui_scrollbar_on_right = FALSE;
}
} else if (strcmp(pref, PRS_GUI_PLIST_SEL_BROWSE) == 0) {
} else if (strcmp(pref_name, PRS_GUI_PLIST_SEL_BROWSE) == 0) {
if (strcmp(value, "TRUE") == 0) {
prefs.gui_plist_sel_browse = TRUE;
}
else {
prefs.gui_plist_sel_browse = FALSE;
}
} else if (strcmp(pref, PRS_GUI_PTREE_SEL_BROWSE) == 0) {
} else if (strcmp(pref_name, PRS_GUI_PTREE_SEL_BROWSE) == 0) {
if (strcmp(value, "TRUE") == 0) {
prefs.gui_ptree_sel_browse = TRUE;
}
else {
prefs.gui_ptree_sel_browse = FALSE;
}
} else if (strcmp(pref, PRS_GUI_PTREE_LINE_STYLE) == 0) {
} else if (strcmp(pref_name, PRS_GUI_PTREE_LINE_STYLE) == 0) {
prefs.gui_ptree_line_style =
find_index_from_string_array(value, gui_ptree_line_style_text, 0);
} else if (strcmp(pref, PRS_GUI_PTREE_EXPANDER_STYLE) == 0) {
} else if (strcmp(pref_name, PRS_GUI_PTREE_EXPANDER_STYLE) == 0) {
prefs.gui_ptree_expander_style =
find_index_from_string_array(value, gui_ptree_expander_style_text, 1);
} else {
return 0;
/* To which module does this preference belong? */
dotp = strchr(pref_name, '.');
if (dotp == NULL)
return PREFS_SET_SYNTAX_ERR; /* no ".", so no module/name separator */
*dotp = '\0'; /* separate module and preference name */
module = find_module(pref_name);
*dotp = '.'; /* put the preference string back */
if (module == NULL)
return PREFS_SET_NO_SUCH_PREF; /* no such module */
dotp++; /* skip past separator to preference name */
pref = find_preference(module, dotp);
if (pref == NULL)
return PREFS_SET_NO_SUCH_PREF; /* no such preference */
switch (pref->type) {
case PREF_UINT:
uval = strtoul(value, &p, pref->info.base);
if (p == value || *p != '\0')
return PREFS_SET_SYNTAX_ERR; /* number was bad */
*pref->varp.uint = uval;
break;
case PREF_BOOL:
/* XXX - give an error if it's neither "true" nor "false"? */
if (strcasecmp(value, "true") == 0)
*pref->varp.bool = TRUE;
else
*pref->varp.bool = FALSE;
break;
case PREF_ENUM:
/* XXX - give an error if it doesn't match? */
*pref->varp.enump = find_val_for_string(value,
pref->info.enum_info.enumvals, 1);
break;
case PREF_STRING:
if (*pref->varp.string != NULL)
g_free(*pref->varp.string);
*pref->varp.string = g_strdup(value);
break;
}
}
return 1;
return PREFS_SET_OK;
}
typedef struct {
module_t *module;
FILE *pf;
} write_pref_arg_t;
/*
* Write out a single preference.
*/
static void
write_pref(gpointer data, gpointer user_data)
{
pref_t *pref = data;
write_pref_arg_t *arg = user_data;
const enum_val *enum_valp;
const char *val_string;
fprintf(arg->pf, "\n# %s\n", pref->description);
switch (pref->type) {
case PREF_UINT:
switch (pref->info.base) {
case 10:
fprintf(arg->pf, "# A decimal number.\n");
fprintf(arg->pf, "%s.%s: %u\n", arg->module->name,
pref->name, *pref->varp.uint);
break;
case 8:
fprintf(arg->pf, "# An octal number.\n");
fprintf(arg->pf, "%s.%s: %#o\n", arg->module->name,
pref->name, *pref->varp.uint);
break;
case 16:
fprintf(arg->pf, "# A hexadecimal number.\n");
fprintf(arg->pf, "%s.%s: %#x\n", arg->module->name,
pref->name, *pref->varp.uint);
break;
}
break;
case PREF_BOOL:
fprintf(arg->pf, "# TRUE or FALSE (case-insensitive).\n");
fprintf(arg->pf, "%s.%s: %s\n", arg->module->name, pref->name,
*pref->varp.bool ? "TRUE" : "FALSE");
break;
case PREF_ENUM:
fprintf(arg->pf, "# One of: ");
enum_valp = pref->info.enum_info.enumvals;
val_string = NULL;
while (enum_valp->name != NULL) {
if (enum_valp->value == *pref->varp.enump)
val_string = enum_valp->name;
fprintf(arg->pf, "%s", enum_valp->name);
enum_valp++;
if (enum_valp->name == NULL)
fprintf(arg->pf, "\n");
else
fprintf(arg->pf, ", ");
}
fprintf(arg->pf, "# (case-insensitive).\n");
fprintf(arg->pf, "%s.%s: %s\n", arg->module->name, pref->name,
val_string);
break;
case PREF_STRING:
fprintf(arg->pf, "# A string.\n");
fprintf(arg->pf, "%s.%s: %s\n", arg->module->name, pref->name,
*pref->varp.string);
break;
}
}
static void
write_module_prefs(gpointer data, gpointer user_data)
{
write_pref_arg_t arg;
arg.module = data;
arg.pf = user_data;
g_list_foreach(arg.module->prefs, write_pref, &arg);
}
int
write_prefs(char **pf_path_return) {
write_prefs(char **pf_path_return)
{
FILE *pf;
struct stat s_buf;
@ -549,6 +1046,8 @@ write_prefs(char **pf_path_return) {
fprintf(pf, PRS_GUI_PTREE_EXPANDER_STYLE ": %s\n",
gui_ptree_expander_style_text[prefs.gui_ptree_expander_style]);
g_list_foreach(modules, write_module_prefs, pf);
fclose(pf);
/* XXX - catch I/O errors (e.g. "ran out of disk space") and return

93
prefs.h
View File

@ -1,7 +1,7 @@
/* prefs.h
* Definitions for preference handling routines
*
* $Id: prefs.h,v 1.15 2000/01/06 07:33:22 guy Exp $
* $Id: prefs.h,v 1.16 2000/07/05 09:40:42 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -50,7 +50,96 @@ typedef struct _e_prefs {
extern e_prefs prefs;
e_prefs* read_prefs(char **);
/*
* Routines to let modules that have preference settings register
* themselves by name, and to let them register preference settings
* by name.
*/
struct pref_module;
typedef struct pref_module module_t;
/*
* Register a module that will have preferences.
* Specify the name used for the module in the preferences file, the
* title used in the tab for it in a preferences dialog box, and a
* routine to call back when we apply the preferences.
*/
module_t *prefs_register_module(const char *name, const char *title,
void (*apply_cb)(void));
typedef void (*module_cb)(module_t *module, gpointer user_data);
/*
* Call a callback function, with a specified argument, for each module.
*/
void prefs_module_foreach(module_cb callback, gpointer user_data);
/*
* Call the "apply" callback function for each module.
*/
void prefs_apply_all(void);
struct preference;
typedef struct preference pref_t;
/*
* Register a preference with an unsigned integral value.
*/
void prefs_register_uint_preference(module_t *module, const char *name,
const char *title, const char *description, guint base, guint *var);
/*
* Register a preference with an Boolean value.
*/
void prefs_register_bool_preference(module_t *module, const char *name,
const char *title, const char *description, gboolean *var);
/*
* Register a preference with an enumerated value.
*/
typedef struct {
char *name;
gint value;
} enum_val;
void prefs_register_enum_preference(module_t *module, const char *name,
const char *title, const char *description, gint *var,
const enum_val *enumvals, gboolean radio_buttons);
/*
* Register a preference with a character-string value.
*/
void prefs_register_string_preference(module_t *module, const char *name,
const char *title, const char *description, char **var);
typedef void (*pref_cb)(pref_t *pref, gpointer user_data);
/*
* Call a callback function, with a specified argument, for each preference
* in a given module.
*/
void prefs_pref_foreach(module_t *module, pref_cb callback, gpointer user_data);
/*
* Register all non-dissector modules' preferences.
*/
void prefs_register_modules(void);
e_prefs *read_prefs(int *, char **, int *, char **);
int write_prefs(char **);
/*
* Given a string of the form "<pref name>:<pref value>", as might appear
* as an argument to a "-o" option, parse it and set the preference in
* question. Return an indication of whether it succeeded or failed
* in some fashion.
*/
#define PREFS_SET_OK 0 /* succeeded */
#define PREFS_SET_SYNTAX_ERR 1 /* syntax error in string */
#define PREFS_SET_NO_SUCH_PREF 2 /* no such preference */
int prefs_set_pref(char *prefarg);
#endif /* prefs.h */

View File

@ -1,6 +1,6 @@
/* tethereal.c
*
* $Id: tethereal.c,v 1.33 2000/07/05 02:06:58 guy Exp $
* $Id: tethereal.c,v 1.34 2000/07/05 09:40:43 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -132,13 +132,13 @@ print_usage(void)
VERSION, comp_info_str);
#ifdef HAVE_LIBPCAP
fprintf(stderr, "t%s [ -vVh ] [ -c count ] [ -D ] [ -f <capture filter> ]\n", PACKAGE);
fprintf(stderr, "\t[ -F <capture file type> ] [ -i interface ] [ -n ] [ -r infile ]\n");
fprintf(stderr, "\t[ -R <read filter> ] [ -s snaplen ] [ -t <time stamp format> ]\n");
fprintf(stderr, "\t[ -w savefile ] [ -x ]\n");
fprintf(stderr, "\t[ -F <capture file type> ] [ -i interface ] [ -n ]\n");
fprintf(stderr, "\t[ -o <preference setting> ] ... [ -r infile ] [ -R <read filter> ]\n");
fprintf(stderr, "\t[ -s snaplen ] [ -t <time stamp format> ] [ -w savefile ] [ -x ]\n");
#else
fprintf(stderr, "t%s [ -vVh ] [ -D ] [ -F <capture file type> ] [ -n ] [ -r infile ]\n", PACKAGE);
fprintf(stderr, "\t[ -R <read filter> ] [ -t <time stamp format> ] [ -w savefile ]\n");
fprintf(stderr, "\t[ -x ]\n");
fprintf(stderr, "t%s [ -vVh ] [ -D ] [ -F <capture file type> ] [ -n ]\n", PACKAGE);
fprintf(stderr, "\t[ -o <preference setting> ] ... [ -r infile ] [ -R <read filter> ]\n");
fprintf(stderr, "\t[ -t <time stamp format> ] [ -w savefile ] [ -x ]\n");
#endif
fprintf(stderr, "Valid file type arguments to the \"-F\" flag:\n");
for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
@ -162,7 +162,8 @@ main(int argc, char *argv[])
extern char pcap_version[];
#endif
#endif
char *pf_path;
char *gpf_path, *pf_path;
int gpf_open_errno, pf_open_errno;
int err;
#ifdef HAVE_LIBPCAP
gboolean capture_filter_specified = FALSE;
@ -177,13 +178,22 @@ main(int argc, char *argv[])
dfilter *rfcode = NULL;
e_prefs *prefs;
/* Register all dissectors; we must do this before checking for the
"-G" flag, as the "-G" flag dumps a list of fields registered
by the dissectors, and we must do it before we read the preferences,
in case any dissectors register preferences. */
dissect_init();
/* Now register the preferences for any non-dissector modules.
We must do that before we read the preferences as well. */
prefs_register_modules();
/* If invoked with the "-G" flag, we dump out a glossary of
display filter symbols.
We do this here to mirror what happens in the GTK+ version, although
it's not necessary here. */
if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
dissect_init();
proto_registrar_dump();
exit(0);
}
@ -191,10 +201,14 @@ main(int argc, char *argv[])
/* Set the C-language locale to the native environment. */
setlocale(LC_ALL, "");
prefs = read_prefs(&pf_path);
prefs = read_prefs(&gpf_open_errno, &gpf_path, &pf_open_errno, &pf_path);
if (gpf_path != NULL) {
fprintf(stderr, "Can't open global preferences file \"%s\": %s.\n", pf_path,
strerror(gpf_open_errno));
}
if (pf_path != NULL) {
fprintf(stderr, "Can't open preferences file \"%s\": %s.\n", pf_path,
strerror(errno));
fprintf(stderr, "Can't open your preferences file \"%s\": %s.\n", pf_path,
strerror(pf_open_errno));
}
/* Initialize the capture file struct */
@ -266,7 +280,7 @@ main(int argc, char *argv[])
);
/* Now get our args */
while ((opt = getopt(argc, argv, "c:Df:F:hi:nr:R:s:t:vw:Vx")) != EOF) {
while ((opt = getopt(argc, argv, "c:Df:F:hi:no:r:R:s:t:vw:Vx")) != EOF) {
switch (opt) {
case 'c': /* Capture xxx packets */
#ifdef HAVE_LIBPCAP
@ -311,6 +325,21 @@ main(int argc, char *argv[])
case 'n': /* No name resolution */
g_resolving_actif = 0;
break;
case 'o': /* Override preference from command line */
switch (prefs_set_pref(optarg)) {
case PREFS_SET_SYNTAX_ERR:
fprintf(stderr, "tethereal: Invalid -o flag \"%s\"\n", optarg);
exit(1);
break;
case PREFS_SET_NO_SUCH_PREF:
fprintf(stderr, "tethereal: -o flag \"%s\" specifies unknown preference\n",
optarg);
exit(1);
break;
}
break;
case 'r': /* Read capture file xxx */
cf_name = g_strdup(optarg);
break;
@ -407,8 +436,6 @@ main(int argc, char *argv[])
else if (cfile.snap < MIN_PACKET_SIZE)
cfile.snap = MIN_PACKET_SIZE;
dissect_init(); /* Init anything that needs initializing */
if (rfilter != NULL) {
if (dfilter_compile(rfilter, &rfcode) != 0) {
fprintf(stderr, "tethereal: %s\n", dfilter_error_msg);