Add support for adding unit names to hf_ fields.

This was inspired by the https://www.wireshark.org/lists/wireshark-dev/201505/msg00029.html thread.

Used TCP and NTP dissectors as the guinea pig with sample use.

Documentation updates includes some unrelated cleanup just because it was noticed.

Change-Id: I59b26e1ca3b95e3473e4757f1759d7ad82976965
Reviewed-on: https://code.wireshark.org/review/19211
Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com>
Petri-Dish: Alexis La Goutte <alexis.lagoutte@gmail.com>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Michael Mann <mmann78@netscape.net>
This commit is contained in:
Michael Mann 2016-12-11 19:16:52 -05:00
parent 97b41a494c
commit 4e97f74f11
12 changed files with 381 additions and 77 deletions

View File

@ -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

View File

@ -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()
----------------------------

View File

@ -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

View File

@ -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
)

View File

@ -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

View File

@ -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 }},

View File

@ -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,

View File

@ -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

View File

@ -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 (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);
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);
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;
}

View File

@ -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)

69
epan/unit_strings.c Normal file
View File

@ -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:
*/

75
epan/unit_strings.h Normal file
View File

@ -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:
*/