2 * Routines for column utilities.
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
19 #include "column-utils.h"
20 #include "timestamp.h"
22 #include "packet_info.h"
23 #include "wsutil/pint.h"
24 #include "addr_resolv.h"
25 #include "address_types.h"
26 #include "osi-utils.h"
27 #include "value_string.h"
28 #include "column-info.h"
32 #include <epan/strutil.h>
33 #include <epan/epan.h>
34 #include <epan/dfilter/dfilter.h>
36 #include <wsutil/inet_cidr.h>
37 #include <wsutil/utf8_entities.h>
38 #include <wsutil/ws_assert.h>
39 #include <wsutil/unicode-utils.h>
40 #include <wsutil/time_util.h>
43 #include <epan/wslua/wslua.h>
46 #define COL_BUF_MAX_LEN (((COL_MAX_INFO_LEN) > (COL_MAX_LEN)) ? \
47 (COL_MAX_INFO_LEN) : (COL_MAX_LEN))
49 /* Used for locale decimal point */
50 static char *col_decimal_point
;
52 /* Used to indicate updated column information, e.g. a new request/response. */
53 static bool col_data_changed_
;
55 static int proto_cols
;
58 /* Allocate all the data structures for constructing column data, given
59 the number of columns. */
61 col_setup(column_info
*cinfo
, const int num_cols
)
65 col_decimal_point
= localeconv()->decimal_point
;
66 cinfo
->num_cols
= num_cols
;
67 cinfo
->columns
= g_new(col_item_t
, num_cols
);
68 cinfo
->col_first
= g_new(int, NUM_COL_FMTS
);
69 cinfo
->col_last
= g_new(int, NUM_COL_FMTS
);
70 for (i
= 0; i
< num_cols
; i
++) {
71 cinfo
->columns
[i
].col_custom_fields_ids
= NULL
;
73 cinfo
->col_expr
.col_expr
= g_new(const char*, num_cols
+ 1);
74 cinfo
->col_expr
.col_expr_val
= g_new(char*, num_cols
+ 1);
76 for (i
= 0; i
< NUM_COL_FMTS
; i
++) {
77 cinfo
->col_first
[i
] = -1;
78 cinfo
->col_last
[i
] = -1;
80 cinfo
->prime_regex
= g_regex_new(COL_CUSTOM_PRIME_REGEX
,
81 (GRegexCompileFlags
) (G_REGEX_RAW
),
86 col_custom_free_cb(void *data
)
88 col_custom_t
*col_custom
= (col_custom_t
*)data
;
89 dfilter_free(col_custom
->dfilter
);
90 g_free(col_custom
->dftext
);
95 col_custom_fields_ids_free(GSList
** custom_fields_id
)
97 if (*custom_fields_id
!= NULL
) {
98 g_slist_free_full(*custom_fields_id
, col_custom_free_cb
);
100 *custom_fields_id
= NULL
;
103 /* Cleanup all the data structures for constructing column data; undoes
104 the allocations that col_setup() does. */
106 col_cleanup(column_info
*cinfo
)
109 col_item_t
* col_item
;
114 for (i
= 0; i
< cinfo
->num_cols
; i
++) {
115 col_item
= &cinfo
->columns
[i
];
116 g_free(col_item
->fmt_matx
);
117 g_free(col_item
->col_title
);
118 g_free(col_item
->col_custom_fields
);
119 dfilter_free(col_item
->col_custom_dfilter
);
120 /* col_item->col_data points to col_buf or static memory */
121 g_free(col_item
->col_buf
);
122 g_free(cinfo
->col_expr
.col_expr_val
[i
]);
123 col_custom_fields_ids_free(&col_item
->col_custom_fields_ids
);
126 g_free(cinfo
->columns
);
127 g_free(cinfo
->col_first
);
128 g_free(cinfo
->col_last
);
130 * XXX - MSVC doesn't correctly handle the "const" qualifier; it thinks
131 * "const XXX **" means "pointer to const pointer to XXX", i.e. that
132 * it's a pointer to something that's "const"ant, not "pointer to
133 * pointer to const XXX", i.e. that it's a pointer to a pointer to
134 * something that's "const"ant. Cast its bogus complaints away.
136 g_free((char **)cinfo
->col_expr
.col_expr
);
137 g_free(cinfo
->col_expr
.col_expr_val
);
138 if (cinfo
->prime_regex
)
139 g_regex_unref(cinfo
->prime_regex
);
142 /* Initialize the data structures for constructing column data. */
144 col_init(column_info
*cinfo
, const struct epan_session
*epan
)
147 col_item_t
* col_item
;
152 for (i
= 0; i
< cinfo
->num_cols
; i
++) {
153 col_item
= &cinfo
->columns
[i
];
154 col_item
->col_buf
[0] = '\0';
155 col_item
->col_data
= col_item
->col_buf
;
156 col_item
->col_fence
= 0;
157 col_item
->writable
= true;
158 cinfo
->col_expr
.col_expr
[i
] = "";
159 cinfo
->col_expr
.col_expr_val
[i
][0] = '\0';
161 cinfo
->writable
= true;
166 col_get_writable(column_info
*cinfo
, const int col
)
169 col_item_t
* col_item
;
174 /* "global" (not) writeability will always override
175 an individual column */
176 if ((col
== -1) || (cinfo
->writable
== false))
177 return cinfo
->writable
;
179 if (cinfo
->col_first
[col
] >= 0) {
180 for (i
= cinfo
->col_first
[col
]; i
<= cinfo
->col_last
[col
]; i
++) {
181 col_item
= &cinfo
->columns
[i
];
182 if (col_item
->fmt_matx
[col
]) {
183 return col_item
->writable
;
191 col_set_writable(column_info
*cinfo
, const int col
, const bool writable
)
194 col_item_t
* col_item
;
198 cinfo
->writable
= writable
;
199 } else if (cinfo
->col_first
[col
] >= 0) {
200 for (i
= cinfo
->col_first
[col
]; i
<= cinfo
->col_last
[col
]; i
++) {
201 col_item
= &cinfo
->columns
[i
];
202 if (col_item
->fmt_matx
[col
]) {
203 col_item
->writable
= writable
;
210 /* Checks to see if a particular packet information element is needed for the packet list */
211 #define CHECK_COL(cinfo, el) \
212 /* We are constructing columns, and they're writable */ \
213 (col_get_writable(cinfo, el) && \
214 /* There is at least one column in that format */ \
215 ((cinfo)->col_first[el] >= 0))
217 /* Sets the fence for a column to be at the end of the column. */
219 col_set_fence(column_info
*cinfo
, const int el
)
222 col_item_t
* col_item
;
224 if (!CHECK_COL(cinfo
, el
))
227 for (i
= cinfo
->col_first
[el
]; i
<= cinfo
->col_last
[el
]; i
++) {
228 col_item
= &cinfo
->columns
[i
];
229 if (col_item
->fmt_matx
[el
]) {
230 col_item
->col_fence
= (int)strlen(col_item
->col_data
);
235 /* Clear the fence for a column. */
237 col_clear_fence(column_info
*cinfo
, const int el
)
240 col_item_t
* col_item
;
242 if (!CHECK_COL(cinfo
, el
))
245 for (i
= cinfo
->col_first
[el
]; i
<= cinfo
->col_last
[el
]; i
++) {
246 col_item
= &cinfo
->columns
[i
];
247 if (col_item
->fmt_matx
[el
]) {
248 col_item
->col_fence
= 0;
253 /* Gets the text of a column */
255 col_get_text(column_info
*cinfo
, const int el
)
258 const char* text
= NULL
;
259 col_item_t
* col_item
;
261 if (!(cinfo
&& (cinfo
)->col_first
[el
] >= 0)) {
265 for (i
= cinfo
->col_first
[el
]; i
<= cinfo
->col_last
[el
]; i
++) {
266 col_item
= &cinfo
->columns
[i
];
267 if (col_item
->fmt_matx
[el
]) {
268 text
= (col_item
->col_data
);
275 /* Use this to clear out a column, especially if you're going to be
276 appending to it later; at least on some platforms, it's more
277 efficient than using "col_add_str()" with a null string, and
278 more efficient than "col_set_str()" with a null string if you
279 later append to it, as the later append will cause a string
282 col_clear(column_info
*cinfo
, const int el
)
285 col_item_t
* col_item
;
287 if (!CHECK_COL(cinfo
, el
))
290 for (i
= cinfo
->col_first
[el
]; i
<= cinfo
->col_last
[el
]; i
++) {
291 col_item
= &cinfo
->columns
[i
];
292 if (col_item
->fmt_matx
[el
]) {
294 * At this point, either
296 * 1) col_data[i] is equal to col_buf[i], in which case we
297 * don't have to worry about copying col_data[i] to
300 * 2) col_data[i] isn't equal to col_buf[i], in which case
301 * the only thing that's been done to the column is
302 * "col_set_str()" calls and possibly "col_set_fence()"
303 * calls, in which case the fence is either unset and
304 * at the beginning of the string or set and at the end
305 * of the string - if it's at the beginning, we're just
306 * going to clear the column, and if it's at the end,
307 * we don't do anything.
309 if (col_item
->col_buf
== col_item
->col_data
|| col_item
->col_fence
== 0) {
311 * The fence isn't at the end of the column, or the column wasn't
312 * last set with "col_set_str()", so clear the column out.
314 col_item
->col_buf
[col_item
->col_fence
] = '\0';
315 col_item
->col_data
= col_item
->col_buf
;
317 cinfo
->col_expr
.col_expr
[i
] = "";
318 cinfo
->col_expr
.col_expr_val
[i
][0] = '\0';
323 #define COL_CHECK_APPEND(col_item, max_len) \
324 if (col_item->col_data != col_item->col_buf) { \
325 /* This was set with "col_set_str()"; copy the string they \
326 set it to into the buffer, so we can append to it. */ \
327 (void) g_strlcpy(col_item->col_buf, col_item->col_data, max_len); \
328 col_item->col_data = col_item->col_buf; \
331 #define COL_CHECK_REF_TIME(fd, buf) \
332 if (fd->ref_time) { \
333 (void) g_strlcpy(buf, "*REF*", COL_MAX_LEN ); \
337 /* The same as CHECK_COL(), but without the check to see if the column is writable. */
338 #define HAVE_CUSTOM_COLS(cinfo) ((cinfo) && (cinfo)->col_first[COL_CUSTOM] >= 0)
341 have_custom_cols(column_info
*cinfo
)
343 return HAVE_CUSTOM_COLS(cinfo
);
347 have_field_extractors(void)
350 return wslua_has_field_extractors();
356 /* search in edt tree custom fields */
357 void col_custom_set_edt(epan_dissect_t
*edt
, column_info
*cinfo
)
360 col_item_t
* col_item
;
362 if (!HAVE_CUSTOM_COLS(cinfo
))
365 for (i
= cinfo
->col_first
[COL_CUSTOM
];
366 i
<= cinfo
->col_last
[COL_CUSTOM
]; i
++) {
367 col_item
= &cinfo
->columns
[i
];
368 if (col_item
->fmt_matx
[COL_CUSTOM
] &&
369 col_item
->col_custom_fields
&&
370 col_item
->col_custom_fields_ids
) {
371 col_item
->col_data
= col_item
->col_buf
;
372 cinfo
->col_expr
.col_expr
[i
] = epan_custom_set(edt
, col_item
->col_custom_fields_ids
,
373 col_item
->col_custom_occurrence
,
374 get_column_display_format(i
) == COLUMN_DISPLAY_DETAILS
,
376 cinfo
->col_expr
.col_expr_val
[i
],
383 // Needed if we create _ws.col.custom
385 col_custom_set(proto_tree
*tree
, column_info
*cinfo
)
388 col_item_t
* col_item
;
390 if (!HAVE_CUSTOM_COLS(cinfo
))
393 for (i
= cinfo
->col_first
[COL_CUSTOM
];
394 i
<= cinfo
->col_last
[COL_CUSTOM
]; i
++) {
395 col_item
= &cinfo
->columns
[i
];
396 if (col_item
->fmt_matx
[COL_CUSTOM
] &&
397 col_item
->col_custom_fields
&&
398 col_item
->col_custom_fields_ids
) {
399 col_item
->col_data
= col_item
->col_buf
;
400 cinfo
->col_expr
.col_expr
[i
] = proto_custom_set(tree
, col_item
->col_custom_fields_ids
,
401 col_item
->col_custom_occurrence
,
402 get_column_display_format(i
) == COLUMN_DISPLAY_DETAILS
,
404 cinfo
->col_expr
.col_expr_val
[i
],
412 col_custom_prime_edt(epan_dissect_t
*edt
, column_info
*cinfo
)
415 col_item_t
* col_item
;
417 if (!HAVE_CUSTOM_COLS(cinfo
))
420 for (i
= cinfo
->col_first
[COL_CUSTOM
];
421 i
<= cinfo
->col_last
[COL_CUSTOM
]; i
++) {
422 col_item
= &cinfo
->columns
[i
];
424 if (col_item
->fmt_matx
[COL_CUSTOM
] &&
425 col_item
->col_custom_dfilter
) {
426 if (get_column_display_format(i
) == COLUMN_DISPLAY_DETAILS
) {
427 epan_dissect_prime_with_dfilter_print(edt
, col_item
->col_custom_dfilter
);
429 epan_dissect_prime_with_dfilter(edt
, col_item
->col_custom_dfilter
);
436 col_custom_get_filter(epan_dissect_t
*edt
, column_info
*cinfo
, const int col
)
438 col_item_t
* col_item
;
441 ws_assert(col
< cinfo
->num_cols
);
443 col_item
= &cinfo
->columns
[col
];
444 if (col_item
->fmt_matx
[COL_CUSTOM
] &&
445 col_item
->col_custom_fields
&&
446 col_item
->col_custom_fields_ids
) {
448 return proto_custom_get_filter(edt
, col_item
->col_custom_fields_ids
,
449 col_item
->col_custom_occurrence
);
455 col_append_lstr(column_info
*cinfo
, const int el
, const char *str1
, ...)
461 col_item_t
* col_item
;
463 if (!CHECK_COL(cinfo
, el
))
467 max_len
= COL_MAX_INFO_LEN
;
469 max_len
= COL_MAX_LEN
;
471 for (i
= cinfo
->col_first
[el
]; i
<= cinfo
->col_last
[el
]; i
++) {
472 col_item
= &cinfo
->columns
[i
];
473 if (col_item
->fmt_matx
[el
]) {
475 * First arrange that we can append, if necessary.
477 COL_CHECK_APPEND(col_item
, max_len
);
479 pos
= strlen(col_item
->col_buf
);
486 if (G_UNLIKELY(str
== NULL
)) {
489 WS_UTF_8_CHECK(str
, -1);
490 pos
= ws_label_strcpy(col_item
->col_buf
, max_len
, pos
, str
, 0);
492 } while (pos
< max_len
&& (str
= va_arg(ap
, const char *)) != COL_ADD_LSTR_TERMINATOR
);
499 col_append_str_uint(column_info
*cinfo
, const int col
, const char *abbrev
, uint32_t val
, const char *sep
)
503 if (!CHECK_COL(cinfo
, col
))
506 uint32_to_str_buf(val
, buf
, sizeof(buf
));
507 col_append_lstr(cinfo
, col
, sep
? sep
: "", abbrev
, "=", buf
, COL_ADD_LSTR_TERMINATOR
);
511 col_snprint_port(char *buf
, size_t buf_siz
, port_type typ
, uint16_t val
)
515 if (gbl_resolv_flags
.transport_name
&&
516 (str
= try_serv_name_lookup(typ
, val
)) != NULL
) {
517 snprintf(buf
, buf_siz
, "%s(%"PRIu16
")", str
, val
);
519 snprintf(buf
, buf_siz
, "%"PRIu16
, val
);
524 col_append_ports(column_info
*cinfo
, const int col
, port_type typ
, uint16_t src
, uint16_t dst
)
526 char buf_src
[32], buf_dst
[32];
528 if (!CHECK_COL(cinfo
, col
))
531 col_snprint_port(buf_src
, 32, typ
, src
);
532 col_snprint_port(buf_dst
, 32, typ
, dst
);
533 col_append_lstr(cinfo
, col
, buf_src
, " " UTF8_RIGHTWARDS_ARROW
" ", buf_dst
, COL_ADD_LSTR_TERMINATOR
);
537 col_append_frame_number(packet_info
*pinfo
, const int col
, const char *fmt_str
, unsigned frame_num
)
539 col_append_fstr(pinfo
->cinfo
, col
, fmt_str
, frame_num
);
540 if (!pinfo
->fd
->visited
) {
541 col_data_changed_
= true;
546 col_do_append_fstr(column_info
*cinfo
, const int el
, const char *separator
, const char *format
, va_list ap
)
548 size_t len
, max_len
, sep_len
, pos
;
550 col_item_t
* col_item
;
551 char tmp
[COL_BUF_MAX_LEN
];
553 sep_len
= (separator
) ? strlen(separator
) : 0;
556 max_len
= COL_MAX_INFO_LEN
;
558 max_len
= COL_MAX_LEN
;
560 for (i
= cinfo
->col_first
[el
]; i
<= cinfo
->col_last
[el
]; i
++) {
561 col_item
= &cinfo
->columns
[i
];
562 if (col_item
->fmt_matx
[el
]) {
564 * First arrange that we can append, if necessary.
566 COL_CHECK_APPEND(col_item
, max_len
);
568 len
= strlen(col_item
->col_buf
);
571 * If we have a separator, append it if the column isn't empty.
573 if (sep_len
!= 0 && len
!= 0) {
574 (void) ws_label_strcat(col_item
->col_buf
, max_len
, separator
, 0);
582 pos
= vsnprintf(tmp
, sizeof(tmp
), format
, ap2
);
584 if (pos
>= max_len
) {
585 ws_utf8_truncate(tmp
, max_len
- 1);
587 WS_UTF_8_CHECK(tmp
, -1);
588 ws_label_strcpy(col_item
->col_buf
, max_len
, len
, tmp
, 0);
594 /* Appends a vararg list to a packet info string. */
596 col_append_fstr(column_info
*cinfo
, const int el
, const char *format
, ...)
600 if (!CHECK_COL(cinfo
, el
))
603 va_start(ap
, format
);
604 col_do_append_fstr(cinfo
, el
, NULL
, format
, ap
);
608 /* Appends a vararg list to a packet info string.
609 * Prefixes it with the given separator if the column is not empty.
612 col_append_sep_fstr(column_info
*cinfo
, const int el
, const char *separator
,
613 const char *format
, ...)
617 if (!CHECK_COL(cinfo
, el
))
620 if (separator
== NULL
)
621 separator
= ", "; /* default */
623 va_start(ap
, format
);
624 col_do_append_fstr(cinfo
, el
, separator
, format
, ap
);
628 /* Prepends a vararg list to a packet info string. */
630 col_prepend_fstr(column_info
*cinfo
, const int el
, const char *format
, ...)
634 char orig_buf
[COL_BUF_MAX_LEN
];
637 col_item_t
* col_item
;
638 char tmp
[COL_BUF_MAX_LEN
];
640 if (!CHECK_COL(cinfo
, el
))
644 max_len
= COL_MAX_INFO_LEN
;
646 max_len
= COL_MAX_LEN
;
648 for (i
= cinfo
->col_first
[el
]; i
<= cinfo
->col_last
[el
]; i
++) {
649 col_item
= &cinfo
->columns
[i
];
650 if (col_item
->fmt_matx
[el
]) {
651 if (col_item
->col_data
!= col_item
->col_buf
) {
652 /* This was set with "col_set_str()"; which is effectively const */
653 orig
= col_item
->col_data
;
655 (void) g_strlcpy(orig_buf
, col_item
->col_buf
, max_len
);
658 va_start(ap
, format
);
659 pos
= vsnprintf(tmp
, sizeof(tmp
), format
, ap
);
661 if (pos
>= max_len
) {
662 ws_utf8_truncate(tmp
, max_len
- 1);
664 WS_UTF_8_CHECK(tmp
, -1);
665 pos
= ws_label_strcpy(col_item
->col_buf
, max_len
, 0, tmp
, 0);
668 * Move the fence, unless it's at the beginning of the string.
670 if (col_item
->col_fence
> 0)
671 col_item
->col_fence
+= (int) strlen(col_item
->col_buf
);
674 * Append the original data.
676 ws_label_strcpy(col_item
->col_buf
, max_len
, pos
, orig
, 0);
677 col_item
->col_data
= col_item
->col_buf
;
682 col_prepend_fence_fstr(column_info
*cinfo
, const int el
, const char *format
, ...)
686 char orig_buf
[COL_BUF_MAX_LEN
];
689 col_item_t
* col_item
;
690 char tmp
[COL_BUF_MAX_LEN
];
692 if (!CHECK_COL(cinfo
, el
))
696 max_len
= COL_MAX_INFO_LEN
;
698 max_len
= COL_MAX_LEN
;
700 for (i
= cinfo
->col_first
[el
]; i
<= cinfo
->col_last
[el
]; i
++) {
701 col_item
= &cinfo
->columns
[i
];
702 if (col_item
->fmt_matx
[el
]) {
703 if (col_item
->col_data
!= col_item
->col_buf
) {
704 /* This was set with "col_set_str()"; which is effectively const */
705 orig
= col_item
->col_data
;
707 (void) g_strlcpy(orig_buf
, col_item
->col_buf
, max_len
);
710 va_start(ap
, format
);
711 pos
= vsnprintf(tmp
, sizeof(tmp
), format
, ap
);
713 if (pos
>= max_len
) {
714 ws_utf8_truncate(tmp
, max_len
- 1);
716 WS_UTF_8_CHECK(tmp
, -1);
717 pos
= ws_label_strcpy(col_item
->col_buf
, max_len
, 0, tmp
, 0);
720 * Move the fence if it exists, else create a new fence at the
721 * end of the prepended data.
723 if (col_item
->col_fence
> 0) {
724 col_item
->col_fence
+= (int) strlen(col_item
->col_buf
);
726 col_item
->col_fence
= (int) strlen(col_item
->col_buf
);
729 * Append the original data.
731 ws_label_strcpy(col_item
->col_buf
, max_len
, pos
, orig
, 0);
732 col_item
->col_data
= col_item
->col_buf
;
737 /* Use this if "str" points to something that won't stay around (and
738 must thus be copied). */
740 col_add_str(column_info
*cinfo
, const int el
, const char* str
)
744 col_item_t
* col_item
;
746 if (!CHECK_COL(cinfo
, el
))
750 max_len
= COL_MAX_INFO_LEN
;
752 max_len
= COL_MAX_LEN
;
754 for (i
= cinfo
->col_first
[el
]; i
<= cinfo
->col_last
[el
]; i
++) {
755 col_item
= &cinfo
->columns
[i
];
756 if (col_item
->fmt_matx
[el
]) {
757 if (col_item
->col_fence
!= 0) {
759 * We will append the string after the fence.
760 * First arrange that we can append, if necessary.
762 COL_CHECK_APPEND(col_item
, max_len
);
765 * There's no fence, so we can just write to the string.
767 col_item
->col_data
= col_item
->col_buf
;
769 WS_UTF_8_CHECK(str
, -1);
770 (void) ws_label_strcpy(col_item
->col_buf
, max_len
, col_item
->col_fence
, str
, 0);
775 /* Use this if "str" points to something that will stay around (and thus
776 needn't be copied). */
778 col_set_str(column_info
*cinfo
, const int el
, const char* str
)
782 col_item_t
* col_item
;
784 DISSECTOR_ASSERT(str
);
786 if (!CHECK_COL(cinfo
, el
))
790 max_len
= COL_MAX_INFO_LEN
;
792 max_len
= COL_MAX_LEN
;
794 for (i
= cinfo
->col_first
[el
]; i
<= cinfo
->col_last
[el
]; i
++) {
795 col_item
= &cinfo
->columns
[i
];
796 if (col_item
->fmt_matx
[el
]) {
797 if (col_item
->col_fence
!= 0) {
799 * We will append the string after the fence.
800 * First arrange that we can append, if necessary.
802 COL_CHECK_APPEND(col_item
, max_len
);
804 (void) g_strlcpy(&col_item
->col_buf
[col_item
->col_fence
], str
, max_len
- col_item
->col_fence
);
807 * There's no fence, so we can just set the column to point
810 col_item
->col_data
= str
;
817 col_add_lstr(column_info
*cinfo
, const int el
, const char *str1
, ...)
824 col_item_t
* col_item
;
826 if (!CHECK_COL(cinfo
, el
))
830 max_len
= COL_MAX_INFO_LEN
;
832 max_len
= COL_MAX_LEN
;
834 for (i
= cinfo
->col_first
[el
]; i
<= cinfo
->col_last
[el
]; i
++) {
835 col_item
= &cinfo
->columns
[i
];
836 if (col_item
->fmt_matx
[el
]) {
837 pos
= col_item
->col_fence
;
840 * We will append the string after the fence.
841 * First arrange that we can append, if necessary.
843 COL_CHECK_APPEND(col_item
, max_len
);
846 * There's no fence, so we can just write to the string.
848 col_item
->col_data
= col_item
->col_buf
;
854 if (G_UNLIKELY(str
== NULL
)) {
857 WS_UTF_8_CHECK(str
, -1);
858 pos
= ws_label_strcpy(col_item
->col_buf
, max_len
, pos
, str
, 0);
860 } while (pos
< max_len
&& (str
= va_arg(ap
, const char *)) != COL_ADD_LSTR_TERMINATOR
);
866 /* Adds a vararg list to a packet info string. */
868 col_add_fstr(column_info
*cinfo
, const int el
, const char *format
, ...)
873 col_item_t
* col_item
;
874 char tmp
[COL_BUF_MAX_LEN
];
876 if (!CHECK_COL(cinfo
, el
))
880 max_len
= COL_MAX_INFO_LEN
;
882 max_len
= COL_MAX_LEN
;
884 for (i
= cinfo
->col_first
[el
]; i
<= cinfo
->col_last
[el
]; i
++) {
885 col_item
= &cinfo
->columns
[i
];
886 if (col_item
->fmt_matx
[el
]) {
887 if (col_item
->col_fence
!= 0) {
889 * We will append the string after the fence.
890 * First arrange that we can append, if necessary.
892 COL_CHECK_APPEND(col_item
, max_len
);
895 * There's no fence, so we can just write to the string.
897 col_item
->col_data
= col_item
->col_buf
;
899 va_start(ap
, format
);
900 pos
= vsnprintf(tmp
, sizeof(tmp
), format
, ap
);
902 if (pos
>= max_len
) {
903 ws_utf8_truncate(tmp
, max_len
- 1);
905 WS_UTF_8_CHECK(tmp
, -1);
906 ws_label_strcpy(col_item
->col_buf
, max_len
, col_item
->col_fence
, tmp
, 0);
912 col_do_append_str(column_info
*cinfo
, const int el
, const char* separator
,
917 col_item_t
* col_item
;
920 max_len
= COL_MAX_INFO_LEN
;
922 max_len
= COL_MAX_LEN
;
924 for (i
= cinfo
->col_first
[el
]; i
<= cinfo
->col_last
[el
]; i
++) {
925 col_item
= &cinfo
->columns
[i
];
926 if (col_item
->fmt_matx
[el
]) {
928 * First arrange that we can append, if necessary.
930 COL_CHECK_APPEND(col_item
, max_len
);
932 len
= col_item
->col_buf
[0];
935 * If we have a separator, append it if the column isn't empty.
937 if (separator
!= NULL
) {
939 (void) ws_label_strcat(col_item
->col_buf
, max_len
, separator
, 0);
942 WS_UTF_8_CHECK(str
, -1);
943 (void) ws_label_strcat(col_item
->col_buf
, max_len
, str
, 0);
949 col_append_str(column_info
*cinfo
, const int el
, const char* str
)
951 if (!CHECK_COL(cinfo
, el
))
954 col_do_append_str(cinfo
, el
, NULL
, str
);
958 col_append_sep_str(column_info
*cinfo
, const int el
, const char* separator
,
961 if (!CHECK_COL(cinfo
, el
))
964 if (separator
== NULL
)
965 separator
= ", "; /* default */
967 col_do_append_str(cinfo
, el
, separator
, str
);
970 /* --------------------------------- */
972 col_has_time_fmt(column_info
*cinfo
, const int col
)
974 col_item_t
* col_item
= &cinfo
->columns
[col
];
975 return ((col_item
->fmt_matx
[COL_CLS_TIME
]) ||
976 (col_item
->fmt_matx
[COL_ABS_TIME
]) ||
977 (col_item
->fmt_matx
[COL_ABS_YMD_TIME
]) ||
978 (col_item
->fmt_matx
[COL_ABS_YDOY_TIME
]) ||
979 (col_item
->fmt_matx
[COL_UTC_TIME
]) ||
980 (col_item
->fmt_matx
[COL_UTC_YMD_TIME
]) ||
981 (col_item
->fmt_matx
[COL_UTC_YDOY_TIME
]) ||
982 (col_item
->fmt_matx
[COL_REL_TIME
]) ||
983 (col_item
->fmt_matx
[COL_DELTA_TIME
]) ||
984 (col_item
->fmt_matx
[COL_DELTA_TIME_DIS
]));
988 get_frame_timestamp_precision(const frame_data
*fd
)
992 tsprecision
= timestamp_get_precision();
993 if (tsprecision
== TS_PREC_AUTO
)
994 tsprecision
= fd
->tsprec
;
995 else if (tsprecision
< 0)
996 ws_assert_not_reached();
999 * Time stamp precision values higher than the maximum
1000 * precision we support can't be handled. Just display
1001 * those times with the maximum precision we support.
1003 if (tsprecision
> WS_TSPREC_MAX
)
1004 tsprecision
= WS_TSPREC_MAX
;
1010 get_default_timestamp_precision(void)
1014 tsprecision
= timestamp_get_precision();
1015 if (tsprecision
== TS_PREC_AUTO
)
1016 tsprecision
= WS_TSPREC_MAX
; /* default to the maximum precision we support */
1017 else if (tsprecision
< 0)
1018 ws_assert_not_reached();
1021 * Time stamp precision values higher than the maximum
1022 * precision we support can't be handled. Just display
1023 * those times with the maximum precision we support.
1025 if (tsprecision
> WS_TSPREC_MAX
)
1026 tsprecision
= WS_TSPREC_MAX
;
1032 set_abs_ymd_time(const frame_data
*fd
, char *buf
, char *decimal_point
, bool local
)
1038 format_nstime_as_iso8601(buf
, COL_MAX_LEN
, &fd
->abs_ts
, decimal_point
, local
, get_frame_timestamp_precision(fd
));
1042 col_set_abs_ymd_time(const frame_data
*fd
, column_info
*cinfo
, const int col
)
1044 set_abs_ymd_time(fd
, cinfo
->columns
[col
].col_buf
, col_decimal_point
, true);
1045 cinfo
->col_expr
.col_expr
[col
] = "frame.time";
1046 (void) g_strlcpy(cinfo
->col_expr
.col_expr_val
[col
],cinfo
->columns
[col
].col_buf
,COL_MAX_LEN
);
1048 cinfo
->columns
[col
].col_data
= cinfo
->columns
[col
].col_buf
;
1052 col_set_utc_ymd_time(const frame_data
*fd
, column_info
*cinfo
, const int col
)
1054 set_abs_ymd_time(fd
, cinfo
->columns
[col
].col_buf
, col_decimal_point
, false);
1055 cinfo
->col_expr
.col_expr
[col
] = "frame.time";
1056 (void) g_strlcpy(cinfo
->col_expr
.col_expr_val
[col
],cinfo
->columns
[col
].col_buf
,COL_MAX_LEN
);
1058 cinfo
->columns
[col
].col_data
= cinfo
->columns
[col
].col_buf
;
1062 set_abs_ydoy_time(const frame_data
*fd
, char *buf
, char *decimal_point
, bool local
)
1076 tmp
= ws_localtime_r(&fd
->abs_ts
.secs
, &tm
);
1078 tmp
= ws_gmtime_r(&fd
->abs_ts
.secs
, &tm
);
1080 snprintf(buf
, COL_MAX_LEN
, "Not representable");
1084 remaining
= COL_MAX_LEN
;
1085 num_bytes
= snprintf(ptr
, remaining
,"%04d/%03d %02d:%02d:%02d",
1086 tmp
->tm_year
+ 1900,
1091 if (num_bytes
< 0) {
1093 * That got an error.
1094 * Not much else we can do.
1096 snprintf(ptr
, remaining
, "snprintf() failed");
1099 if ((unsigned int)num_bytes
>= remaining
) {
1101 * That filled up or would have overflowed the buffer.
1102 * Nothing more we can do.
1107 remaining
-= num_bytes
;
1109 tsprecision
= get_frame_timestamp_precision(fd
);
1110 if (tsprecision
!= 0) {
1112 * Append the fractional part.
1113 * Get the nsecs as a 32-bit unsigned value, as it should never
1114 * be negative, so we treat it as unsigned.
1116 format_fractional_part_nsecs(ptr
, remaining
, (uint32_t)fd
->abs_ts
.nsecs
, decimal_point
, tsprecision
);
1121 col_set_abs_ydoy_time(const frame_data
*fd
, column_info
*cinfo
, const int col
)
1123 set_abs_ydoy_time(fd
, cinfo
->columns
[col
].col_buf
, col_decimal_point
, true);
1124 cinfo
->col_expr
.col_expr
[col
] = "frame.time";
1125 (void) g_strlcpy(cinfo
->col_expr
.col_expr_val
[col
],cinfo
->columns
[col
].col_buf
,COL_MAX_LEN
);
1127 cinfo
->columns
[col
].col_data
= cinfo
->columns
[col
].col_buf
;
1131 col_set_utc_ydoy_time(const frame_data
*fd
, column_info
*cinfo
, const int col
)
1133 set_abs_ydoy_time(fd
, cinfo
->columns
[col
].col_buf
, col_decimal_point
, false);
1134 cinfo
->col_expr
.col_expr
[col
] = "frame.time";
1135 (void) g_strlcpy(cinfo
->col_expr
.col_expr_val
[col
],cinfo
->columns
[col
].col_buf
,COL_MAX_LEN
);
1137 cinfo
->columns
[col
].col_data
= cinfo
->columns
[col
].col_buf
;
1141 set_time_seconds(const frame_data
*fd
, const nstime_t
*ts
, char *buf
)
1143 ws_assert(fd
->has_ts
);
1145 display_signed_time(buf
, COL_MAX_LEN
, ts
, get_frame_timestamp_precision(fd
));
1149 set_time_hour_min_sec(const frame_data
*fd
, const nstime_t
*ts
, char *buf
, char *decimal_point
)
1151 time_t secs
= ts
->secs
;
1153 bool negative
= false;
1159 ws_assert(fd
->has_ts
);
1165 if (ts
->nsecs
>= 0) {
1167 } else if (G_LIKELY(ts
->nsecs
!= INT_MIN
)) {
1169 * This isn't the smallest negative number that fits in 32
1170 * bits, so we can compute its negative and store it in a
1171 * 32-bit unsigned int variable.
1177 * -2147483648 is the smallest number that fits in a signed
1178 * 2's complement 32-bit variable, and its negative doesn't
1181 * Just cast it to a 32-bit unsigned int value to set the
1182 * 32-bit unsigned int variable to 2147483648.
1184 * Note that, on platforms where both integers and long
1185 * integers are 32-bit, such as 32-bit UN*Xes and both
1186 * 32-bit *and* 64-bit Windows, making the variable in
1187 * question a long will not avoid undefined behavior.
1189 nsecs
= (uint32_t)ts
->nsecs
;
1193 remaining
= COL_MAX_LEN
;
1194 if (secs
>= (60*60)) {
1195 num_bytes
= snprintf(ptr
, remaining
, "%s%dh %2dm %2d",
1196 negative
? "- " : "",
1197 (int32_t) secs
/ (60 * 60),
1198 (int32_t) (secs
/ 60) % 60,
1199 (int32_t) secs
% 60);
1200 } else if (secs
>= 60) {
1201 num_bytes
= snprintf(ptr
, remaining
, "%s%dm %2d",
1202 negative
? "- " : "",
1203 (int32_t) secs
/ 60,
1204 (int32_t) secs
% 60);
1206 num_bytes
= snprintf(ptr
, remaining
, "%s%d",
1207 negative
? "- " : "",
1210 if (num_bytes
< 0) {
1212 * That got an error.
1213 * Not much else we can do.
1215 snprintf(ptr
, remaining
, "snprintf() failed");
1218 if ((unsigned int)num_bytes
>= remaining
) {
1220 * That filled up or would have overflowed the buffer.
1221 * Nothing more we can do.
1226 remaining
-= num_bytes
;
1228 tsprecision
= get_frame_timestamp_precision(fd
);
1229 if (tsprecision
!= 0) {
1231 * Append the fractional part.
1233 num_bytes
= format_fractional_part_nsecs(ptr
, remaining
, nsecs
, decimal_point
, tsprecision
);
1234 if ((unsigned int)num_bytes
>= remaining
) {
1236 * That filled up or would have overflowed the buffer.
1237 * Nothing more we can do.
1242 remaining
-= num_bytes
;
1245 /* Append the "s" for seconds. */
1246 snprintf(ptr
, remaining
, "s");
1250 col_set_rel_time(const frame_data
*fd
, column_info
*cinfo
, const int col
)
1252 nstime_t del_rel_ts
;
1255 cinfo
->columns
[col
].col_buf
[0] = '\0';
1259 frame_delta_abs_time(cinfo
->epan
, fd
, fd
->frame_ref_num
, &del_rel_ts
);
1261 switch (timestamp_get_seconds_type()) {
1262 case TS_SECONDS_DEFAULT
:
1263 set_time_seconds(fd
, &del_rel_ts
, cinfo
->columns
[col
].col_buf
);
1264 cinfo
->col_expr
.col_expr
[col
] = "frame.time_relative";
1265 (void) g_strlcpy(cinfo
->col_expr
.col_expr_val
[col
],cinfo
->columns
[col
].col_buf
,COL_MAX_LEN
);
1267 case TS_SECONDS_HOUR_MIN_SEC
:
1268 set_time_hour_min_sec(fd
, &del_rel_ts
, cinfo
->columns
[col
].col_buf
, col_decimal_point
);
1269 cinfo
->col_expr
.col_expr
[col
] = "frame.time_relative";
1270 set_time_seconds(fd
, &del_rel_ts
, cinfo
->col_expr
.col_expr_val
[col
]);
1273 ws_assert_not_reached();
1275 cinfo
->columns
[col
].col_data
= cinfo
->columns
[col
].col_buf
;
1279 col_set_delta_time(const frame_data
*fd
, column_info
*cinfo
, const int col
)
1281 nstime_t del_cap_ts
;
1284 cinfo
->columns
[col
].col_buf
[0] = '\0';
1288 frame_delta_abs_time(cinfo
->epan
, fd
, fd
->num
- 1, &del_cap_ts
);
1290 switch (timestamp_get_seconds_type()) {
1291 case TS_SECONDS_DEFAULT
:
1292 set_time_seconds(fd
, &del_cap_ts
, cinfo
->columns
[col
].col_buf
);
1293 cinfo
->col_expr
.col_expr
[col
] = "frame.time_delta";
1294 (void) g_strlcpy(cinfo
->col_expr
.col_expr_val
[col
],cinfo
->columns
[col
].col_buf
,COL_MAX_LEN
);
1296 case TS_SECONDS_HOUR_MIN_SEC
:
1297 set_time_hour_min_sec(fd
, &del_cap_ts
, cinfo
->columns
[col
].col_buf
, col_decimal_point
);
1298 cinfo
->col_expr
.col_expr
[col
] = "frame.time_delta";
1299 set_time_seconds(fd
, &del_cap_ts
, cinfo
->col_expr
.col_expr_val
[col
]);
1302 ws_assert_not_reached();
1305 cinfo
->columns
[col
].col_data
= cinfo
->columns
[col
].col_buf
;
1309 col_set_delta_time_dis(const frame_data
*fd
, column_info
*cinfo
, const int col
)
1311 nstime_t del_dis_ts
;
1314 cinfo
->columns
[col
].col_buf
[0] = '\0';
1318 frame_delta_abs_time(cinfo
->epan
, fd
, fd
->prev_dis_num
, &del_dis_ts
);
1320 switch (timestamp_get_seconds_type()) {
1321 case TS_SECONDS_DEFAULT
:
1322 set_time_seconds(fd
, &del_dis_ts
, cinfo
->columns
[col
].col_buf
);
1323 cinfo
->col_expr
.col_expr
[col
] = "frame.time_delta_displayed";
1324 (void) g_strlcpy(cinfo
->col_expr
.col_expr_val
[col
],cinfo
->columns
[col
].col_buf
,COL_MAX_LEN
);
1326 case TS_SECONDS_HOUR_MIN_SEC
:
1327 set_time_hour_min_sec(fd
, &del_dis_ts
, cinfo
->columns
[col
].col_buf
, col_decimal_point
);
1328 cinfo
->col_expr
.col_expr
[col
] = "frame.time_delta_displayed";
1329 set_time_seconds(fd
, &del_dis_ts
, cinfo
->col_expr
.col_expr_val
[col
]);
1332 ws_assert_not_reached();
1335 cinfo
->columns
[col
].col_data
= cinfo
->columns
[col
].col_buf
;
1339 * Time, without date.
1342 set_abs_time(const frame_data
*fd
, char *buf
, char *decimal_point
, bool local
)
1356 remaining
= COL_MAX_LEN
;
1359 tmp
= ws_localtime_r(&fd
->abs_ts
.secs
, &tm
);
1361 tmp
= ws_gmtime_r(&fd
->abs_ts
.secs
, &tm
);
1363 snprintf(ptr
, remaining
, "Not representable");
1367 /* Integral part. */
1368 num_bytes
= snprintf(ptr
, remaining
, "%02d:%02d:%02d",
1372 if (num_bytes
< 0) {
1374 * That got an error.
1375 * Not much else we can do.
1377 snprintf(ptr
, remaining
, "snprintf() failed");
1380 if ((unsigned int)num_bytes
>= remaining
) {
1382 * That filled up or would have overflowed the buffer.
1383 * Nothing more we can do.
1388 remaining
-= num_bytes
;
1390 tsprecision
= get_frame_timestamp_precision(fd
);
1391 if (tsprecision
!= 0) {
1393 * Append the fractional part.
1394 * Get the nsecs as a 32-bit unsigned value, as it should never
1395 * be negative, so we treat it as unsigned.
1397 format_fractional_part_nsecs(ptr
, remaining
, (uint32_t)fd
->abs_ts
.nsecs
, decimal_point
, tsprecision
);
1402 col_set_abs_time(const frame_data
*fd
, column_info
*cinfo
, const int col
)
1404 set_abs_time(fd
, cinfo
->columns
[col
].col_buf
, col_decimal_point
, true);
1405 cinfo
->col_expr
.col_expr
[col
] = "frame.time";
1406 (void) g_strlcpy(cinfo
->col_expr
.col_expr_val
[col
],cinfo
->columns
[col
].col_buf
,COL_MAX_LEN
);
1408 cinfo
->columns
[col
].col_data
= cinfo
->columns
[col
].col_buf
;
1412 col_set_utc_time(const frame_data
*fd
, column_info
*cinfo
, const int col
)
1414 set_abs_time(fd
, cinfo
->columns
[col
].col_buf
, col_decimal_point
, false);
1415 cinfo
->col_expr
.col_expr
[col
] = "frame.time";
1416 (void) g_strlcpy(cinfo
->col_expr
.col_expr_val
[col
],cinfo
->columns
[col
].col_buf
,COL_MAX_LEN
);
1418 cinfo
->columns
[col
].col_data
= cinfo
->columns
[col
].col_buf
;
1422 set_epoch_time(const frame_data
*fd
, char *buf
)
1428 display_epoch_time(buf
, COL_MAX_LEN
, &fd
->abs_ts
, get_frame_timestamp_precision(fd
));
1433 col_set_epoch_time(const frame_data
*fd
, column_info
*cinfo
, const int col
)
1435 if (set_epoch_time(fd
, cinfo
->columns
[col
].col_buf
)) {
1436 cinfo
->col_expr
.col_expr
[col
] = "frame.time_delta";
1437 (void) g_strlcpy(cinfo
->col_expr
.col_expr_val
[col
],cinfo
->columns
[col
].col_buf
,COL_MAX_LEN
);
1439 cinfo
->columns
[col
].col_data
= cinfo
->columns
[col
].col_buf
;
1443 set_fd_time(const epan_t
*epan
, frame_data
*fd
, char *buf
)
1446 switch (timestamp_get_type()) {
1448 set_abs_time(fd
, buf
, col_decimal_point
, true);
1451 case TS_ABSOLUTE_WITH_YMD
:
1452 set_abs_ymd_time(fd
, buf
, col_decimal_point
, true);
1455 case TS_ABSOLUTE_WITH_YDOY
:
1456 set_abs_ydoy_time(fd
, buf
, col_decimal_point
, true);
1461 nstime_t del_rel_ts
;
1463 frame_delta_abs_time(epan
, fd
, fd
->frame_ref_num
, &del_rel_ts
);
1465 switch (timestamp_get_seconds_type()) {
1466 case TS_SECONDS_DEFAULT
:
1467 set_time_seconds(fd
, &del_rel_ts
, buf
);
1469 case TS_SECONDS_HOUR_MIN_SEC
:
1470 set_time_seconds(fd
, &del_rel_ts
, buf
);
1473 ws_assert_not_reached();
1482 nstime_t del_cap_ts
;
1484 frame_delta_abs_time(epan
, fd
, fd
->num
- 1, &del_cap_ts
);
1486 switch (timestamp_get_seconds_type()) {
1487 case TS_SECONDS_DEFAULT
:
1488 set_time_seconds(fd
, &del_cap_ts
, buf
);
1490 case TS_SECONDS_HOUR_MIN_SEC
:
1491 set_time_hour_min_sec(fd
, &del_cap_ts
, buf
, col_decimal_point
);
1494 ws_assert_not_reached();
1503 nstime_t del_dis_ts
;
1505 frame_delta_abs_time(epan
, fd
, fd
->prev_dis_num
, &del_dis_ts
);
1507 switch (timestamp_get_seconds_type()) {
1508 case TS_SECONDS_DEFAULT
:
1509 set_time_seconds(fd
, &del_dis_ts
, buf
);
1511 case TS_SECONDS_HOUR_MIN_SEC
:
1512 set_time_hour_min_sec(fd
, &del_dis_ts
, buf
, col_decimal_point
);
1515 ws_assert_not_reached();
1523 set_epoch_time(fd
, buf
);
1527 set_abs_time(fd
, buf
, col_decimal_point
, false);
1530 case TS_UTC_WITH_YMD
:
1531 set_abs_ymd_time(fd
, buf
, col_decimal_point
, false);
1534 case TS_UTC_WITH_YDOY
:
1535 set_abs_ydoy_time(fd
, buf
, col_decimal_point
, false);
1539 /* code is missing for this case, but I don't know which [jmayer20051219] */
1540 ws_assert_not_reached();
1546 col_set_cls_time(const frame_data
*fd
, column_info
*cinfo
, const int col
)
1548 switch (timestamp_get_type()) {
1550 col_set_abs_time(fd
, cinfo
, col
);
1553 case TS_ABSOLUTE_WITH_YMD
:
1554 col_set_abs_ymd_time(fd
, cinfo
, col
);
1557 case TS_ABSOLUTE_WITH_YDOY
:
1558 col_set_abs_ydoy_time(fd
, cinfo
, col
);
1562 col_set_rel_time(fd
, cinfo
, col
);
1566 col_set_delta_time(fd
, cinfo
, col
);
1570 col_set_delta_time_dis(fd
, cinfo
, col
);
1574 col_set_epoch_time(fd
, cinfo
, col
);
1578 col_set_utc_time(fd
, cinfo
, col
);
1581 case TS_UTC_WITH_YMD
:
1582 col_set_utc_ymd_time(fd
, cinfo
, col
);
1585 case TS_UTC_WITH_YDOY
:
1586 col_set_utc_ydoy_time(fd
, cinfo
, col
);
1590 /* code is missing for this case, but I don't know which [jmayer20051219] */
1591 ws_assert_not_reached();
1596 /* Set the format of the variable time format. */
1598 col_set_fmt_time(const frame_data
*fd
, column_info
*cinfo
, const int fmt
, const int col
)
1600 COL_CHECK_REF_TIME(fd
, cinfo
->columns
[col
].col_buf
);
1604 col_set_cls_time(fd
, cinfo
, col
);
1608 col_set_abs_time(fd
, cinfo
, col
);
1611 case COL_ABS_YMD_TIME
:
1612 col_set_abs_ymd_time(fd
, cinfo
, col
);
1615 case COL_ABS_YDOY_TIME
:
1616 col_set_abs_ydoy_time(fd
, cinfo
, col
);
1620 col_set_rel_time(fd
, cinfo
, col
);
1623 case COL_DELTA_TIME
:
1624 col_set_delta_time(fd
, cinfo
, col
);
1627 case COL_DELTA_TIME_DIS
:
1628 col_set_delta_time_dis(fd
, cinfo
, col
);
1632 col_set_utc_time(fd
, cinfo
, col
);
1635 case COL_UTC_YMD_TIME
:
1636 col_set_utc_ymd_time(fd
, cinfo
, col
);
1639 case COL_UTC_YDOY_TIME
:
1640 col_set_utc_ydoy_time(fd
, cinfo
, col
);
1644 ws_assert_not_reached();
1649 /* --------------------------- */
1650 /* Set the given (relative) time to a column element.
1652 * Used by dissectors to set the time in a column
1654 * @param cinfo the current packet row
1655 * @param el the column to use, e.g. COL_INFO
1656 * @param ts the time to set in the column
1657 * @param fieldname the fieldname to use for creating a filter (when
1658 * applying/preparing/copying as filter)
1661 col_set_time(column_info
*cinfo
, const int el
, const nstime_t
*ts
, const char *fieldname
)
1664 col_item_t
* col_item
;
1666 if (!CHECK_COL(cinfo
, el
))
1669 /** @todo TODO: We don't respect fd->ref_time (no way to access 'fd')
1670 COL_CHECK_REF_TIME(fd, buf);
1673 for (col
= cinfo
->col_first
[el
]; col
<= cinfo
->col_last
[el
]; col
++) {
1674 col_item
= &cinfo
->columns
[col
];
1675 if (col_item
->fmt_matx
[el
]) {
1676 display_signed_time(col_item
->col_buf
, COL_MAX_LEN
, ts
, get_default_timestamp_precision());
1677 col_item
->col_data
= col_item
->col_buf
;
1678 cinfo
->col_expr
.col_expr
[col
] = fieldname
;
1679 (void) g_strlcpy(cinfo
->col_expr
.col_expr_val
[col
],col_item
->col_buf
,COL_MAX_LEN
);
1685 col_set_addr(packet_info
*pinfo
, const int col
, const address
*addr
, const bool is_src
,
1686 const bool fill_col_exprs
, const bool res
)
1689 col_item_t
* col_item
= &pinfo
->cinfo
->columns
[col
];
1691 if (addr
->type
== AT_NONE
) {
1692 /* No address, nothing to do */
1696 if (res
&& (name
= address_to_name(addr
)) != NULL
)
1697 col_item
->col_data
= name
;
1699 col_item
->col_data
= col_item
->col_buf
;
1700 address_to_str_buf(addr
, col_item
->col_buf
, COL_MAX_LEN
);
1703 if (!fill_col_exprs
)
1706 pinfo
->cinfo
->col_expr
.col_expr
[col
] = address_type_column_filter_string(addr
, is_src
);
1707 /* For address types that have a filter, create a string */
1708 if (strlen(pinfo
->cinfo
->col_expr
.col_expr
[col
]) > 0) {
1709 address_to_str_buf(addr
, pinfo
->cinfo
->col_expr
.col_expr_val
[col
], COL_MAX_LEN
);
1711 /* For address types that don't, use the internal column FT_STRING hfi */
1712 pinfo
->cinfo
->col_expr
.col_expr
[col
] = proto_registrar_get_nth(col_item
->hf_id
)->abbrev
;
1713 (void) g_strlcpy(pinfo
->cinfo
->col_expr
.col_expr_val
[col
], pinfo
->cinfo
->columns
[col
].col_data
, COL_MAX_LEN
);
1717 /* ------------------------ */
1719 col_set_port(packet_info
*pinfo
, const int col
, const bool is_res
, const bool is_src
, const bool fill_col_exprs _U_
)
1722 col_item_t
* col_item
= &pinfo
->cinfo
->columns
[col
];
1725 port
= pinfo
->srcport
;
1727 port
= pinfo
->destport
;
1729 /* TODO: Use fill_col_exprs */
1731 switch (pinfo
->ptype
) {
1734 (void) g_strlcpy(col_item
->col_buf
, sctp_port_to_display(pinfo
->pool
, port
), COL_MAX_LEN
);
1736 uint32_to_str_buf(port
, col_item
->col_buf
, COL_MAX_LEN
);
1740 uint32_to_str_buf(port
, pinfo
->cinfo
->col_expr
.col_expr_val
[col
], COL_MAX_LEN
);
1742 (void) g_strlcpy(col_item
->col_buf
, tcp_port_to_display(pinfo
->pool
, port
), COL_MAX_LEN
);
1744 (void) g_strlcpy(col_item
->col_buf
, pinfo
->cinfo
->col_expr
.col_expr_val
[col
], COL_MAX_LEN
);
1746 pinfo
->cinfo
->col_expr
.col_expr
[col
] = "tcp.srcport";
1748 pinfo
->cinfo
->col_expr
.col_expr
[col
] = "tcp.dstport";
1752 uint32_to_str_buf(port
, pinfo
->cinfo
->col_expr
.col_expr_val
[col
], COL_MAX_LEN
);
1754 (void) g_strlcpy(col_item
->col_buf
, udp_port_to_display(pinfo
->pool
, port
), COL_MAX_LEN
);
1756 (void) g_strlcpy(col_item
->col_buf
, pinfo
->cinfo
->col_expr
.col_expr_val
[col
], COL_MAX_LEN
);
1758 pinfo
->cinfo
->col_expr
.col_expr
[col
] = "udp.srcport";
1760 pinfo
->cinfo
->col_expr
.col_expr
[col
] = "udp.dstport";
1765 pinfo
->cinfo
->col_expr
.col_expr
[col
] = "ddp.src_socket";
1767 pinfo
->cinfo
->col_expr
.col_expr
[col
] = "ddp.dst_socket";
1768 uint32_to_str_buf(port
, pinfo
->cinfo
->col_expr
.col_expr_val
[col
], COL_MAX_LEN
);
1769 (void) g_strlcpy(col_item
->col_buf
, pinfo
->cinfo
->col_expr
.col_expr_val
[col
], COL_MAX_LEN
);
1773 /* XXX - resolve IPX socket numbers */
1774 snprintf(col_item
->col_buf
, COL_MAX_LEN
, "0x%04x", port
);
1775 (void) g_strlcpy(pinfo
->cinfo
->col_expr
.col_expr_val
[col
], col_item
->col_buf
,COL_MAX_LEN
);
1777 pinfo
->cinfo
->col_expr
.col_expr
[col
] = "ipx.src.socket";
1779 pinfo
->cinfo
->col_expr
.col_expr
[col
] = "ipx.dst.socket";
1783 /* XXX - resolve IDP socket numbers */
1784 snprintf(col_item
->col_buf
, COL_MAX_LEN
, "0x%04x", port
);
1785 (void) g_strlcpy(pinfo
->cinfo
->col_expr
.col_expr_val
[col
], col_item
->col_buf
,COL_MAX_LEN
);
1787 pinfo
->cinfo
->col_expr
.col_expr
[col
] = "idp.src.socket";
1789 pinfo
->cinfo
->col_expr
.col_expr
[col
] = "idp.dst.socket";
1793 /* XXX - resolve USB endpoint numbers */
1794 snprintf(col_item
->col_buf
, COL_MAX_LEN
, "0x%08x", port
);
1795 (void) g_strlcpy(pinfo
->cinfo
->col_expr
.col_expr_val
[col
], col_item
->col_buf
,COL_MAX_LEN
);
1797 pinfo
->cinfo
->col_expr
.col_expr
[col
] = "usb.src.endpoint";
1799 pinfo
->cinfo
->col_expr
.col_expr
[col
] = "usb.dst.endpoint";
1805 col_item
->col_data
= col_item
->col_buf
;
1809 col_based_on_frame_data(column_info
*cinfo
, const int col
)
1812 ws_assert(col
< cinfo
->num_cols
);
1814 switch (cinfo
->columns
[col
].col_fmt
) {
1816 case COL_NUMBER_DIS
:
1819 case COL_ABS_YMD_TIME
:
1820 case COL_ABS_YDOY_TIME
:
1822 case COL_UTC_YMD_TIME
:
1823 case COL_UTC_YDOY_TIME
:
1825 case COL_DELTA_TIME
:
1826 case COL_DELTA_TIME_DIS
:
1827 case COL_PACKET_LENGTH
:
1828 case COL_CUMULATIVE_BYTES
:
1837 col_fill_in_frame_data(const frame_data
*fd
, column_info
*cinfo
, const int col
, const bool fill_col_exprs
)
1839 col_item_t
* col_item
= &cinfo
->columns
[col
];
1841 switch (col_item
->col_fmt
) {
1843 uint32_to_str_buf(fd
->num
, col_item
->col_buf
, COL_MAX_LEN
);
1844 col_item
->col_data
= col_item
->col_buf
;
1847 case COL_NUMBER_DIS
:
1848 uint32_to_str_buf(fd
->dis_num
, col_item
->col_buf
, COL_MAX_LEN
);
1849 col_item
->col_data
= col_item
->col_buf
;
1854 case COL_ABS_YMD_TIME
:
1855 case COL_ABS_YDOY_TIME
:
1857 case COL_UTC_YMD_TIME
:
1858 case COL_UTC_YDOY_TIME
:
1860 case COL_DELTA_TIME
:
1861 case COL_DELTA_TIME_DIS
:
1862 /* TODO: Pass on fill_col_exprs */
1863 col_set_fmt_time(fd
, cinfo
, col_item
->col_fmt
, col
);
1866 case COL_PACKET_LENGTH
:
1867 uint32_to_str_buf(fd
->pkt_len
, col_item
->col_buf
, COL_MAX_LEN
);
1868 col_item
->col_data
= col_item
->col_buf
;
1871 case COL_CUMULATIVE_BYTES
:
1872 uint32_to_str_buf(fd
->cum_bytes
, col_item
->col_buf
, COL_MAX_LEN
);
1873 col_item
->col_data
= col_item
->col_buf
;
1880 if (!fill_col_exprs
)
1883 switch (col_item
->col_fmt
) {
1885 cinfo
->col_expr
.col_expr
[col
] = "frame.number";
1886 (void) g_strlcpy(cinfo
->col_expr
.col_expr_val
[col
], col_item
->col_buf
, COL_MAX_LEN
);
1891 case COL_ABS_YMD_TIME
:
1892 case COL_ABS_YDOY_TIME
:
1894 case COL_UTC_YMD_TIME
:
1895 case COL_UTC_YDOY_TIME
:
1897 case COL_DELTA_TIME
:
1898 case COL_DELTA_TIME_DIS
:
1899 /* Already handled above */
1902 case COL_PACKET_LENGTH
:
1903 cinfo
->col_expr
.col_expr
[col
] = "frame.len";
1904 (void) g_strlcpy(cinfo
->col_expr
.col_expr_val
[col
], col_item
->col_buf
, COL_MAX_LEN
);
1907 case COL_CUMULATIVE_BYTES
:
1908 case COL_NUMBER_DIS
:
1917 col_fill_in(packet_info
*pinfo
, const bool fill_col_exprs
, const bool fill_fd_colums
)
1920 col_item_t
* col_item
;
1925 for (i
= 0; i
< pinfo
->cinfo
->num_cols
; i
++) {
1926 col_item
= &pinfo
->cinfo
->columns
[i
];
1927 if (col_based_on_frame_data(pinfo
->cinfo
, i
)) {
1929 col_fill_in_frame_data(pinfo
->fd
, pinfo
->cinfo
, i
, fill_col_exprs
);
1931 switch (col_item
->col_fmt
) {
1933 case COL_RES_SRC
: /* COL_DEF_SRC is currently just like COL_RES_SRC */
1934 col_set_addr(pinfo
, i
, &pinfo
->src
, true, fill_col_exprs
, true);
1938 col_set_addr(pinfo
, i
, &pinfo
->src
, true, fill_col_exprs
, false);
1941 case COL_DEF_DL_SRC
:
1942 case COL_RES_DL_SRC
:
1943 col_set_addr(pinfo
, i
, &pinfo
->dl_src
, true, fill_col_exprs
, true);
1946 case COL_UNRES_DL_SRC
:
1947 col_set_addr(pinfo
, i
, &pinfo
->dl_src
, true, fill_col_exprs
, false);
1950 case COL_DEF_NET_SRC
:
1951 case COL_RES_NET_SRC
:
1952 col_set_addr(pinfo
, i
, &pinfo
->net_src
, true, fill_col_exprs
, true);
1955 case COL_UNRES_NET_SRC
:
1956 col_set_addr(pinfo
, i
, &pinfo
->net_src
, true, fill_col_exprs
, false);
1960 case COL_RES_DST
: /* COL_DEF_DST is currently just like COL_RES_DST */
1961 col_set_addr(pinfo
, i
, &pinfo
->dst
, false, fill_col_exprs
, true);
1965 col_set_addr(pinfo
, i
, &pinfo
->dst
, false, fill_col_exprs
, false);
1968 case COL_DEF_DL_DST
:
1969 case COL_RES_DL_DST
:
1970 col_set_addr(pinfo
, i
, &pinfo
->dl_dst
, false, fill_col_exprs
, true);
1973 case COL_UNRES_DL_DST
:
1974 col_set_addr(pinfo
, i
, &pinfo
->dl_dst
, false, fill_col_exprs
, false);
1977 case COL_DEF_NET_DST
:
1978 case COL_RES_NET_DST
:
1979 col_set_addr(pinfo
, i
, &pinfo
->net_dst
, false, fill_col_exprs
, true);
1982 case COL_UNRES_NET_DST
:
1983 col_set_addr(pinfo
, i
, &pinfo
->net_dst
, false, fill_col_exprs
, false);
1986 case COL_DEF_SRC_PORT
:
1987 case COL_RES_SRC_PORT
: /* COL_DEF_SRC_PORT is currently just like COL_RES_SRC_PORT */
1988 col_set_port(pinfo
, i
, true, true, fill_col_exprs
);
1991 case COL_UNRES_SRC_PORT
:
1992 col_set_port(pinfo
, i
, false, true, fill_col_exprs
);
1995 case COL_DEF_DST_PORT
:
1996 case COL_RES_DST_PORT
: /* COL_DEF_DST_PORT is currently just like COL_RES_DST_PORT */
1997 col_set_port(pinfo
, i
, true, false, fill_col_exprs
);
2000 case COL_UNRES_DST_PORT
:
2001 col_set_port(pinfo
, i
, false, false, fill_col_exprs
);
2005 /* Formatting handled by col_custom_set_edt() / col_custom_get_filter() */
2008 case NUM_COL_FMTS
: /* keep compiler happy - shouldn't get here */
2009 ws_assert_not_reached();
2012 if (col_item
->col_fmt
>= NUM_COL_FMTS
) {
2013 ws_assert_not_reached();
2016 * Formatting handled by expert.c (COL_EXPERT), or individual
2017 * dissectors. Fill in from the text using the internal hfid.
2019 if (fill_col_exprs
) {
2020 pinfo
->cinfo
->col_expr
.col_expr
[i
] = proto_registrar_get_nth(col_item
->hf_id
)->abbrev
;
2021 (void) g_strlcpy(pinfo
->cinfo
->col_expr
.col_expr_val
[i
], pinfo
->cinfo
->columns
[i
].col_data
, (col_item
->col_fmt
== COL_INFO
) ? COL_MAX_INFO_LEN
: COL_MAX_LEN
);
2030 * Fill in columns if we got an error reading the packet.
2031 * We set most columns to "???", fill in columns that don't need data read
2032 * from the file, and set the Info column to an error message.
2035 col_fill_in_error(column_info
*cinfo
, frame_data
*fdata
, const bool fill_col_exprs
, const bool fill_fd_colums
)
2038 col_item_t
* col_item
;
2043 for (i
= 0; i
< cinfo
->num_cols
; i
++) {
2044 col_item
= &cinfo
->columns
[i
];
2045 if (col_based_on_frame_data(cinfo
, i
)) {
2047 col_fill_in_frame_data(fdata
, cinfo
, i
, fill_col_exprs
);
2048 } else if (col_item
->col_fmt
== COL_INFO
) {
2049 /* XXX - say more than this */
2050 col_item
->col_data
= "Read error";
2052 if (col_item
->col_fmt
>= NUM_COL_FMTS
) {
2053 ws_assert_not_reached();
2056 * No dissection was done, and these columns are set as the
2057 * result of the dissection, so....
2059 col_item
->col_data
= "???";
2065 bool col_data_changed(void) {
2066 bool cur_cdc
= col_data_changed_
;
2067 col_data_changed_
= false;
2072 col_register_protocol(void)
2074 /* This gets called by proto_init() before column_register_fields()
2075 * gets called by the preference modules actually getting registered.
2077 if (proto_cols
<= 0) {
2078 proto_cols
= proto_get_id_by_filter_name("_ws.col");
2080 if (proto_cols
<= 0) {
2081 proto_cols
= proto_register_protocol("Wireshark Columns", "Columns", "_ws.col");
2083 static int *ett
[] = {
2086 proto_register_subtree_array(ett
, G_N_ELEMENTS(ett
));
2090 col_dissect(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
2093 proto_tree
*col_tree
;
2095 column_info
*cinfo
= pinfo
->cinfo
;
2101 if (proto_field_is_referenced(tree
, proto_cols
)) {
2102 // XXX: Needed if we also create _ws.col.custom
2103 //col_custom_set(tree, cinfo);
2104 col_fill_in(pinfo
, false, true);
2105 ti
= proto_tree_add_item(tree
, proto_cols
, tvb
, 0, 0, ENC_NA
);
2106 proto_item_set_hidden(ti
);
2107 col_tree
= proto_item_add_subtree(ti
, ett_cols
);
2108 for (int i
= 0; i
< cinfo
->num_cols
; ++i
) {
2109 if (cinfo
->columns
[i
].hf_id
!= -1) {
2110 if (cinfo
->columns
[i
].col_fmt
== COL_CUSTOM
) {
2111 ti
= proto_tree_add_string_format(col_tree
, cinfo
->columns
[i
].hf_id
, tvb
, 0, 0, get_column_text(cinfo
, i
), "%s: %s", get_column_title(i
), get_column_text(cinfo
, i
));
2113 ti
= proto_tree_add_string(col_tree
, cinfo
->columns
[i
].hf_id
, tvb
, 0, 0, get_column_text(cinfo
, i
));
2115 proto_item_set_hidden(ti
);
2127 * indent-tabs-mode: nil
2130 * ex: set shiftwidth=2 tabstop=8 expandtab:
2131 * :indentSize=2:tabSize=8:noTabs=true: