aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--debian/libwireshark0.symbols10
-rw-r--r--doc/README.dissector34
-rw-r--r--docbook/release-notes.asciidoc3
-rw-r--r--epan/CMakeLists.txt1
-rw-r--r--epan/Makefile.am2
-rw-r--r--epan/dissectors/packet-ntp.c18
-rw-r--r--epan/dissectors/packet-tcp.c5
-rw-r--r--epan/packet.h1
-rw-r--r--epan/proto.c239
-rw-r--r--epan/proto.h1
-rw-r--r--epan/unit_strings.c69
-rw-r--r--epan/unit_strings.h75
12 files changed, 381 insertions, 77 deletions
diff --git a/debian/libwireshark0.symbols b/debian/libwireshark0.symbols
index 83a87b843f..9c8ad8f7d0 100644
--- a/debian/libwireshark0.symbols
+++ b/debian/libwireshark0.symbols
@@ -1639,6 +1639,16 @@ libwireshark.so.0 libwireshark0 #MINVER#
udp_port_to_display@Base 1.99.2
uint_to_str_back@Base 2.1.0
union_of_tap_listener_flags@Base 1.9.1
+ unit_name_string_get_value@Base 2.3.0
+ unit_name_string_get_value64@Base 2.3.0
+ units_bit_bits@Base 2.3.0
+ units_byte_bytes@Base 2.3.0
+ units_foot_feet@Base 2.3.0
+ units_millisecond_milliseconds@Base 2.3.0
+ units_milliseconds@Base 2.3.0
+ units_second_seconds@Base 2.3.0
+ units_seconds@Base 2.3.0
+ units_word_words@Base 2.3.0
unsigned_time_secs_to_str@Base 2.1.0
update_crc10_by_bytes_tvb@Base 1.99.0
uri_str_to_bytes@Base 1.9.1
diff --git a/doc/README.dissector b/doc/README.dissector
index 3c6ba01adb..a3ae632e22 100644
--- a/doc/README.dissector
+++ b/doc/README.dissector
@@ -116,7 +116,8 @@ FIELDDISPLAY --For FT_UINT{8,16,24,32,40,48,56,64} and
BASE_DEC, BASE_HEX, BASE_OCT, BASE_DEC_HEX, BASE_HEX_DEC,
BASE_CUSTOM, or BASE_NONE, possibly ORed with
- BASE_RANGE_STRING, BASE_EXT_STRING or BASE_VAL64_STRING.
+ BASE_RANGE_STRING, BASE_EXT_STRING, BASE_VAL64_STRING,
+ BASE_ALLOW_ZERO or BASE_UNIT_STRING
BASE_NONE may be used with a non-NULL FIELDCONVERT when the
numeric value of the field itself is not of significance to
@@ -988,6 +989,34 @@ used is a guint64 (instead of guint32). Instead of using the VALS()
macro for the 'strings' field in the header_field_info struct array,
'VALS64()' is used.
+-- Unit string
+Some integer fields, of type FT_UINT* and float fiels, of type FT_FLOAT
+or FT_DOUBLE, need units of measurement to help convey the field value.
+
+A 'unit_name_string' structure is a way to add a unit suffix to a field.
+
+ typedef struct unit_name_string {
+ char *singular; /* name to use for 1 unit */
+ char *plural; /* name to use for < 1 or > 1 units */
+ } unit_name_string;
+
+For fields with that unit name, you would declare a "unit_name_string":
+
+ static const unit_name_string unitname[] =
+ { "single item name" , "multiple item name" };
+
+(the second entry can be NULL if there is no plural form of the unit name.
+This is typically the case when abbreviations are used instead of full words.)
+
+There are several "common" unit name structures already defined in
+epan/unit_strings.h. Dissector authors may choose to add the unit name
+structure there rather than locally in a dissector.
+
+For hf[] array FT_(U)INT*, FT_FlOAT and FT_DOUBLE fields that need a
+'unit_name_string' struct, the 'strings' field would be set to
+'&units_second_seconds'. Furthermore, the 'display' field must be ORed
+with 'BASE_UNIT_STRING' (e.g. BASE_DEC|BASE_UNIT_STRING).
+
-- Ranges
If the field has a numeric type that might logically fit in ranges of values
one can use a range_string struct.
@@ -1826,6 +1855,9 @@ arguments are a "printf"-style format and any arguments for that format.
With these routines, unlike the proto_tree_add_XXX_format() routines,
the name of the field is added automatically as in the
proto_tree_add_XXX() functions; only the value is added with the format.
+One use case for this would be to add a unit of measurement string to
+the value of the field, however using BASE_UNIT_STRING in the hf_
+definition is now preferred.
proto_tree_add_checksum()
----------------------------
diff --git a/docbook/release-notes.asciidoc b/docbook/release-notes.asciidoc
index a162b0d547..0ed61a2782 100644
--- a/docbook/release-notes.asciidoc
+++ b/docbook/release-notes.asciidoc
@@ -40,6 +40,9 @@ since version 2.2.0:
* TShark can now export objects like the other GUI interfaces.
* Support for G.722 and G.726 codecs in the RTP Player (via the SpanDSP library).
* You can now choose the output device when playing RTP streams.
+* Added support for dissectors to include a unit name natively in their hf field.
+ A field can now automatically append "seconds" or "ms" to its value without
+ additional printf-style APIs.
//=== Removed Dissectors
diff --git a/epan/CMakeLists.txt b/epan/CMakeLists.txt
index f3c2f07fc4..ac30715037 100644
--- a/epan/CMakeLists.txt
+++ b/epan/CMakeLists.txt
@@ -167,6 +167,7 @@ set(LIBWIRESHARK_FILES
tvbuff_zlib.c
uat.c
value_string.c
+ unit_strings.c
xdlc.c
${CMAKE_SOURCE_DIR}/ws_version_info.c
)
diff --git a/epan/Makefile.am b/epan/Makefile.am
index de37f2fa53..a59d9e1b86 100644
--- a/epan/Makefile.am
+++ b/epan/Makefile.am
@@ -128,6 +128,7 @@ LIBWIRESHARK_SRC = \
tvbuff_zlib.c \
tvbuff.c \
uat.c \
+ unit_strings.c \
value_string.c \
xdlc.c
@@ -290,6 +291,7 @@ LIBWIRESHARK_INCLUDES = \
tvbuff-int.h \
uat.h \
uat-int.h \
+ unit_strings.h \
value_string.h \
x264_prt_id.h \
xdlc.h
diff --git a/epan/dissectors/packet-ntp.c b/epan/dissectors/packet-ntp.c
index cfd2cf3e3e..7c3606cc88 100644
--- a/epan/dissectors/packet-ntp.c
+++ b/epan/dissectors/packet-ntp.c
@@ -955,10 +955,7 @@ dissect_ntp_std(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ntp_tree)
*/
rootdelay = ((gint16)tvb_get_ntohs(tvb, 4)) +
(tvb_get_ntohs(tvb, 6) / 65536.0);
- proto_tree_add_double_format_value(ntp_tree, hf_ntp_rootdelay, tvb, 4, 4,
- rootdelay,
- "%9.4f sec",
- rootdelay);
+ proto_tree_add_double(ntp_tree, hf_ntp_rootdelay, tvb, 4, 4, rootdelay);
/* Root Dispersion, 32-bit unsigned fixed-point number indicating
* the nominal error relative to the primary reference source, in
@@ -966,10 +963,7 @@ dissect_ntp_std(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ntp_tree)
*/
rootdispersion = ((gint16)tvb_get_ntohs(tvb, 8)) +
(tvb_get_ntohs(tvb, 10) / 65536.0);
- proto_tree_add_double_format_value(ntp_tree, hf_ntp_rootdispersion, tvb, 8, 4,
- rootdispersion,
- "%9.4f sec",
- rootdispersion);
+ proto_tree_add_double(ntp_tree, hf_ntp_rootdispersion, tvb, 8, 4, rootdispersion);
/* Now, there is a problem with secondary servers. Standards
* asks from stratum-2 - stratum-15 servers to set this to the
@@ -1428,11 +1422,11 @@ proto_register_ntp(void)
"Peer Clock Precision", "ntp.precision", FT_INT8, BASE_DEC,
NULL, 0, "The precision of the system clock", HFILL }},
{ &hf_ntp_rootdelay, {
- "Root Delay", "ntp.rootdelay", FT_DOUBLE, BASE_NONE,
- NULL, 0, "Total round-trip delay to the reference clock", HFILL }},
+ "Root Delay", "ntp.rootdelay", FT_DOUBLE, BASE_NONE|BASE_UNIT_STRING,
+ &units_second_seconds, 0, "Total round-trip delay to the reference clock", HFILL }},
{ &hf_ntp_rootdispersion, {
- "Root Dispersion", "ntp.rootdispersion", FT_DOUBLE, BASE_NONE,
- NULL, 0, "Total dispersion to the reference clock", HFILL }},
+ "Root Dispersion", "ntp.rootdispersion", FT_DOUBLE, BASE_NONE|BASE_UNIT_STRING,
+ &units_second_seconds, 0, "Total dispersion to the reference clock", HFILL }},
{ &hf_ntp_refid, {
"Reference ID", "ntp.refid", FT_BYTES, BASE_NONE,
NULL, 0, "Particular server or reference clock being used", HFILL }},
diff --git a/epan/dissectors/packet-tcp.c b/epan/dissectors/packet-tcp.c
index 43cd8b1ba8..ba52c1ff9e 100644
--- a/epan/dissectors/packet-tcp.c
+++ b/epan/dissectors/packet-tcp.c
@@ -5982,8 +5982,7 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
}
if (tree) {
- proto_tree_add_uint_format_value(tcp_tree, hf_tcp_hdr_len, tvb, offset + 12, 1, tcph->th_hlen,
- "%u bytes", tcph->th_hlen);
+ proto_tree_add_uint(tcp_tree, hf_tcp_hdr_len, tvb, offset + 12, 1, tcph->th_hlen);
tf = proto_tree_add_uint_format(tcp_tree, hf_tcp_flags, tvb, offset + 12, 2,
tcph->th_flags, "Flags: 0x%03x (%s)", tcph->th_flags, flags_str);
field_tree = proto_item_add_subtree(tf, ett_tcp_flags);
@@ -6490,7 +6489,7 @@ proto_register_tcp(void)
NULL, HFILL }},
{ &hf_tcp_hdr_len,
- { "Header Length", "tcp.hdr_len", FT_UINT8, BASE_DEC, NULL, 0x0,
+ { "Header Length", "tcp.hdr_len", FT_UINT8, BASE_DEC|BASE_UNIT_STRING, &units_byte_bytes, 0x0,
NULL, HFILL }},
{ &hf_tcp_flags,
diff --git a/epan/packet.h b/epan/packet.h
index 461a07e0ac..060d43c1eb 100644
--- a/epan/packet.h
+++ b/epan/packet.h
@@ -31,6 +31,7 @@
#include "column-utils.h"
#include "guid-utils.h"
#include "tfs.h"
+#include "unit_strings.h"
#include "ws_symbol_export.h"
#ifdef __cplusplus
diff --git a/epan/proto.c b/epan/proto.c
index 978008fa1f..ae260f72f2 100644
--- a/epan/proto.c
+++ b/epan/proto.c
@@ -5114,13 +5114,20 @@ proto_custom_set(proto_tree* tree, GSList *field_ids, gint occurrence,
offset_r += protoo_strlcpy(result+offset_r, tmp, size-offset_r);
} else if (hfinfo->strings && hfinfo->type != FT_FRAMENUM) {
- number_out = hf_str_val = hf_try_val_to_str(number, hfinfo);
-
- if (!number_out)
- number_out = hfinfo_number_value_format_display(hfinfo, BASE_DEC, number_buf, number);
+ if (hfinfo->display & BASE_UNIT_STRING) {
+ number_out = hfinfo_numeric_value_format(hfinfo, number_buf, number);
+ offset_r += protoo_strlcpy(result+offset_r, number_out, size-offset_r);
+ hf_str_val = hf_try_val_to_str(number, hfinfo);
+ offset_r += protoo_strlcpy(result+offset_r, hf_str_val, size-offset_r);
+ }
+ else {
+ number_out = hf_str_val = hf_try_val_to_str(number, hfinfo);
- offset_r += protoo_strlcpy(result+offset_r, number_out, size-offset_r);
+ if (!number_out)
+ number_out = hfinfo_number_value_format_display(hfinfo, BASE_DEC, number_buf, number);
+ offset_r += protoo_strlcpy(result+offset_r, number_out, size-offset_r);
+ }
} else {
number_out = hfinfo_number_value_format(hfinfo, number_buf, number);
@@ -5253,14 +5260,28 @@ proto_custom_set(proto_tree* tree, GSList *field_ids, gint occurrence,
break;
case FT_FLOAT:
- g_snprintf(result+offset_r, size-offset_r,
- "%." G_STRINGIFY(FLT_DIG) "g", fvalue_get_floating(&finfo->value));
+ if (hfinfo->display & BASE_UNIT_STRING) {
+ double d_value = fvalue_get_floating(&finfo->value);
+ g_snprintf(result+offset_r, size-offset_r,
+ "%." G_STRINGIFY(FLT_DIG) "g%s", d_value,
+ unit_name_string_get_value64((guint64)d_value, (unit_name_string*)hfinfo->strings));
+ } else {
+ g_snprintf(result+offset_r, size-offset_r,
+ "%." G_STRINGIFY(FLT_DIG) "g", fvalue_get_floating(&finfo->value));
+ }
offset_r = (int)strlen(result);
break;
case FT_DOUBLE:
- g_snprintf(result+offset_r, size-offset_r,
- "%." G_STRINGIFY(DBL_DIG) "g", fvalue_get_floating(&finfo->value));
+ if (hfinfo->display & BASE_UNIT_STRING) {
+ double d_value = fvalue_get_floating(&finfo->value);
+ g_snprintf(result+offset_r, size-offset_r,
+ "%." G_STRINGIFY(DBL_DIG) "g%s", d_value,
+ unit_name_string_get_value64((guint64)d_value, (unit_name_string*)hfinfo->strings));
+ } else {
+ g_snprintf(result+offset_r, size-offset_r,
+ "%." G_STRINGIFY(DBL_DIG) "g", fvalue_get_floating(&finfo->value));
+ }
offset_r = (int)strlen(result);
break;
@@ -6357,19 +6378,31 @@ free_deregistered_field (gpointer data, gpointer user_data _U_)
}
case FT_UINT64:
case FT_INT64: {
- val64_string *vs64 = (val64_string *)hfi->strings;
- while (vs64->strptr) {
- g_free((gchar *)vs64->strptr);
- vs64++;
+ if (hfi->display & BASE_UNIT_STRING) {
+ unit_name_string *unit = (unit_name_string*)hfi->strings;
+ g_free ((gchar *)unit->singular);
+ g_free ((gchar *)unit->plural);
+ } else {
+ val64_string *vs64 = (val64_string *)hfi->strings;
+ while (vs64->strptr) {
+ g_free((gchar *)vs64->strptr);
+ vs64++;
+ }
}
break;
}
default: {
/* Other Integer types */
- value_string *vs = (value_string *)hfi->strings;
- while (vs->strptr) {
- g_free((gchar *)vs->strptr);
- vs++;
+ if (hfi->display & BASE_UNIT_STRING) {
+ unit_name_string *unit = (unit_name_string*)hfi->strings;
+ g_free ((gchar *)unit->singular);
+ g_free ((gchar *)unit->plural);
+ } else {
+ value_string *vs = (value_string *)hfi->strings;
+ while (vs->strptr) {
+ g_free((gchar *)vs->strptr);
+ vs++;
+ }
}
break;
}
@@ -6508,30 +6541,42 @@ tmp_fld_check_assert(header_field_info *hfinfo)
/* These types of fields are allowed to have value_strings,
* true_false_strings or a protocol_t struct
*/
- if (hfinfo->strings != NULL && !(
- (hfinfo->type == FT_CHAR) ||
- (hfinfo->type == FT_UINT8) ||
- (hfinfo->type == FT_UINT16) ||
- (hfinfo->type == FT_UINT24) ||
- (hfinfo->type == FT_UINT32) ||
- (hfinfo->type == FT_UINT40) ||
- (hfinfo->type == FT_UINT48) ||
- (hfinfo->type == FT_UINT56) ||
- (hfinfo->type == FT_UINT64) ||
- (hfinfo->type == FT_INT8) ||
- (hfinfo->type == FT_INT16) ||
- (hfinfo->type == FT_INT24) ||
- (hfinfo->type == FT_INT32) ||
- (hfinfo->type == FT_INT40) ||
- (hfinfo->type == FT_INT48) ||
- (hfinfo->type == FT_INT56) ||
- (hfinfo->type == FT_INT64) ||
- (hfinfo->type == FT_BOOLEAN) ||
- (hfinfo->type == FT_PROTOCOL) ||
- (hfinfo->type == FT_FRAMENUM) ))
- g_error("Field '%s' (%s) has a 'strings' value but is of type %s"
- " (which is not allowed to have strings)\n",
- hfinfo->name, hfinfo->abbrev, ftype_name(hfinfo->type));
+ if (hfinfo->strings != NULL) {
+ switch(hfinfo->type) {
+ case FT_CHAR:
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ case FT_UINT40:
+ case FT_UINT48:
+ case FT_UINT56:
+ case FT_UINT64:
+ case FT_INT8:
+ case FT_INT16:
+ case FT_INT24:
+ case FT_INT32:
+ case FT_INT40:
+ case FT_INT48:
+ case FT_INT56:
+ case FT_INT64:
+ case FT_BOOLEAN:
+ case FT_PROTOCOL:
+ case FT_FRAMENUM:
+ break;
+ case FT_FLOAT:
+ case FT_DOUBLE:
+ //allowed to support string if its a unit decsription
+ if (hfinfo->display & BASE_UNIT_STRING)
+ break;
+
+ //fallthrough
+ default:
+ g_error("Field '%s' (%s) has a 'strings' value but is of type %s"
+ " (which is not allowed to have strings)\n",
+ hfinfo->name, hfinfo->abbrev, ftype_name(hfinfo->type));
+ }
+ }
/* TODO: This check may slow down startup, and output quite a few warnings.
It would be good to be able to enable this (and possibly other checks?)
@@ -6600,7 +6645,7 @@ tmp_fld_check_assert(header_field_info *hfinfo)
* meaningless; we'll avoid showing the value to the
* user.
*/
- switch (hfinfo->display & FIELD_DISPLAY_E_MASK) {
+ switch (FIELD_DISPLAY(hfinfo->display)) {
case BASE_HEX:
case BASE_OCT:
case BASE_CUSTOM: /* hfinfo_numeric_value_format() treats this as decimal */
@@ -6621,6 +6666,11 @@ tmp_fld_check_assert(header_field_info *hfinfo)
ftype_name(hfinfo->type), tmp_str);
wmem_free(NULL, tmp_str);
}
+ if (hfinfo->display & BASE_UNIT_STRING) {
+ g_error("Field '%s' (%s) is a character value (%s) but has a unit string\n",
+ hfinfo->name, hfinfo->abbrev,
+ ftype_name(hfinfo->type));
+ }
break;
case FT_INT8:
case FT_INT16:
@@ -6695,13 +6745,15 @@ tmp_fld_check_assert(header_field_info *hfinfo)
case BASE_CUSTOM: /* hfinfo_numeric_value_format() treats this as decimal */
break;
case BASE_NONE:
- if (hfinfo->strings == NULL)
+ if (hfinfo->strings == NULL) {
g_error("Field '%s' (%s) is an integral value (%s)"
" but is being displayed as BASE_NONE but"
" without a strings conversion",
hfinfo->name, hfinfo->abbrev,
ftype_name(hfinfo->type));
+ }
break;
+
default:
tmp_str = val_to_str_wmem(NULL, hfinfo->display, hf_display, "(Unknown: 0x%x)");
g_error("Field '%s' (%s) is an integral value (%s)"
@@ -6715,7 +6767,7 @@ tmp_fld_check_assert(header_field_info *hfinfo)
/* Require bytes to have a "display type" that could
* add a character between displayed bytes.
*/
- switch (hfinfo->display & FIELD_DISPLAY_E_MASK) {
+ switch (FIELD_DISPLAY(hfinfo->display)) {
case BASE_NONE:
case SEP_DOT:
case SEP_DASH:
@@ -6815,6 +6867,25 @@ tmp_fld_check_assert(header_field_info *hfinfo)
break;
}
break;
+ case FT_FLOAT:
+ case FT_DOUBLE:
+ if (FIELD_DISPLAY(hfinfo->display) != BASE_NONE) {
+ tmp_str = val_to_str_wmem(NULL, hfinfo->display, hf_display, "(Bit count: %d)");
+ g_error("Field '%s' (%s) is an %s but is being displayed as %s instead of BASE_NONE\n",
+ hfinfo->name, hfinfo->abbrev,
+ ftype_name(hfinfo->type),
+ tmp_str);
+ wmem_free(NULL, tmp_str);
+ }
+ if (hfinfo->bitmask != 0)
+ g_error("Field '%s' (%s) is an %s but has a bitmask\n",
+ hfinfo->name, hfinfo->abbrev,
+ ftype_name(hfinfo->type));
+ if ((hfinfo->strings != NULL) && (!(hfinfo->display & BASE_UNIT_STRING)))
+ g_error("Field '%s' (%s) is an %s but has a strings value\n",
+ hfinfo->name, hfinfo->abbrev,
+ ftype_name(hfinfo->type));
+ break;
default:
if (hfinfo->display != BASE_NONE) {
tmp_str = val_to_str_wmem(NULL, hfinfo->display, hf_display, "(Bit count: %d)");
@@ -7140,10 +7211,15 @@ label_fill_descr(char *label_str, gsize pos, const header_field_info *hfinfo, co
/* "%s: %s (%s)", hfinfo->name, text, descr */
name_pos = pos = label_concat(label_str, pos, hfinfo->name);
pos = label_concat(label_str, pos, ": ");
- pos = label_concat(label_str, pos, text ? text : "(null)");
- pos = label_concat(label_str, pos, " (");
- pos = label_concat(label_str, pos, descr ? descr : "(null)");
- pos = label_concat(label_str, pos, ")");
+ if (hfinfo->display & BASE_UNIT_STRING) {
+ pos = label_concat(label_str, pos, descr ? descr : "(null)");
+ pos = label_concat(label_str, pos, text ? text : "(null)");
+ } else {
+ pos = label_concat(label_str, pos, text ? text : "(null)");
+ pos = label_concat(label_str, pos, " (");
+ pos = label_concat(label_str, pos, descr ? descr : "(null)");
+ pos = label_concat(label_str, pos, ")");
+ }
if (pos >= ITEM_LABEL_LENGTH) {
/* Uh oh, we don't have enough room. Tell the user that the field is truncated. */
@@ -7291,16 +7367,34 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
}
break;
- case FT_FLOAT:
- g_snprintf(label_str, ITEM_LABEL_LENGTH,
- "%s: %." G_STRINGIFY(FLT_DIG) "g",
- hfinfo->name, fvalue_get_floating(&fi->value));
+ case FT_FLOAT: {
+ double d_value = fvalue_get_floating(&fi->value);
+ if (hfinfo->display & BASE_UNIT_STRING) {
+ g_snprintf(label_str, ITEM_LABEL_LENGTH,
+ "%s: %." G_STRINGIFY(FLT_DIG) "g%s",
+ hfinfo->name, d_value,
+ unit_name_string_get_value64((guint64)d_value, (unit_name_string*)hfinfo->strings));
+ } else {
+ g_snprintf(label_str, ITEM_LABEL_LENGTH,
+ "%s: %." G_STRINGIFY(FLT_DIG) "g",
+ hfinfo->name, d_value);
+ }
+ }
break;
- case FT_DOUBLE:
- g_snprintf(label_str, ITEM_LABEL_LENGTH,
- "%s: %." G_STRINGIFY(DBL_DIG) "g",
- hfinfo->name, fvalue_get_floating(&fi->value));
+ case FT_DOUBLE: {
+ double d_value = fvalue_get_floating(&fi->value);
+ if (hfinfo->display & BASE_UNIT_STRING) {
+ g_snprintf(label_str, ITEM_LABEL_LENGTH,
+ "%s: %." G_STRINGIFY(DBL_DIG) "g%s",
+ hfinfo->name, d_value,
+ unit_name_string_get_value64((guint64)d_value, (unit_name_string*)hfinfo->strings));
+ } else {
+ g_snprintf(label_str, ITEM_LABEL_LENGTH,
+ "%s: %." G_STRINGIFY(DBL_DIG) "g",
+ hfinfo->name, d_value);
+ }
+ }
break;
case FT_ABSOLUTE_TIME:
@@ -7529,6 +7623,9 @@ hf_try_val_to_str(guint32 value, const header_field_info *hfinfo)
if (hfinfo->display & BASE_VAL64_STRING)
return try_val64_to_str(value, (const val64_string *) hfinfo->strings);
+ if (hfinfo->display & BASE_UNIT_STRING)
+ return unit_name_string_get_value(value, (struct unit_name_string*) hfinfo->strings);
+
return try_val_to_str(value, (const value_string *) hfinfo->strings);
}
@@ -7541,6 +7638,9 @@ hf_try_val64_to_str(guint64 value, const header_field_info *hfinfo)
if (hfinfo->display & BASE_RANGE_STRING)
return try_rval64_to_str(value, (const range_string *) hfinfo->strings);
+ if (hfinfo->display & BASE_UNIT_STRING)
+ return unit_name_string_get_value64(value, (struct unit_name_string*) hfinfo->strings);
+
/* If this is reached somebody registered a 64-bit field with a 32-bit
* value-string, which isn't right. */
DISSECTOR_ASSERT_NOT_REACHED();
@@ -8638,6 +8738,7 @@ proto_registrar_dump_values(void)
const val64_string *vals64;
const range_string *range;
const true_false_string *tfs;
+ const unit_name_string *units;
len = gpa_hfinfo.len;
for (i = 0; i < len ; i++) {
@@ -8675,6 +8776,7 @@ proto_registrar_dump_values(void)
vals64 = NULL;
range = NULL;
tfs = NULL;
+ units = NULL;
if (hfinfo->strings != NULL) {
if ((hfinfo->display & FIELD_DISPLAY_E_MASK) != BASE_CUSTOM &&
@@ -8702,6 +8804,8 @@ proto_registrar_dump_values(void)
vals = VALUE_STRING_EXT_VS_P((value_string_ext *)hfinfo->strings);
} else if (hfinfo->display & BASE_VAL64_STRING) {
vals64 = (const val64_string *)hfinfo->strings;
+ } else if (hfinfo->display & BASE_UNIT_STRING) {
+ units = (const unit_name_string *)hfinfo->strings;
} else {
vals = (const value_string *)hfinfo->strings;
}
@@ -8805,6 +8909,11 @@ proto_registrar_dump_values(void)
ws_debug_printf("T\t%s\t%s\t%s\n", hfinfo->abbrev,
tfs->true_string, tfs->false_string);
}
+ /* Print unit strings? */
+ else if (units) {
+ ws_debug_printf("U\t%s\t%s\t%s\n", hfinfo->abbrev,
+ units->singular, units->plural ? units->plural : "(no plural)");
+ }
}
}
@@ -9424,9 +9533,9 @@ proto_item_add_bitmask_tree(proto_item *item, tvbuff_t *tvb, const int offset,
hf->name, lbl);
first = FALSE;
}
- else if (hf->strings) {
+ else if ((hf->strings) &&(!(hf->display & BASE_UNIT_STRING))) {
proto_item_append_text(item, "%s%s: %s", first ? "" : ", ",
- hf->name, hf_try_val_to_str_const((guint32) tmpval, hf, "Unknown"));
+ hf->name, hf_try_val_to_str_const((guint32) tmpval, hf, "Unknown"));
first = FALSE;
}
else if (!(flags & BMT_NO_INT)) {
@@ -9438,7 +9547,11 @@ proto_item_add_bitmask_tree(proto_item *item, tvbuff_t *tvb, const int offset,
}
out = hfinfo_number_value_format(hf, buf, (guint32) tmpval);
- proto_item_append_text(item, "%s: %s", hf->name, out);
+ if (hf->display & BASE_UNIT_STRING) {
+ proto_item_append_text(item, "%s: %s%s", hf->name, out, unit_name_string_get_value((guint32) tmpval, (unit_name_string*)hf->strings));
+ } else {
+ proto_item_append_text(item, "%s: %s", hf->name, out);
+ }
first = FALSE;
}
@@ -9463,7 +9576,7 @@ proto_item_add_bitmask_tree(proto_item *item, tvbuff_t *tvb, const int offset,
hf->name, lbl);
first = FALSE;
}
- else if (hf->strings) {
+ else if ((hf->strings) &&(!(hf->display & BASE_UNIT_STRING))) {
proto_item_append_text(item, "%s%s: %s", first ? "" : ", ",
hf->name, hf_try_val_to_str_const((gint32) integer32, hf, "Unknown"));
first = FALSE;
@@ -9477,7 +9590,11 @@ proto_item_add_bitmask_tree(proto_item *item, tvbuff_t *tvb, const int offset,
}
out = hfinfo_number_value_format(hf, buf, (gint32) integer32);
- proto_item_append_text(item, "%s: %s", hf->name, out);
+ if ((hf->strings) &&(!(hf->display & BASE_UNIT_STRING))) {
+ proto_item_append_text(item, "%s: %s%s", hf->name, out, unit_name_string_get_value((guint32) tmpval, (unit_name_string*)hf->strings));
+ } else {
+ proto_item_append_text(item, "%s: %s", hf->name, out);
+ }
first = FALSE;
}
diff --git a/epan/proto.h b/epan/proto.h
index eff10a9c93..53f8dca61f 100644
--- a/epan/proto.h
+++ b/epan/proto.h
@@ -546,6 +546,7 @@ typedef enum {
#define BASE_EXT_STRING 0x200
#define BASE_VAL64_STRING 0x400
#define BASE_ALLOW_ZERO 0x800 /**< Display <none> instead of <MISSING> for zero sized byte array */
+#define BASE_UNIT_STRING 0x1000 /**< Add unit text to the field value */
/** BASE_ values that cause the field value to be displayed twice */
#define IS_BASE_DUAL(b) ((b)==BASE_DEC_HEX||(b)==BASE_HEX_DEC)
diff --git a/epan/unit_strings.c b/epan/unit_strings.c
new file mode 100644
index 0000000000..27b066937d
--- /dev/null
+++ b/epan/unit_strings.c
@@ -0,0 +1,69 @@
+/* unit_strings.c
+ * Units to append to field values
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include <wsutil/str_util.h>
+#include "unit_strings.h"
+
+char* unit_name_string_get_value(guint32 value, unit_name_string* units)
+{
+ if (units->plural == NULL)
+ return units->singular;
+
+ return plurality(value, units->singular, units->plural);
+}
+
+char* unit_name_string_get_value64(guint64 value, unit_name_string* units)
+{
+ if (units->plural == NULL)
+ return units->singular;
+
+ return plurality(value, units->singular, units->plural);
+}
+
+/*
+ * A default set of unit strings that dissectors can use for
+ * header fields. Some units intentionally have a space
+ * character in them for spacing between unit and value
+ */
+const unit_name_string units_foot_feet = { " foot", " feet" };
+const unit_name_string units_bit_bits = { " bit", " bits" };
+const unit_name_string units_byte_bytes = { " byte", " bytes" };
+const unit_name_string units_word_words = { " word", " words" };
+const unit_name_string units_second_seconds = { " second", " seconds" };
+const unit_name_string units_seconds = { "s", NULL };
+const unit_name_string units_millisecond_milliseconds = { " millisecond", " milliseconds" };
+const unit_name_string units_milliseconds = { "ms", NULL };
+
+/*
+ * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * ex: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */ \ No newline at end of file
diff --git a/epan/unit_strings.h b/epan/unit_strings.h
new file mode 100644
index 0000000000..7d2a5204cd
--- /dev/null
+++ b/epan/unit_strings.h
@@ -0,0 +1,75 @@
+/* unit_strings.h
+ * Units to append to field values
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __UNIT_STRINGS_H__
+#define __UNIT_STRINGS_H__
+
+#include "ws_symbol_export.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** @file
+ * Units to append to field values
+ */
+
+/* For BASE_UNIT_STRING, the display format for adding units */
+typedef struct unit_name_string {
+ char *singular; /* name to use for 1 unit */
+ char *plural; /* name to use for < 1 or > 1 units */
+} unit_name_string;
+
+WS_DLL_PUBLIC char* unit_name_string_get_value(guint32 value, unit_name_string* units);
+WS_DLL_PUBLIC char* unit_name_string_get_value64(guint64 value, unit_name_string* units);
+
+/*
+ * A default set of unit strings that dissectors can use for
+ * header fields.
+ */
+WS_DLL_PUBLIC const unit_name_string units_foot_feet;
+WS_DLL_PUBLIC const unit_name_string units_bit_bits;
+WS_DLL_PUBLIC const unit_name_string units_byte_bytes;
+WS_DLL_PUBLIC const unit_name_string units_word_words;
+WS_DLL_PUBLIC const unit_name_string units_second_seconds; // full unit name "second[s?]"
+WS_DLL_PUBLIC const unit_name_string units_seconds; //only seconds abbreviation "s"
+WS_DLL_PUBLIC const unit_name_string units_millisecond_milliseconds; // full unit name "millisecond[s?]"
+WS_DLL_PUBLIC const unit_name_string units_milliseconds; //only seconds abbreviation "ms"
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __UNIT_STRINGS_H__ */
+
+/*
+ * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * ex: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */