diff options
author | Michael Mann <mmann78@netscape.net> | 2016-12-11 19:16:52 -0500 |
---|---|---|
committer | Michael Mann <mmann78@netscape.net> | 2016-12-13 13:08:39 +0000 |
commit | 4e97f74f1156db5c2cb139a404bc6423cebf7236 (patch) | |
tree | bce553ff7dbbe9977fb1adbfc2dc6440be0307c4 | |
parent | 97b41a494c214161b358cc99fad843a6f061b283 (diff) | |
download | wireshark-4e97f74f1156db5c2cb139a404bc6423cebf7236.tar.gz |
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>
-rw-r--r-- | debian/libwireshark0.symbols | 10 | ||||
-rw-r--r-- | doc/README.dissector | 34 | ||||
-rw-r--r-- | docbook/release-notes.asciidoc | 3 | ||||
-rw-r--r-- | epan/CMakeLists.txt | 1 | ||||
-rw-r--r-- | epan/Makefile.am | 2 | ||||
-rw-r--r-- | epan/dissectors/packet-ntp.c | 18 | ||||
-rw-r--r-- | epan/dissectors/packet-tcp.c | 5 | ||||
-rw-r--r-- | epan/packet.h | 1 | ||||
-rw-r--r-- | epan/proto.c | 239 | ||||
-rw-r--r-- | epan/proto.h | 1 | ||||
-rw-r--r-- | epan/unit_strings.c | 69 | ||||
-rw-r--r-- | epan/unit_strings.h | 75 |
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: + */ |