diff --git a/epan/column-utils.c b/epan/column-utils.c index 225eb39141..1a5b9e7f93 100644 --- a/epan/column-utils.c +++ b/epan/column-utils.c @@ -59,6 +59,7 @@ col_setup(column_info *cinfo, const gint num_cols) cinfo->col_last = g_new(int, NUM_COL_FMTS); cinfo->col_title = g_new(gchar*, num_cols); cinfo->col_custom_field = g_new(gchar*, num_cols); + cinfo->col_custom_occurrence = g_new(gint, num_cols); cinfo->col_custom_field_id = g_new(int, num_cols); cinfo->col_custom_dfilter = g_new(dfilter_t*, num_cols); cinfo->col_data = (const gchar **)g_new(gchar*, num_cols); @@ -222,6 +223,7 @@ void col_custom_set_edt(epan_dissect_t *edt, column_info *cinfo) cinfo->col_custom_field_id[i] != -1) { cinfo->col_data[i] = cinfo->col_buf[i]; cinfo->col_expr.col_expr[i] = epan_custom_set(edt, cinfo->col_custom_field_id[i], + cinfo->col_custom_occurrence[i], cinfo->col_buf[i], cinfo->col_expr.col_expr_val[i], COL_MAX_LEN); diff --git a/epan/column.c b/epan/column.c index b1b0504500..ef5a3ce503 100644 --- a/epan/column.c +++ b/epan/column.c @@ -725,6 +725,20 @@ get_column_custom_field(const gint col) return(cfmt->custom_field); } +gint +get_column_custom_occurrence(const gint col) +{ + GList *clp = g_list_nth(prefs.col_list, col); + fmt_data *cfmt; + + if (!clp) /* Invalid column requested */ + return 0; + + cfmt = (fmt_data *) clp->data; + + return(cfmt->custom_occurrence); +} + void build_column_format_array(column_info *cinfo, const gint num_cols, const gboolean reset_fences) { @@ -739,14 +753,17 @@ build_column_format_array(column_info *cinfo, const gint num_cols, const gboolea if (cinfo->col_fmt[i] == COL_CUSTOM) { cinfo->col_custom_field[i] = g_strdup(get_column_custom_field(i)); + cinfo->col_custom_occurrence[i] = get_column_custom_occurrence(i); if(!dfilter_compile(cinfo->col_custom_field[i], &cinfo->col_custom_dfilter[i])) { /* XXX: Should we issue a warning? */ g_free(cinfo->col_custom_field[i]); cinfo->col_custom_field[i] = NULL; + cinfo->col_custom_occurrence[i] = 0; cinfo->col_custom_dfilter[i] = NULL; } } else { cinfo->col_custom_field[i] = NULL; + cinfo->col_custom_occurrence[i] = 0; cinfo->col_custom_dfilter[i] = NULL; } diff --git a/epan/column.h b/epan/column.h index e402eeaaae..ff8ca8eb13 100644 --- a/epan/column.h +++ b/epan/column.h @@ -33,6 +33,7 @@ typedef struct _fmt_data { gchar *title; gchar *fmt; gchar *custom_field; + gint custom_occurrence; gboolean visible; gboolean resolved; } fmt_data; @@ -48,6 +49,7 @@ void set_column_visible(const gint, gboolean); gboolean get_column_resolved(const gint); void set_column_resolved(const gint, gboolean); const gchar *get_column_custom_field(const gint); +gint get_column_custom_occurrence(const gint); const gchar *get_column_width_string(const gint, const gint); const char *get_column_longest_string(const gint); gint get_column_char_width(const gint format); diff --git a/epan/column_info.h b/epan/column_info.h index 91489c113a..bce6473417 100644 --- a/epan/column_info.h +++ b/epan/column_info.h @@ -44,7 +44,7 @@ typedef struct { gchar **col_expr_val; /**< Value for filter expression */ } col_expr_t; -/** Coulmn info */ +/** Column info */ typedef struct _column_info { gint num_cols; /**< Number of columns */ gint *col_fmt; /**< Format of column */ @@ -53,6 +53,7 @@ typedef struct _column_info { gint *col_last; /**< Last column number with a given format */ gchar **col_title; /**< Column titles */ gchar **col_custom_field; /**< Custom column field */ + gint *col_custom_occurrence;/**< Custom column field id*/ gint *col_custom_field_id; /**< Custom column field id*/ struct _dfilter_t **col_custom_dfilter; /**< Compiled custom column field */ const gchar **col_data; /**< Column data */ diff --git a/epan/epan.c b/epan/epan.c index 021958efc0..236ea20b92 100644 --- a/epan/epan.c +++ b/epan/epan.c @@ -235,10 +235,11 @@ epan_dissect_prime_dfilter(epan_dissect_t *edt, const dfilter_t* dfcode) /* ----------------------- */ const gchar * epan_custom_set(epan_dissect_t *edt, int field_id, + gint occurrence, gchar *result, gchar *expr, const int size ) { - return proto_custom_set(edt->tree, field_id, result, expr, size); + return proto_custom_set(edt->tree, field_id, occurrence, result, expr, size); } void diff --git a/epan/epan.h b/epan/epan.h index 3beb8e9047..43501d2b10 100644 --- a/epan/epan.h +++ b/epan/epan.h @@ -124,7 +124,7 @@ epan_dissect_free(epan_dissect_t* edt); /** Sets custom column */ const gchar * -epan_custom_set(epan_dissect_t *edt, int id, +epan_custom_set(epan_dissect_t *edt, int id, gint occurrence, gchar *result, gchar *expr, const int size); /** diff --git a/epan/prefs.c b/epan/prefs.c index 1368367700..6df0875f55 100644 --- a/epan/prefs.c +++ b/epan/prefs.c @@ -1139,6 +1139,7 @@ init_prefs(void) { cfmt->visible = TRUE; cfmt->resolved = TRUE; cfmt->custom_field = NULL; + cfmt->custom_occurrence = 0; prefs.col_list = g_list_append(prefs.col_list, cfmt); } prefs.num_cols = DEF_NUM_COLS; @@ -1933,7 +1934,7 @@ try_convert_to_custom_column(gpointer *el_data) haystack_fmt = col_format_to_string(migrated_columns[haystack_idx].el); if (strcmp(haystack_fmt, *fmt) == 0) { - gchar *cust_col = g_strdup_printf("%%Cus:%s", + gchar *cust_col = g_strdup_printf("%%Cus:%s:0", migrated_columns[haystack_idx].col_expr); g_free(*fmt); @@ -1957,6 +1958,7 @@ set_pref(gchar *pref_name, gchar *value, void *private_data _U_) module_t *module; pref_t *pref; gboolean had_a_dot; + gchar **cust_format_info; const gchar *cust_format = col_format_to_string(COL_CUSTOM); size_t cust_format_len = strlen(cust_format); @@ -2035,11 +2037,19 @@ set_pref(gchar *pref_name, gchar *value, void *private_data _U_) if (strncmp(col_l_elt->data, cust_format, cust_format_len) == 0) { cfmt->fmt = g_strdup(cust_format); prefs_fmt = g_strdup(col_l_elt->data); - cfmt->custom_field = g_strdup(&prefs_fmt[cust_format_len+1]); /* add 1 for ':' */ + cust_format_info = g_strsplit(&prefs_fmt[cust_format_len+1],":",2); /* add 1 for ':' */ + cfmt->custom_field = g_strdup(cust_format_info[0]); + if (cfmt->custom_field && cust_format_info[1]) { + cfmt->custom_occurrence = (int)strtol(cust_format_info[1],NULL,10); + } else { + cfmt->custom_occurrence = 0; + } + g_strfreev(cust_format_info); } else { cfmt->fmt = g_strdup(col_l_elt->data); prefs_fmt = g_strdup(cfmt->fmt); cfmt->custom_field = NULL; + cfmt->custom_occurrence = 0; } cfmt->visible = prefs_is_column_hidden (cols_hidden_list, prefs_fmt) ? FALSE : TRUE; cfmt->resolved = TRUE; @@ -3067,7 +3077,7 @@ write_prefs(char **pf_path_return) cfmt = (fmt_data *) clp->data; col_l = g_list_append(col_l, g_strdup(cfmt->title)); if ((strcmp(cfmt->fmt, cust_format) == 0) && (cfmt->custom_field)) { - prefs_fmt = g_strdup_printf("%s:%s", cfmt->fmt, cfmt->custom_field); + prefs_fmt = g_strdup_printf("%s:%s:%d", cfmt->fmt, cfmt->custom_field, cfmt->custom_occurrence); col_l = g_list_append(col_l, prefs_fmt); } else { prefs_fmt = cfmt->fmt; @@ -3311,8 +3321,10 @@ copy_prefs(e_prefs *dest, e_prefs *src) dest_cfmt->fmt = g_strdup(src_cfmt->fmt); if (src_cfmt->custom_field) { dest_cfmt->custom_field = g_strdup(src_cfmt->custom_field); + dest_cfmt->custom_occurrence = src_cfmt->custom_occurrence; } else { dest_cfmt->custom_field = NULL; + dest_cfmt->custom_occurrence = 0; } dest_cfmt->visible = src_cfmt->visible; dest_cfmt->resolved = src_cfmt->resolved; diff --git a/epan/proto.c b/epan/proto.c index cbcb56ba30..65bd3bfdbf 100644 --- a/epan/proto.c +++ b/epan/proto.c @@ -3418,8 +3418,8 @@ proto_tree_set_representation(proto_item *pi, const char *format, va_list ap) /* -------------------------- */ const gchar * -proto_custom_set(proto_tree* tree, const int field_id, gchar *result, - gchar *expr, const int size) +proto_custom_set(proto_tree* tree, const int field_id, gint occurrence, + gchar *result, gchar *expr, const int size) { guint32 u_integer; gint32 integer; @@ -3430,7 +3430,7 @@ proto_custom_set(proto_tree* tree, const int field_id, gchar *result, guint32 n_addr; /* network-order IPv4 address */ const true_false_string *tfstring; - int len; + int len, last, i, offset=0; GPtrArray *finfos; field_info *finfo; header_field_info* hfinfo; @@ -3450,172 +3450,207 @@ proto_custom_set(proto_tree* tree, const int field_id, gchar *result, hfinfo = hfinfo->same_name_next; continue; } - /* get the last one */ - finfo = g_ptr_array_index(finfos, len -1); - switch(hfinfo->type) { + /* Are there enough occurrences of the field? */ + if ((occurrence > len) || (occurrence < -len) ) + return ""; - case FT_NONE: /* Nothing to add */ - result[0] = '\0'; - break; + /* calculate single index or set outer bounderies */ + if (occurrence < 0) { + i = occurrence + len; + last = i; + } else if (occurrence > 0) { + i = occurrence - 1; + last = i; + } else { + i = 0; + last = len - 1; + } - case FT_PROTOCOL: - g_strlcpy(result, "Yes", size); - break; + while (i <= last) { + finfo = g_ptr_array_index(finfos, i); - case FT_UINT_BYTES: - case FT_BYTES: - bytes = fvalue_get(&finfo->value); - g_strlcpy(result, bytes_to_str(bytes, fvalue_length(&finfo->value)), size); - break; + if (offset && (offset < size-2)) + result[offset++]=','; - case FT_ABSOLUTE_TIME: - g_strlcpy(result, - abs_time_to_str(fvalue_get(&finfo->value), hfinfo->display, TRUE), - size); - break; + switch(hfinfo->type) { - case FT_RELATIVE_TIME: - g_strlcpy(result, rel_time_to_secs_str(fvalue_get(&finfo->value)), size); - break; + case FT_NONE: /* Nothing to add */ + result[0] = '\0'; + break; - case FT_BOOLEAN: - u_integer = fvalue_get_uinteger(&finfo->value); - tfstring = (const true_false_string *)&tfs_true_false; - if (hfinfo->strings) { - tfstring = (const struct true_false_string*) hfinfo->strings; - } - g_strlcpy(result, u_integer ? tfstring->true_string : tfstring->false_string, size); - break; + case FT_PROTOCOL: + /* prevent multiple "yes" entries by setting result directly */ + g_strlcpy(result, "Yes", size); + break; - case FT_UINT8: - case FT_UINT16: - case FT_UINT24: - case FT_UINT32: - case FT_FRAMENUM: - u_integer = fvalue_get_uinteger(&finfo->value); - if (hfinfo->strings) { - if (hfinfo->display & BASE_RANGE_STRING) { - g_strlcpy(result, rval_to_str(u_integer, hfinfo->strings, "%u"), size); - } else if (hfinfo->display & BASE_EXT_STRING) { - g_strlcpy(result, val_to_str_ext(u_integer, (value_string_ext *) (hfinfo->strings), "%u"), size); - } else { - g_strlcpy(result, val_to_str(u_integer, cVALS(hfinfo->strings), "%u"), size); - } - } else if (IS_BASE_DUAL(hfinfo->display)) { - g_snprintf(result, size, hfinfo_uint_value_format(hfinfo), u_integer, u_integer); - } else { - g_snprintf(result, size, hfinfo_uint_value_format(hfinfo), u_integer); - } - break; + case FT_UINT_BYTES: + case FT_BYTES: + bytes = fvalue_get(&finfo->value); + offset += g_strlcpy(result+offset, bytes_to_str(bytes, fvalue_length(&finfo->value)), size-offset); + break; - case FT_INT64: - case FT_UINT64: - g_snprintf(result, size, "%" G_GINT64_MODIFIER "u", fvalue_get_integer64(&finfo->value)); - break; + case FT_ABSOLUTE_TIME: + offset += g_strlcpy(result+offset, + abs_time_to_str(fvalue_get(&finfo->value), hfinfo->display, TRUE), + size-offset); + break; - /* XXX - make these just FT_INT? */ - case FT_INT8: - case FT_INT16: - case FT_INT24: - case FT_INT32: - integer = fvalue_get_sinteger(&finfo->value); - if (hfinfo->strings) { - if (hfinfo->display & BASE_RANGE_STRING) { - g_strlcpy(result, rval_to_str(integer, hfinfo->strings, "%d"), size); - } else if (hfinfo->display & BASE_EXT_STRING) { - g_strlcpy(result, val_to_str_ext(integer, (value_string_ext *) (hfinfo->strings), "%d"), size); - } else { - g_strlcpy(result, val_to_str(integer, cVALS(hfinfo->strings), "%d"), size); - } - } else if (IS_BASE_DUAL(hfinfo->display)) { - g_snprintf(result, size, hfinfo_int_value_format(hfinfo), integer, integer); - } else { - g_snprintf(result, size, hfinfo_int_value_format(hfinfo), integer); - } - break; + case FT_RELATIVE_TIME: + offset += g_strlcpy(result+offset, rel_time_to_secs_str(fvalue_get(&finfo->value)), size-offset); + break; - case FT_IPv4: - ipv4 = fvalue_get(&finfo->value); - n_addr = ipv4_get_net_order_addr(ipv4); - g_strlcpy(result, ip_to_str((guint8 *)&n_addr), size); - break; + case FT_BOOLEAN: + u_integer = fvalue_get_uinteger(&finfo->value); + tfstring = (const true_false_string *)&tfs_true_false; + if (hfinfo->strings) { + tfstring = (const struct true_false_string*) hfinfo->strings; + } + offset += g_strlcpy(result+offset, u_integer ? tfstring->true_string : tfstring->false_string, size-offset); + break; - case FT_IPv6: - ipv6 = fvalue_get(&finfo->value); - SET_ADDRESS (&addr, AT_IPv6, sizeof(struct e_in6_addr), ipv6); - address_to_str_buf(&addr, result, size); - break; + case FT_UINT8: + case FT_UINT16: + case FT_UINT24: + case FT_UINT32: + case FT_FRAMENUM: + u_integer = fvalue_get_uinteger(&finfo->value); + if (hfinfo->strings) { + if (hfinfo->display & BASE_RANGE_STRING) { + offset += g_strlcpy(result+offset, rval_to_str(u_integer, hfinfo->strings, "%u"), size-offset); + } else if (hfinfo->display & BASE_EXT_STRING) { + offset += g_strlcpy(result+offset, val_to_str_ext(u_integer, (value_string_ext *) (hfinfo->strings), "%u"), size-offset); + } else { + offset += g_strlcpy(result+offset, val_to_str(u_integer, cVALS(hfinfo->strings), "%u"), size-offset); + } + } else if (IS_BASE_DUAL(hfinfo->display)) { + g_snprintf(result+offset, size-offset, hfinfo_uint_value_format(hfinfo), u_integer, u_integer); + offset = strlen(result); + } else { + g_snprintf(result+offset, size-offset, hfinfo_uint_value_format(hfinfo), u_integer); + offset = strlen(result); + } + break; - case FT_ETHER: - g_strlcpy(result, bytes_to_str_punct(fvalue_get(&finfo->value), 6, ':'), size); - break; + case FT_INT64: + case FT_UINT64: + g_snprintf(result+offset, size-offset, "%" G_GINT64_MODIFIER "u", fvalue_get_integer64(&finfo->value)); + offset = strlen(result); + break; - case FT_GUID: - g_strlcpy(result, guid_to_str((e_guid_t *)fvalue_get(&finfo->value)), size); - break; + /* XXX - make these just FT_INT? */ + case FT_INT8: + case FT_INT16: + case FT_INT24: + case FT_INT32: + integer = fvalue_get_sinteger(&finfo->value); + if (hfinfo->strings) { + if (hfinfo->display & BASE_RANGE_STRING) { + offset += g_strlcpy(result+offset, rval_to_str(integer, hfinfo->strings, "%d"), size-offset); + } else if (hfinfo->display & BASE_EXT_STRING) { + offset += g_strlcpy(result+offset, val_to_str_ext(integer, (value_string_ext *) (hfinfo->strings), "%d"), size-offset); + } else { + offset += g_strlcpy(result+offset, val_to_str(integer, cVALS(hfinfo->strings), "%d"), size-offset); + } + } else if (IS_BASE_DUAL(hfinfo->display)) { + g_snprintf(result+offset, size-offset, hfinfo_int_value_format(hfinfo), integer, integer); + offset = strlen(result); + } else { + g_snprintf(result+offset, size-offset, hfinfo_int_value_format(hfinfo), integer); + offset = strlen(result); + } + break; - case FT_OID: - bytes = fvalue_get(&finfo->value); - g_strlcpy(result, oid_resolved_from_encoded(bytes, fvalue_length(&finfo->value)), size); - break; + case FT_IPv4: + ipv4 = fvalue_get(&finfo->value); + n_addr = ipv4_get_net_order_addr(ipv4); + offset += g_strlcpy(result+offset, ip_to_str((guint8 *)&n_addr), size-offset); + break; - case FT_FLOAT: - g_snprintf(result, size, "%." STRINGIFY(FLT_DIG) "f", fvalue_get_floating(&finfo->value)); - break; + case FT_IPv6: + ipv6 = fvalue_get(&finfo->value); + SET_ADDRESS (&addr, AT_IPv6, sizeof(struct e_in6_addr), ipv6); + address_to_str_buf(&addr, result+offset, size-offset); + offset = strlen(result); + break; - case FT_DOUBLE: - g_snprintf(result, size, "%." STRINGIFY(DBL_DIG) "g", fvalue_get_floating(&finfo->value)); - break; + case FT_ETHER: + offset += g_strlcpy(result+offset, bytes_to_str_punct(fvalue_get(&finfo->value), 6, ':'), size-offset); + break; - case FT_EBCDIC: - case FT_STRING: - case FT_STRINGZ: - case FT_UINT_STRING: - bytes = fvalue_get(&finfo->value); - g_strlcpy(result, format_text(bytes, strlen(bytes)), size); - break; + case FT_GUID: + offset += g_strlcpy(result+offset, guid_to_str((e_guid_t *)fvalue_get(&finfo->value)), size-offset); + break; - case FT_IPXNET: /*XXX really No column custom ?*/ - case FT_PCRE: - default: - g_error("hfinfo->type %d (%s) not handled\n", - hfinfo->type, - ftype_name(hfinfo->type)); - DISSECTOR_ASSERT_NOT_REACHED(); - break; - } + case FT_OID: + bytes = fvalue_get(&finfo->value); + offset += g_strlcpy(result+offset, oid_resolved_from_encoded(bytes, fvalue_length(&finfo->value)), size-offset); + break; - switch(hfinfo->type) { + case FT_FLOAT: + g_snprintf(result+offset, size-offset, "%." STRINGIFY(FLT_DIG) "f", fvalue_get_floating(&finfo->value)); + offset = strlen(result); + break; - case FT_BOOLEAN: - g_snprintf(expr, size, "%u", fvalue_get_uinteger(&finfo->value) ? 1 : 0); - break; + case FT_DOUBLE: + g_snprintf(result+offset, size-offset, "%." STRINGIFY(DBL_DIG) "g", fvalue_get_floating(&finfo->value)); + offset = strlen(result); + break; - case FT_UINT8: - case FT_UINT16: - case FT_UINT24: - case FT_UINT32: - case FT_FRAMENUM: - g_snprintf(expr, size, hfinfo_numeric_value_format(hfinfo), fvalue_get_uinteger(&finfo->value)); - break; + case FT_EBCDIC: + case FT_STRING: + case FT_STRINGZ: + case FT_UINT_STRING: + bytes = fvalue_get(&finfo->value); + offset += g_strlcpy(result+offset, format_text(bytes, strlen(bytes)), size-offset); + break; - case FT_INT8: - case FT_INT16: - case FT_INT24: - case FT_INT32: - g_snprintf(expr, size, hfinfo_numeric_value_format(hfinfo), fvalue_get_sinteger(&finfo->value)); - break; + case FT_IPXNET: /*XXX really No column custom ?*/ + case FT_PCRE: + default: + g_error("hfinfo->type %d (%s) not handled\n", + hfinfo->type, + ftype_name(hfinfo->type)); + DISSECTOR_ASSERT_NOT_REACHED(); + break; + } + i++; + } - case FT_OID: - bytes = fvalue_get(&finfo->value); - g_strlcpy(expr, oid_encoded2string(bytes, fvalue_length(&finfo->value)), size); - break; + if(occurrence) { + switch(hfinfo->type) { - default: - g_strlcpy(expr, result, size); - break; - } + case FT_BOOLEAN: + g_snprintf(expr, size, "%u", fvalue_get_uinteger(&finfo->value) ? 1 : 0); + break; + + case FT_UINT8: + case FT_UINT16: + case FT_UINT24: + case FT_UINT32: + case FT_FRAMENUM: + g_snprintf(expr, size, hfinfo_numeric_value_format(hfinfo), fvalue_get_uinteger(&finfo->value)); + break; + + case FT_INT8: + case FT_INT16: + case FT_INT24: + case FT_INT32: + g_snprintf(expr, size, hfinfo_numeric_value_format(hfinfo), fvalue_get_sinteger(&finfo->value)); + break; + + case FT_OID: + bytes = fvalue_get(&finfo->value); + g_strlcpy(expr, oid_encoded2string(bytes, fvalue_length(&finfo->value)), size); + break; + + default: + g_strlcpy(expr, result, size); + break; + } + } + /*XXSLBXX*/ + return hfinfo->abbrev; } return ""; diff --git a/epan/proto.h b/epan/proto.h index ee672a7555..19aff82ff7 100644 --- a/epan/proto.h +++ b/epan/proto.h @@ -1822,11 +1822,13 @@ proto_check_field_name(const gchar *field_name); /** Check if given string is a valid field name @param tree the tree to append this item to @param field_id the field id used for custom column + @param occurrence the occurrence of the field used for custom column @param result the buffer to fill with the field string @param expr the filter expression @param size the size of the string buffer */ const gchar * proto_custom_set(proto_tree* tree, const int field_id, + gint occurrence, gchar *result, gchar *expr, const int size ); diff --git a/gtk/main.c b/gtk/main.c index d70880e382..994801fb1a 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -897,7 +897,7 @@ void apply_as_custom_column_cb (GtkWidget *widget _U_, gpointer data _U_) { if (cfile.finfo_selected) { column_prefs_add_custom(COL_CUSTOM, cfile.finfo_selected->hfinfo->name, - cfile.finfo_selected->hfinfo->abbrev); + cfile.finfo_selected->hfinfo->abbrev,0); /* Recreate the packet list according to new preferences */ #ifdef NEW_PACKET_LIST new_packet_list_recreate (); diff --git a/gtk/main_packet_list.c b/gtk/main_packet_list.c index fae0a0fd0d..50f6b84796 100644 --- a/gtk/main_packet_list.c +++ b/gtk/main_packet_list.c @@ -1244,7 +1244,7 @@ packet_list_recent_write_all(FILE *rf) fprintf (rf, "%s:", RECENT_KEY_COL_WIDTH); for (col = 0; col < cfile.cinfo.num_cols; col++) { if (cfile.cinfo.col_fmt[col] == COL_CUSTOM) { - fprintf (rf, " %%Cus:%s,", get_column_custom_field(col)); + fprintf (rf, " %%Cus:%s:%d,", get_column_custom_field(col),get_column_custom_occurrence(col)); } else { fprintf (rf, " %s,", col_format_to_string(cfile.cinfo.col_fmt[col])); } diff --git a/gtk/new_packet_list.c b/gtk/new_packet_list.c index d71a79caf7..92b108d6d9 100644 --- a/gtk/new_packet_list.c +++ b/gtk/new_packet_list.c @@ -1493,7 +1493,7 @@ new_packet_list_recent_write_all(FILE *rf) for (col = 0; col < num_cols; col++) { col_fmt = get_column_format(col); if (col_fmt == COL_CUSTOM) { - fprintf (rf, " %%Cus:%s,", get_column_custom_field(col)); + fprintf (rf, " %%Cus:%s:%d,", get_column_custom_field(col),get_column_custom_occurrence(col)); } else { fprintf (rf, " %s,", col_format_to_string(col_fmt)); } diff --git a/gtk/prefs_column.c b/gtk/prefs_column.c index a36dd0b205..e41da57e1f 100644 --- a/gtk/prefs_column.c +++ b/gtk/prefs_column.c @@ -49,9 +49,10 @@ #include "gtk/filter_autocomplete.h" -static GtkWidget *remove_bt, *field_te, *field_lb, *fmt_cmb; +static GtkWidget *remove_bt, *field_te, *field_lb, *occurrence_te, *occurrence_lb, *fmt_cmb; static gulong column_menu_changed_handler_id; static gulong column_field_changed_handler_id; +static gulong column_occurrence_changed_handler_id; static gulong column_row_deleted_handler_id; static void column_list_new_cb(GtkWidget *, gpointer); @@ -59,9 +60,12 @@ static void column_list_delete_cb(GtkWidget *, gpointer); static void column_list_select_cb(GtkTreeSelection *, gpointer); static void column_menu_changed_cb(GtkWidget *, gpointer); static void column_field_changed_cb(GtkEditable *, gpointer); +static void column_occurrence_changed_cb(GtkEditable *, gpointer); static void column_dnd_row_deleted_cb(GtkTreeModel *, GtkTreePath *, gpointer); static gboolean column_title_changed_cb(GtkCellRendererText *, const gchar *, const gchar *, gpointer); +static char custom_occurrence_str[8] = ""; + enum { #ifdef NEW_PACKET_LIST VISIBLE_COLUMN, @@ -196,12 +200,17 @@ column_prefs_show(GtkWidget *prefs_window) { cfmt = (fmt_data *) clp->data; cur_fmt = get_column_format_from_str(cfmt->fmt); if (cur_fmt == COL_CUSTOM) { - fmt = g_strdup_printf("%s (%s)", col_format_desc(cur_fmt), cfmt->custom_field); + if (cfmt->custom_occurrence) { + fmt = g_strdup_printf("%s (%s#%d)", col_format_desc(cur_fmt), cfmt->custom_field, cfmt->custom_occurrence); + } else { + fmt = g_strdup_printf("%s (%s)", col_format_desc(cur_fmt), cfmt->custom_field); + } } else { if (cfmt->custom_field) { /* Delete custom_field from previous changes */ g_free (cfmt->custom_field); cfmt->custom_field = NULL; + cfmt->custom_occurrence = 0; } fmt = g_strdup_printf("%s", col_format_desc(cur_fmt)); } @@ -257,7 +266,7 @@ column_prefs_show(GtkWidget *prefs_window) { gtk_widget_show(props_fr); /* Column name entry and format selection */ - tb = gtk_table_new(2, 2, FALSE); + tb = gtk_table_new(2, 4, FALSE); gtk_container_set_border_width(GTK_CONTAINER(tb), 5); gtk_container_add(GTK_CONTAINER(props_fr), tb); gtk_table_set_row_spacings(GTK_TABLE(tb), 10); @@ -265,7 +274,7 @@ column_prefs_show(GtkWidget *prefs_window) { gtk_widget_show(tb); lb = gtk_label_new("Field type:"); - gtk_misc_set_alignment(GTK_MISC(lb), 1.0f, 0.5f); + gtk_misc_set_alignment(GTK_MISC(lb), 0.0f, 0.5f); gtk_table_attach_defaults(GTK_TABLE(tb), lb, 0, 1, 0, 1); gtk_tooltips_set_tip (tooltips, lb, "Select which packet information to present in the column.", NULL); @@ -278,7 +287,7 @@ column_prefs_show(GtkWidget *prefs_window) { gtk_widget_show(props_hb); field_lb = gtk_label_new("Field name:"); - gtk_misc_set_alignment(GTK_MISC(field_lb), 1.0f, 0.5f); + gtk_misc_set_alignment(GTK_MISC(field_lb), 0.0f, 0.5f); gtk_table_attach_defaults(GTK_TABLE(tb), field_lb, 0, 1, 1, 2); gtk_widget_set_sensitive(field_lb, FALSE); gtk_tooltips_set_tip (tooltips, field_lb, @@ -307,6 +316,30 @@ column_prefs_show(GtkWidget *prefs_window) { "This string has the same syntax as a display filter string.", NULL); gtk_widget_show(field_te); + occurrence_lb = gtk_label_new("Field occurrence:"); + gtk_misc_set_alignment(GTK_MISC(occurrence_lb), 0.0f, 0.5f); + gtk_table_attach_defaults(GTK_TABLE(tb), occurrence_lb, 2, 3, 1, 2); + gtk_widget_set_sensitive(occurrence_lb, FALSE); + gtk_tooltips_set_tip (tooltips, occurrence_lb, + "Field occurence to use. " + "0=all (default), 1=first, 2=second, ..., -1=last.", NULL); + gtk_widget_show(occurrence_lb); + + occurrence_te = gtk_entry_new(); + g_object_set_data (G_OBJECT(occurrence_te), "occurrence", ""); + + /* XXX: column_occurrence_changed_cb will be called for every character entered in the entry box. */ + /* Consider Changing logic so that the field is "accepted" only when a return is entered ?? */ + column_occurrence_changed_handler_id = + g_signal_connect(occurrence_te, "changed", G_CALLBACK(column_occurrence_changed_cb), column_l); + + gtk_table_attach_defaults(GTK_TABLE(tb), occurrence_te, 3, 4, 1, 2); + gtk_widget_set_sensitive(occurrence_te, FALSE); + gtk_tooltips_set_tip (tooltips, occurrence_te, + "Field occurence to use. " + "0=all (default), 1=first, 2=second, ..., -1=last.", NULL); + gtk_widget_show(occurrence_te); + fmt_cmb = gtk_combo_box_new_text(); for (i = 0; i < NUM_COL_FMTS; i++) @@ -326,7 +359,7 @@ column_prefs_show(GtkWidget *prefs_window) { } void -column_prefs_add_custom(gint fmt, const gchar *title, const gchar *custom_field) +column_prefs_add_custom(gint fmt, const gchar *title, const gchar *custom_field, gint custom_occurrence) { GList *clp; fmt_data *cfmt, *last_cfmt; @@ -340,6 +373,7 @@ column_prefs_add_custom(gint fmt, const gchar *title, const gchar *custom_field) cfmt->title = g_strdup(title); cfmt->fmt = g_strdup(col_format_to_string(fmt)); cfmt->custom_field = g_strdup(custom_field); + cfmt->custom_occurrence = custom_occurrence; cfmt->resolved = TRUE; if (custom_field) { @@ -394,7 +428,7 @@ column_list_new_cb(GtkWidget *w _U_, gpointer data) { GtkTreeViewColumn *title_column; cur_fmt = COL_NUMBER; /* Set the default new column type */ - column_prefs_add_custom (cur_fmt, title, NULL); + column_prefs_add_custom (cur_fmt, title, NULL, 0); model = gtk_tree_view_get_model(column_l); #if GTK_CHECK_VERSION(2,6,0) @@ -546,15 +580,24 @@ column_list_select_cb(GtkTreeSelection *sel, gpointer data _U_) g_signal_handler_unblock(fmt_cmb, column_menu_changed_handler_id); g_signal_handler_block (field_te, column_field_changed_handler_id); + g_signal_handler_block (occurrence_te, column_occurrence_changed_handler_id); if (cur_fmt == COL_CUSTOM) { gtk_entry_set_text(GTK_ENTRY(field_te), cfmt->custom_field); gtk_widget_set_sensitive(field_lb, TRUE); gtk_widget_set_sensitive(field_te, TRUE); + g_snprintf(custom_occurrence_str, sizeof(custom_occurrence_str), "%d", cfmt->custom_occurrence); + gtk_entry_set_text(GTK_ENTRY(occurrence_te), custom_occurrence_str); + gtk_widget_set_sensitive(occurrence_lb, TRUE); + gtk_widget_set_sensitive(occurrence_te, TRUE); } else { gtk_editable_delete_text(GTK_EDITABLE(field_te), 0, -1); gtk_widget_set_sensitive(field_lb, FALSE); gtk_widget_set_sensitive(field_te, FALSE); + gtk_editable_delete_text(GTK_EDITABLE(occurrence_te), 0, -1); + gtk_widget_set_sensitive(occurrence_lb, FALSE); + gtk_widget_set_sensitive(occurrence_te, FALSE); } + g_signal_handler_unblock(occurrence_te, column_occurrence_changed_handler_id); g_signal_handler_unblock(field_te, column_field_changed_handler_id); gtk_widget_set_sensitive(remove_bt, TRUE); @@ -563,9 +606,11 @@ column_list_select_cb(GtkTreeSelection *sel, gpointer data _U_) else { gtk_editable_delete_text(GTK_EDITABLE(field_te), 0, -1); + gtk_editable_delete_text(GTK_EDITABLE(occurrence_te), 0, -1); gtk_widget_set_sensitive(remove_bt, FALSE); gtk_widget_set_sensitive(field_te, FALSE); + gtk_widget_set_sensitive(occurrence_te, FALSE); gtk_widget_set_sensitive(fmt_cmb, FALSE); } } @@ -615,12 +660,16 @@ column_menu_changed_cb(GtkWidget *w, gpointer data) { /* Update field widgets, list_store, column format array */ /* entry as appropriate. */ g_signal_handler_block (field_te, column_field_changed_handler_id); + g_signal_handler_block (occurrence_te, column_occurrence_changed_handler_id); if (cur_fmt == COL_CUSTOM) { /* Changing from custom to non-custom */ gtk_editable_delete_text(GTK_EDITABLE(field_te), 0, -1); + gtk_editable_delete_text(GTK_EDITABLE(occurrence_te), 0, -1); fmt = g_strdup_printf("%s", col_format_desc(cur_cb_fmt)); gtk_widget_set_sensitive(field_lb, FALSE); gtk_widget_set_sensitive(field_te, FALSE); + gtk_widget_set_sensitive(occurrence_lb, FALSE); + gtk_widget_set_sensitive(occurrence_te, FALSE); } else if (cur_cb_fmt == COL_CUSTOM) { /* Changing from non-custom to custom */ @@ -628,14 +677,24 @@ column_menu_changed_cb(GtkWidget *w, gpointer data) { cfmt->custom_field = g_strdup(""); /* The following doesn't trigger a call to menu_field_changed_cb() */ gtk_entry_set_text(GTK_ENTRY(field_te), cfmt->custom_field); - fmt = g_strdup_printf("%s (%s)", col_format_desc(cur_cb_fmt), cfmt->custom_field); + g_snprintf(custom_occurrence_str, sizeof(custom_occurrence_str), "%d", cfmt->custom_occurrence); + gtk_entry_set_text(GTK_ENTRY(occurrence_te), custom_occurrence_str); + + if (cfmt->custom_occurrence) { + fmt = g_strdup_printf("%s (%s#%d)", col_format_desc(cur_cb_fmt), cfmt->custom_field, cfmt->custom_occurrence); + } else { + fmt = g_strdup_printf("%s (%s)", col_format_desc(cur_cb_fmt), cfmt->custom_field); + } gtk_widget_set_sensitive(field_lb, TRUE); gtk_widget_set_sensitive(field_te, TRUE); + gtk_widget_set_sensitive(occurrence_lb, TRUE); + gtk_widget_set_sensitive(occurrence_te, TRUE); } else { /* Changing from non-custom to non-custom */ fmt = g_strdup_printf("%s", col_format_desc(cur_cb_fmt)); } + g_signal_handler_unblock(occurrence_te, column_occurrence_changed_handler_id); g_signal_handler_unblock(field_te, column_field_changed_handler_id); gtk_list_store_set(GTK_LIST_STORE(model), &iter, FORMAT_COLUMN, fmt, -1); @@ -680,7 +739,11 @@ column_field_changed_cb(GtkEditable *te, gpointer data) { /* The user has entered a new value in the field entry box: make the req'd changes */ cur_fmt = get_column_format_from_str(cfmt->fmt); - fmt = g_strdup_printf("%s (%s)", col_format_desc(cur_fmt), field); + if (cfmt->custom_occurrence) { + fmt = g_strdup_printf("%s (%s#%d)", col_format_desc(cur_fmt), field, cfmt->custom_occurrence); + } else { + fmt = g_strdup_printf("%s (%s)", col_format_desc(cur_fmt), field); + } gtk_list_store_set(GTK_LIST_STORE(model), &iter, FORMAT_COLUMN, fmt, -1); g_free(fmt); @@ -690,6 +753,54 @@ column_field_changed_cb(GtkEditable *te, gpointer data) { } +/* + * The user changed the custom field occurrence entry box or + * the field occurrece entry box has been updated because a new + * column row with custom format has been selected. + * If the current field entry matches that of the current + * column row, this is just an update because a new + * column row has been selected. Do nothing. + * If the two are different, then update the column row & etc. + */ +static void +column_occurrence_changed_cb(GtkEditable *te, gpointer data) { + fmt_data *cfmt; + gint cur_fmt; + gint occurrence; + GList *clp; + gchar *fmt; + GtkTreeView *tree = (GtkTreeView *)data; + GtkTreeSelection *sel; + GtkTreeModel *model; + GtkTreeIter iter; + + sel = gtk_tree_view_get_selection(tree); + if ( ! (gtk_tree_selection_get_selected(sel, &model, &iter))) { + return; + } + + occurrence = (gint)strtol(gtk_editable_get_chars(te, 0, -1), NULL, 10); + gtk_tree_model_get(model, &iter, DATA_COLUMN, &clp, -1); + cfmt = (fmt_data *) clp->data; + if (cfmt->custom_occurrence == occurrence) { + return; /* no action req'd */ + } + + /* The user has entered a new value in the field occurrence entry box: make the req'd changes */ + cur_fmt = get_column_format_from_str(cfmt->fmt); + if (occurrence) { + fmt = g_strdup_printf("%s (%s#%d)", col_format_desc(cur_fmt), cfmt->custom_field, occurrence); + } else { + fmt = g_strdup_printf("%s (%s)", col_format_desc(cur_fmt), cfmt->custom_field); + } + + gtk_list_store_set(GTK_LIST_STORE(model), &iter, FORMAT_COLUMN, fmt, -1); + g_free(fmt); + cfmt->custom_occurrence = occurrence; + cfile.cinfo.columns_changed = TRUE; +} + + /* * Callback for the "row-deleted" signal emitted when a list item is dragged. * http://library.gnome.org/devel/gtk/stable/GtkTreeModel.html#GtkTreeModel-rows-reordered diff --git a/gtk/prefs_column.h b/gtk/prefs_column.h index 639308616f..1a2d4747ad 100644 --- a/gtk/prefs_column.h +++ b/gtk/prefs_column.h @@ -62,7 +62,8 @@ void column_prefs_destroy(GtkWidget *widget); * @param custom_field column custom field */ void column_prefs_add_custom(gint fmt, const gchar *title, - const gchar *custom_field); + const gchar *custom_field, + gint custom_occurrence); /** Rename a column title. *