When using a custom column, make it possible to select which occurrence to show if...
authorsake <sake@f5534014-38df-0310-8fa8-9805f1628bb7>
Wed, 22 Sep 2010 20:56:14 +0000 (20:56 +0000)
committersake <sake@f5534014-38df-0310-8fa8-9805f1628bb7>
Wed, 22 Sep 2010 20:56:14 +0000 (20:56 +0000)
git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@34186 f5534014-38df-0310-8fa8-9805f1628bb7

14 files changed:
epan/column-utils.c
epan/column.c
epan/column.h
epan/column_info.h
epan/epan.c
epan/epan.h
epan/prefs.c
epan/proto.c
epan/proto.h
gtk/main.c
gtk/main_packet_list.c
gtk/new_packet_list.c
gtk/prefs_column.c
gtk/prefs_column.h

index 225eb391414941f32864d2f97c8b4cf22a1183a1..1a5b9e7f93a549a94624e25feb0a0b15a9966d2e 100644 (file)
@@ -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);
index b1b0504500f2565deb330991474aa17d505738f6..ef5a3ce5034fde6b0ddbf30f426100acf51c4dd0 100644 (file)
@@ -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;
     }
 
index e402eeaaae14d25e415d5ae6d51abf133618ca0a..ff8ca8eb1356bd6620e1f7cfdc9ed116d3216dc3 100644 (file)
@@ -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);
index 91489c113a778cabca50fd471c7dbd406cf91029..bce64734179f08e0986626a66ef97d486576d028 100644 (file)
@@ -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 */
index 021958efc02bf5de66c142a6a046fc92e4b5c726..236ea20b925356e9e376de3440409e120a2a0277 100644 (file)
@@ -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
index 3beb8e904711ba8c3c7ae11d170c3424d3e95ebb..43501d2b1081f963f35be46cbc5a4c5db9cf36c7 100644 (file)
@@ -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);
 
 /**
index 136836770092c5b1d8c377c40aa0631f62639d27..6df0875f5549a447cb533aab28da31ef2e653d0a 100644 (file)
@@ -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;
index cbcb56ba30ffea9a88547f6ac2f6cc49e197dff2..65bd3bfdbf021c404c2d0fd957494e4a008de0d2 100644 (file)
@@ -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) {
-
-               case FT_NONE: /* Nothing to add */
-                       result[0] = '\0';
-                       break;
-
-               case FT_PROTOCOL:
-                       g_strlcpy(result, "Yes", size);
-                       break;
-
-               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;
-
-               case FT_ABSOLUTE_TIME:
-                       g_strlcpy(result,
-                               abs_time_to_str(fvalue_get(&finfo->value), hfinfo->display, TRUE),
-                               size);
-                       break;
-
-               case FT_RELATIVE_TIME:
-                       g_strlcpy(result, rel_time_to_secs_str(fvalue_get(&finfo->value)), 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;
-                       }
-                       g_strlcpy(result, u_integer ? tfstring->true_string : tfstring->false_string, 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_INT64:
-               case FT_UINT64:
-                       g_snprintf(result, size, "%" G_GINT64_MODIFIER "u", fvalue_get_integer64(&finfo->value));
-                       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_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_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_ETHER:
-                       g_strlcpy(result, bytes_to_str_punct(fvalue_get(&finfo->value), 6, ':'), size);
-                       break;
-
-               case FT_GUID:
-                       g_strlcpy(result, guid_to_str((e_guid_t *)fvalue_get(&finfo->value)), size);
-                       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_FLOAT:
-                       g_snprintf(result, size, "%." STRINGIFY(FLT_DIG) "f", fvalue_get_floating(&finfo->value));
-                       break;
-
-               case FT_DOUBLE:
-                       g_snprintf(result, size, "%." STRINGIFY(DBL_DIG) "g", fvalue_get_floating(&finfo->value));
-                       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_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;
-               }
-
-               switch(hfinfo->type) {
-
-               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;
-               }
+                /* Are there enough occurrences of the field? */
+                if ((occurrence > len) || (occurrence < -len) )
+                        return "";
+
+                /* 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;
+                }
+
+                while (i <= last) {
+                        finfo = g_ptr_array_index(finfos, i);
+
+                        if (offset && (offset < size-2))
+                                result[offset++]=',';
+
+                        switch(hfinfo->type) {
+
+                        case FT_NONE: /* Nothing to add */
+                                result[0] = '\0';
+                                break;
+
+                        case FT_PROTOCOL:
+                                /* prevent multiple "yes" entries by setting result directly */
+                                g_strlcpy(result, "Yes", size); 
+                                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_ABSOLUTE_TIME:
+                                offset += g_strlcpy(result+offset,
+                                        abs_time_to_str(fvalue_get(&finfo->value), hfinfo->display, TRUE),
+                                        size-offset);
+                                break;
+
+                        case FT_RELATIVE_TIME:
+                                offset += g_strlcpy(result+offset, rel_time_to_secs_str(fvalue_get(&finfo->value)), size-offset);
+                                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_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_INT64:
+                        case FT_UINT64:
+                                g_snprintf(result+offset, size-offset, "%" G_GINT64_MODIFIER "u", fvalue_get_integer64(&finfo->value));
+                                offset = strlen(result);
+                                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_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_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_ETHER:
+                                offset += g_strlcpy(result+offset, bytes_to_str_punct(fvalue_get(&finfo->value), 6, ':'), size-offset);
+                                break;
+
+                        case FT_GUID:
+                                offset += g_strlcpy(result+offset, guid_to_str((e_guid_t *)fvalue_get(&finfo->value)), size-offset);
+                                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;
+
+                        case FT_FLOAT:
+                                g_snprintf(result+offset, size-offset, "%." STRINGIFY(FLT_DIG) "f", fvalue_get_floating(&finfo->value));
+                                offset = strlen(result);
+                                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_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_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++;
+                }
+
+                if(occurrence) {
+                        switch(hfinfo->type) {
+
+                        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 "";
index ee672a75557d2703b9e1ce7432475e5912dae75b..19aff82ff77d4df3117949c7c5ecd256908a24bb 100644 (file)
@@ -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 );
 
index d70880e382d3ce436cc6de9b18077b12e2d04f83..994801fb1a369eef4fd5246351a412bafc5ab582 100644 (file)
@@ -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 ();
index fae0a0fd0deedd340b6f78f97f0c9111a3f58124..50f6b8479648b3efd213aa5c3b77938f86a708f8 100644 (file)
@@ -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]));
      }
index d71a79caf7f3e2880f73af5e835cea9dcb74da58..92b108d6d9397e612fc6e8b6dae4c46cbb5a7034 100644 (file)
@@ -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));
                }
index a36dd0b205f52813e79ecab45107fe52d0f7a4bc..e41da57e1f866e98bc254e7577604f7f6e4afef2 100644 (file)
 #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
index 639308616f9a3a473911bbed6d68a1bfba8ef41b..1a2d4747adec66c9f95f54d08b8b6f30f868332d 100644 (file)
@@ -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.
  *