/* prefs.c
* Routines for handling preferences
*
- * $Id: prefs.c,v 1.49 2001/04/13 14:59:28 jfoster Exp $
+ * $Id: prefs.c,v 1.56 2001/07/22 21:56:25 guy Exp $
*
* Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
+ * By Gerald Combs <gerald@ethereal.com>
* 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
{
}
-/* Parse through a list of comma-separated, quoted strings. Return a
- list of the string data */
+/* Parse through a list of comma-separated, possibly quoted strings.
+ Return a list of the string data. */
static GList *
-get_string_list(gchar *str) {
- enum { PRE_QUOT, IN_QUOT, POST_QUOT };
-
- gint state = PRE_QUOT, i = 0, j = 0;
- gboolean backslash = FALSE;
+get_string_list(gchar *str)
+{
+ gint i = 0, j = 0;
+ gboolean in_quot = FALSE, backslash = FALSE;
gchar cur_c, *slstr = NULL;
GList *sl = NULL;
-
- while ((cur_c = str[i]) != '\0') {
+
+ /* Allocate a buffer for the first string. */
+ slstr = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
+ j = 0;
+
+ for (;;) {
+ cur_c = str[i];
+ if (cur_c == '\0') {
+ /* It's the end of the input, so it's the end of the string we
+ were working on, and there's no more input. */
+ if (in_quot || backslash) {
+ /* We were in the middle of a quoted string or backslash escape,
+ and ran out of characters; that's an error. */
+ g_free(slstr);
+ clear_string_list(sl);
+ return NULL;
+ }
+ slstr[j] = '\0';
+ sl = g_list_append(sl, slstr);
+ break;
+ }
if (cur_c == '"' && ! backslash) {
- switch (state) {
- case PRE_QUOT:
- state = IN_QUOT;
- slstr = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
- j = 0;
- break;
- case IN_QUOT:
- state = POST_QUOT;
- slstr[j] = '\0';
- sl = g_list_append(sl, slstr);
- break;
- case POST_QUOT:
- clear_string_list(sl);
- return NULL;
- break;
- default:
- break;
+ if (!in_quot) {
+ /* We're not in the middle of a quoted string, and we saw a
+ quotation mark; we're now quoting. */
+ in_quot = TRUE;
+ } else {
+ /* We're in the middle of a quoted string, and we saw a quotation
+ mark; we're no longer quoting. */
+ in_quot = FALSE;
}
} else if (cur_c == '\\' && ! backslash) {
+ /* We saw a backslash, and the previous character wasn't a
+ backslash; escape the next character. */
backslash = TRUE;
- } else if (cur_c == ',' && state == POST_QUOT) {
- state = PRE_QUOT;
- } else if (state == IN_QUOT && j < COL_MAX_LEN) {
- slstr[j] = str[i];
- j++;
+ } else if (cur_c == ',' && ! in_quot && ! backslash) {
+ /* We saw a comma, and we're not in the middle of a quoted string
+ and it wasn't preceded by a backslash; it's the end of
+ the string we were working on... */
+ slstr[j] = '\0';
+ sl = g_list_append(sl, slstr);
+
+ /* ...and the beginning of a new string. */
+ slstr = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
+ j = 0;
+ } else {
+ /* It's a character to be put into a string; do so if there's room. */
+ if (j < COL_MAX_LEN) {
+ slstr[j] = cur_c;
+ j++;
+ }
+
+ /* If it was backslash-escaped, we're done with the backslash escape. */
+ backslash = FALSE;
}
i++;
}
- if (state != POST_QUOT) {
- clear_string_list(sl);
- }
return(sl);
}
+/* XXX - needs to handle quote marks inside the quoted string, by
+ backslash-escaping them. */
+#define MAX_FMT_PREF_LEN 1024
+#define MAX_FMT_PREF_LINE_LEN 60
+static gchar *
+put_string_list(GList *sl)
+{
+ static gchar pref_str[MAX_FMT_PREF_LEN] = "";
+ GList *clp = g_list_first(sl);
+ fmt_data *cfmt;
+ int cur_pos = 0, cur_len = 0, fmt_len;
+
+ while (clp) {
+ cfmt = (fmt_data *) clp->data;
+
+ fmt_len = strlen(cfmt->title) + 4;
+ if ((fmt_len + cur_len) < (MAX_FMT_PREF_LEN - 1)) {
+ if ((fmt_len + cur_pos) > MAX_FMT_PREF_LINE_LEN) {
+ cur_len--;
+ cur_pos = 0;
+ pref_str[cur_len] = '\n'; cur_len++;
+ pref_str[cur_len] = '\t'; cur_len++;
+ }
+ sprintf(&pref_str[cur_len], "\"%s\", ", cfmt->title);
+ cur_len += fmt_len;
+ cur_pos += fmt_len;
+ }
+
+ fmt_len = strlen(cfmt->fmt) + 4;
+ if ((fmt_len + cur_len) < (MAX_FMT_PREF_LEN - 1)) {
+ if ((fmt_len + cur_pos) > MAX_FMT_PREF_LINE_LEN) {
+ cur_len--;
+ cur_pos = 0;
+ pref_str[cur_len] = '\n'; cur_len++;
+ pref_str[cur_len] = '\t'; cur_len++;
+ }
+ sprintf(&pref_str[cur_len], "\"%s\", ", cfmt->fmt);
+ cur_len += fmt_len;
+ cur_pos += fmt_len;
+ }
+
+ clp = clp->next;
+ }
+
+ if (cur_len > 2)
+ pref_str[cur_len - 2] = '\0';
+
+ return(pref_str);
+}
+
void
clear_string_list(GList *sl) {
GList *l = sl;
prefs.gui_marked_bg.blue = 0;
/* set the default values for the capture dialog box */
- prefs.capture_prom_mode = 0;
- prefs.capture_real_time = 0;
- prefs.capture_auto_scroll = 0;
- prefs.capture_name_resolve= 1;
-
+ prefs.capture_prom_mode = TRUE;
+ prefs.capture_real_time = FALSE;
+ prefs.capture_auto_scroll = FALSE;
+ prefs.name_resolve = PREFS_RESOLV_ALL;
}
/* Read the global preferences file, if it exists. */
#define PRS_GUI_MARKED_FG "gui.marked_frame.fg"
#define PRS_GUI_MARKED_BG "gui.marked_frame.bg"
+/*
+ * This applies to more than just captures, so it's not "capture.name_resolve";
+ * "capture.name_resolve" is supported on input for backwards compatibility.
+ *
+ * It's not a preference for a particular part of Ethereal, it's used all
+ * over the place, so its name doesn't have two components.
+ */
+#define PRS_NAME_RESOLVE "name_resolve"
+#define PRS_CAP_NAME_RESOLVE "capture.name_resolve"
+
/* values for the capture dialog box */
#define PRS_CAP_REAL_TIME "capture.real_time_update"
#define PRS_CAP_PROM_MODE "capture.prom_mode"
#define PRS_CAP_AUTO_SCROLL "capture.auto_scroll"
-#define PRS_CAP_NAME_RESOLVE "capture.name_resolve"
#define RED_COMPONENT(x) ((((x) >> 16) & 0xff) * 65535 / 255)
#define GREEN_COMPONENT(x) ((((x) >> 8) & 0xff) * 65535 / 255)
static gchar *pr_formats[] = { "text", "postscript" };
static gchar *pr_dests[] = { "command", "file" };
+typedef struct {
+ char letter;
+ guint32 value;
+} name_resolve_opt_t;
+
+static name_resolve_opt_t name_resolve_opt[] = {
+ { 'm', PREFS_RESOLV_MAC },
+ { 'n', PREFS_RESOLV_NETWORK },
+ { 't', PREFS_RESOLV_TRANSPORT },
+};
+
+#define N_NAME_RESOLVE_OPT (sizeof name_resolve_opt / sizeof name_resolve_opt[0])
+
+static char *
+name_resolve_to_string(guint32 name_resolve)
+{
+ static char string[N_NAME_RESOLVE_OPT+1];
+ char *p;
+ unsigned int i;
+ gboolean all_opts_set = TRUE;
+
+ if (name_resolve == PREFS_RESOLV_NONE)
+ return "FALSE";
+ p = &string[0];
+ for (i = 0; i < N_NAME_RESOLVE_OPT; i++) {
+ if (name_resolve & name_resolve_opt[i].value)
+ *p++ = name_resolve_opt[i].letter;
+ else
+ all_opts_set = FALSE;
+ }
+ *p = '\0';
+ if (all_opts_set)
+ return "TRUE";
+ return string;
+}
+
+char
+string_to_name_resolve(char *string, guint32 *name_resolve)
+{
+ char c;
+ unsigned int i;
+
+ *name_resolve = 0;
+ while ((c = *string++) != '\0') {
+ for (i = 0; i < N_NAME_RESOLVE_OPT; i++) {
+ if (c == name_resolve_opt[i].letter) {
+ *name_resolve |= name_resolve_opt[i].value;
+ break;
+ }
+ }
+ if (i == N_NAME_RESOLVE_OPT) {
+ /*
+ * Unrecognized letter.
+ */
+ return c;
+ }
+ }
+ return '\0';
+}
+
static int
set_pref(gchar *pref_name, gchar *value)
{
- GList *col_l;
+ GList *col_l, *col_l_elt;
gint llen;
fmt_data *cfmt;
unsigned long int cval;
if (prefs.pr_cmd) g_free(prefs.pr_cmd);
prefs.pr_cmd = g_strdup(value);
} else if (strcmp(pref_name, PRS_COL_FMT) == 0) {
- if ((col_l = get_string_list(value)) && (g_list_length(col_l) % 2) == 0) {
- free_col_info(&prefs);
- prefs.col_list = NULL;
- llen = g_list_length(col_l);
- prefs.num_cols = llen / 2;
- col_l = g_list_first(col_l);
- while(col_l) {
- cfmt = (fmt_data *) g_malloc(sizeof(fmt_data));
- cfmt->title = g_strdup(col_l->data);
- col_l = col_l->next;
- cfmt->fmt = g_strdup(col_l->data);
- col_l = col_l->next;
- prefs.col_list = g_list_append(prefs.col_list, cfmt);
+ col_l = get_string_list(value);
+ if (col_l == NULL)
+ return PREFS_SET_SYNTAX_ERR;
+ if ((g_list_length(col_l) % 2) != 0) {
+ /* A title didn't have a matching format. */
+ clear_string_list(col_l);
+ return PREFS_SET_SYNTAX_ERR;
+ }
+ /* Check to make sure all column formats are valid. */
+ col_l_elt = g_list_first(col_l);
+ while(col_l_elt) {
+ /* Make sure the title isn't empty. */
+ if (strcmp(col_l_elt->data, "") == 0) {
+ /* It is. */
+ clear_string_list(col_l);
+ return PREFS_SET_SYNTAX_ERR;
}
- /* To do: else print some sort of error? */
+
+ /* Go past the title. */
+ col_l_elt = col_l_elt->next;
+
+ /* Check the format. */
+ if (get_column_format_from_str(col_l_elt->data) == -1) {
+ /* It's not a valid column format. */
+ clear_string_list(col_l);
+ return PREFS_SET_SYNTAX_ERR;
+ }
+
+ /* Go past the format. */
+ col_l_elt = col_l_elt->next;
+ }
+ free_col_info(&prefs);
+ prefs.col_list = NULL;
+ llen = g_list_length(col_l);
+ prefs.num_cols = llen / 2;
+ col_l_elt = g_list_first(col_l);
+ while(col_l_elt) {
+ cfmt = (fmt_data *) g_malloc(sizeof(fmt_data));
+ cfmt->title = g_strdup(col_l_elt->data);
+ col_l_elt = col_l_elt->next;
+ cfmt->fmt = g_strdup(col_l_elt->data);
+ col_l_elt = col_l_elt->next;
+ prefs.col_list = g_list_append(prefs.col_list, cfmt);
}
clear_string_list(col_l);
} else if (strcmp(pref_name, PRS_STREAM_CL_FG) == 0) {
prefs.st_server_bg.green = GREEN_COMPONENT(cval);
prefs.st_server_bg.blue = BLUE_COMPONENT(cval);
} else if (strcmp(pref_name, PRS_GUI_SCROLLBAR_ON_RIGHT) == 0) {
- if (strcmp(value, "TRUE") == 0) {
+ if (strcasecmp(value, "true") == 0) {
prefs.gui_scrollbar_on_right = TRUE;
}
else {
prefs.gui_scrollbar_on_right = FALSE;
}
} else if (strcmp(pref_name, PRS_GUI_PLIST_SEL_BROWSE) == 0) {
- if (strcmp(value, "TRUE") == 0) {
+ if (strcasecmp(value, "true") == 0) {
prefs.gui_plist_sel_browse = TRUE;
}
else {
prefs.gui_plist_sel_browse = FALSE;
}
} else if (strcmp(pref_name, PRS_GUI_PTREE_SEL_BROWSE) == 0) {
- if (strcmp(value, "TRUE") == 0) {
+ if (strcasecmp(value, "true") == 0) {
prefs.gui_ptree_sel_browse = TRUE;
}
else {
/* handle the capture options */
} else if (strcmp(pref_name, PRS_CAP_PROM_MODE) == 0) {
- prefs.capture_prom_mode = ((strcmp(value, "TRUE") == 0)?TRUE:FALSE);
+ prefs.capture_prom_mode = ((strcasecmp(value, "true") == 0)?TRUE:FALSE);
} else if (strcmp(pref_name, PRS_CAP_REAL_TIME) == 0) {
- prefs.capture_real_time = ((strcmp(value, "TRUE") == 0)?TRUE:FALSE);
+ prefs.capture_real_time = ((strcasecmp(value, "true") == 0)?TRUE:FALSE);
} else if (strcmp(pref_name, PRS_CAP_AUTO_SCROLL) == 0) {
- prefs.capture_auto_scroll = ((strcmp(value, "TRUE") == 0)?TRUE:FALSE);
+ prefs.capture_auto_scroll = ((strcasecmp(value, "true") == 0)?TRUE:FALSE);
- } else if (strcmp(pref_name, PRS_CAP_NAME_RESOLVE) == 0) {
- prefs.capture_name_resolve = ((strcmp(value, "TRUE") == 0)?TRUE:FALSE);
-
+/* handle the global options */
+ } else if (strcmp(pref_name, PRS_NAME_RESOLVE) == 0 ||
+ strcmp(pref_name, PRS_CAP_NAME_RESOLVE) == 0) {
+ /*
+ * "TRUE" and "FALSE", for backwards compatibility, are synonyms for
+ * PREFS_RESOLV_ALL and PREFS_RESOLV_NONE.
+ *
+ * Otherwise, we treat it as a list of name types we want to resolve.
+ */
+ if (strcasecmp(value, "true") == 0)
+ prefs.name_resolve = PREFS_RESOLV_ALL;
+ else if (strcasecmp(value, "false") == 0)
+ prefs.name_resolve = PREFS_RESOLV_NONE;
+ else {
+ prefs.name_resolve = PREFS_RESOLV_NONE; /* start out with none set */
+ if (string_to_name_resolve(value, &prefs.name_resolve) != '\0')
+ return PREFS_SET_SYNTAX_ERR;
+ }
} else {
/* To which module does this preference belong? */
dotp = strchr(pref_name, '.');
fprintf (pf, "# Packet list column format. Each pair of strings consists "
"of a column title \n# and its format.\n"
- "%s: %s\n\n", PRS_COL_FMT, col_format_to_pref_str());
+ "%s: %s\n\n", PRS_COL_FMT, put_string_list(prefs.col_list));
fprintf (pf, "# TCP stream window color preferences. Each value is a six "
"digit hexadecimal value in the form rrggbb.\n");
(prefs.gui_marked_bg.green * 255 / 65535),
(prefs.gui_marked_bg.blue * 255 / 65535));
+ fprintf(pf, "\n# Resolve addresses to names? TRUE/FALSE/{list of address types to resolve}\n");
+ fprintf(pf, PRS_NAME_RESOLVE ": %s\n",
+ name_resolve_to_string(prefs.name_resolve));
+
/* write the capture options */
fprintf(pf, "\n# Capture in promiscuous mode? TRUE/FALSE\n");
fprintf(pf, PRS_CAP_PROM_MODE ": %s\n",
fprintf(pf, PRS_CAP_AUTO_SCROLL ": %s\n",
prefs.capture_auto_scroll == TRUE ? "TRUE" : "FALSE");
- fprintf(pf, "\n# resolve names during capture? TRUE/FALSE\n");
- fprintf(pf, PRS_CAP_NAME_RESOLVE ": %s\n",
- prefs.capture_name_resolve == TRUE ? "TRUE" : "FALSE");
-
g_list_foreach(modules, write_module_prefs, pf);
fclose(pf);
dest->capture_prom_mode = src->capture_prom_mode;
dest->capture_real_time = src->capture_real_time;
dest->capture_auto_scroll = src->capture_auto_scroll;
- dest->capture_name_resolve = src->capture_name_resolve;
+ dest->name_resolve = src->name_resolve;
}