2 * Routines for handling column preferences
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
21 #include <epan/timestamp.h>
22 #include <epan/prefs.h>
23 #include <epan/dfilter/dfilter.h>
24 #include <epan/column.h>
25 #include <epan/column-info.h>
26 #include <epan/packet.h>
27 #include <wsutil/ws_assert.h>
29 static int proto_cols
;
30 static hf_register_info
*hf_cols
;
31 static unsigned int hf_cols_cleanup
;
33 /* Given a format number (as defined in column-utils.h), returns its equivalent
36 col_format_to_string(const int fmt
) {
37 static const char *const slist
[NUM_COL_FMTS
] = {
38 "%Yt", /* 0) COL_ABS_YMD_TIME */
39 "%YDOYt", /* 1) COL_ABS_YDOY_TIME */
40 "%At", /* 2) COL_ABS_TIME */
41 "%B", /* 3) COL_CUMULATIVE_BYTES */
42 "%Cus", /* 4) COL_CUSTOM */
43 "%Tt", /* 5) COL_DELTA_TIME */
44 "%Gt", /* 6) COL_DELTA_TIME_DIS */
45 "%rd", /* 7) COL_RES_DST */
46 "%ud", /* 8) COL_UNRES_DST */
47 "%rD", /* 9) COL_RES_DST_PORT */
48 "%uD", /* 10) COL_UNRES_DST_PORT */
49 "%d", /* 11) COL_DEF_DST */
50 "%D", /* 12) COL_DEF_DST_PORT */
51 "%a", /* 13) COL_EXPERT */
52 "%I", /* 14) COL_IF_DIR */
53 "%F", /* 15) COL_FREQ_CHAN */
54 "%hd", /* 16) COL_DEF_DL_DST */
55 "%hs", /* 17) COL_DEF_DL_SRC */
56 "%rhd", /* 18) COL_RES_DL_DST */
57 "%uhd", /* 19) COL_UNRES_DL_DST */
58 "%rhs", /* 20) COL_RES_DL_SRC*/
59 "%uhs", /* 21) COL_UNRES_DL_SRC */
60 "%e", /* 22) COL_RSSI */
61 "%x", /* 23) COL_TX_RATE */
62 "%f", /* 24) COL_DSCP_VALUE */
63 "%i", /* 25) COL_INFO */
64 "%rnd", /* 26) COL_RES_NET_DST */
65 "%und", /* 27) COL_UNRES_NET_DST */
66 "%rns", /* 28) COL_RES_NET_SRC */
67 "%uns", /* 29) COL_UNRES_NET_SRC */
68 "%nd", /* 30) COL_DEF_NET_DST */
69 "%ns", /* 31) COL_DEF_NET_SRC */
70 "%m", /* 32) COL_NUMBER */
71 "%md", /* 33) COL_NUMBER_DIS */
72 "%L", /* 34) COL_PACKET_LENGTH */
73 "%p", /* 35) COL_PROTOCOL */
74 "%Rt", /* 36) COL_REL_TIME */
75 "%s", /* 37) COL_DEF_SRC */
76 "%S", /* 38) COL_DEF_SRC_PORT */
77 "%rs", /* 39) COL_RES_SRC */
78 "%us", /* 40) COL_UNRES_SRC */
79 "%rS", /* 41) COL_RES_SRC_PORT */
80 "%uS", /* 42) COL_UNRES_SRC_PORT */
81 "%Yut", /* 43) COL_UTC_YMD_TIME */
82 "%YDOYut", /* 44) COL_UTC_YDOY_TIME */
83 "%Aut", /* 45) COL_UTC_TIME */
84 "%t", /* 46) COL_CLS_TIME */
87 /* Note the formats in migrated_columns[] below have been used in deprecated
88 * columns, and avoid reusing them.
90 if (fmt
< 0 || fmt
>= NUM_COL_FMTS
)
96 /* Given a format number (as defined in column-utils.h), returns its
99 col_format_desc(const int fmt_num
) {
101 /* This should be sorted alphabetically, e.g. `sort -t, -k2` */
103 * This is currently used in the preferences UI, so out-of-numeric-order
104 * performance shouldn't be an issue.
106 static const value_string dlist_vals
[] = {
108 { COL_ABS_YMD_TIME
, "Absolute date, as YYYY-MM-DD, and time" },
109 { COL_ABS_YDOY_TIME
, "Absolute date, as YYYY/DOY, and time" },
110 { COL_ABS_TIME
, "Absolute time" },
111 { COL_CUMULATIVE_BYTES
, "Cumulative Bytes" },
112 { COL_CUSTOM
, "Custom" },
113 { COL_DELTA_TIME_DIS
, "Delta time displayed" },
114 { COL_DELTA_TIME
, "Delta time" },
115 { COL_RES_DST
, "Dest addr (resolved)" },
116 { COL_UNRES_DST
, "Dest addr (unresolved)" },
117 { COL_RES_DST_PORT
, "Dest port (resolved)" },
118 { COL_UNRES_DST_PORT
, "Dest port (unresolved)" },
119 { COL_DEF_DST
, "Destination address" },
120 { COL_DEF_DST_PORT
, "Destination port" },
121 { COL_EXPERT
, "Expert Info Severity" },
122 { COL_IF_DIR
, "FW-1 monitor if/direction" },
123 { COL_FREQ_CHAN
, "Frequency/Channel" },
124 { COL_DEF_DL_DST
, "Hardware dest addr" },
125 { COL_DEF_DL_SRC
, "Hardware src addr" },
126 { COL_RES_DL_DST
, "Hw dest addr (resolved)" },
127 { COL_UNRES_DL_DST
, "Hw dest addr (unresolved)" },
128 { COL_RES_DL_SRC
, "Hw src addr (resolved)" },
129 { COL_UNRES_DL_SRC
, "Hw src addr (unresolved)" },
130 { COL_RSSI
, "IEEE 802.11 RSSI" },
131 { COL_TX_RATE
, "IEEE 802.11 TX rate" },
132 { COL_DSCP_VALUE
, "IP DSCP Value" },
133 { COL_INFO
, "Information" },
134 { COL_RES_NET_DST
, "Net dest addr (resolved)" },
135 { COL_UNRES_NET_DST
, "Net dest addr (unresolved)" },
136 { COL_RES_NET_SRC
, "Net src addr (resolved)" },
137 { COL_UNRES_NET_SRC
, "Net src addr (unresolved)" },
138 { COL_DEF_NET_DST
, "Network dest addr" },
139 { COL_DEF_NET_SRC
, "Network src addr" },
140 { COL_NUMBER
, "Number" },
141 { COL_NUMBER_DIS
, "Number displayed" },
142 { COL_PACKET_LENGTH
, "Packet length (bytes)" },
143 { COL_PROTOCOL
, "Protocol" },
144 { COL_REL_TIME
, "Relative time" },
145 { COL_DEF_SRC
, "Source address" },
146 { COL_DEF_SRC_PORT
, "Source port" },
147 { COL_RES_SRC
, "Src addr (resolved)" },
148 { COL_UNRES_SRC
, "Src addr (unresolved)" },
149 { COL_RES_SRC_PORT
, "Src port (resolved)" },
150 { COL_UNRES_SRC_PORT
, "Src port (unresolved)" },
151 { COL_CLS_TIME
, "Time (format as specified)" },
152 { COL_UTC_YMD_TIME
, "UTC date, as YYYY-MM-DD, and time" },
153 { COL_UTC_YDOY_TIME
, "UTC date, as YYYY/DOY, and time" },
154 { COL_UTC_TIME
, "UTC time" },
159 const char *val_str
= try_val_to_str(fmt_num
, dlist_vals
);
160 ws_assert(val_str
!= NULL
);
164 /* Given a format number (as defined in column-utils.h), returns its
165 filter abbreviation. This can return NULL for columns that can't
166 be used in filters. */
168 col_format_abbrev(const int fmt_num
) {
170 static const value_string alist_vals
[] = {
172 { COL_ABS_YMD_TIME
, COLUMN_FIELD_FILTER
"abs_ymd_time" },
173 { COL_ABS_YDOY_TIME
, COLUMN_FIELD_FILTER
"abs_ydoy_time" },
174 { COL_ABS_TIME
, COLUMN_FIELD_FILTER
"abs_time" },
176 /* Don't have abbreviations or register fields for these columns, because
177 * they don't work. Cumulative Bytes, Delta Time Displayed and Number Displayed
178 * depend on whether the current field and previous fields are displayed, and so
179 * aren't idempotent. We might want to do custom columns in the future,
180 * though the implementation is harder.
182 { COL_CUMULATIVE_BYTES
, COLUMN_FIELD_FILTER
"cumulative_bytes" },
183 { COL_CUSTOM
, COLUMN_FIELD_FILTER
"custom" },
184 { COL_DELTA_TIME_DIS
, COLUMN_FIELD_FILTER
"delta_time_dis" },
185 { COL_NUMBER_DIS
, COLUMN_FIELD_FILTER
"number_displayed" },
187 { COL_DELTA_TIME
, COLUMN_FIELD_FILTER
"delta_time" },
188 { COL_RES_DST
, COLUMN_FIELD_FILTER
"res_dst" },
189 { COL_UNRES_DST
, COLUMN_FIELD_FILTER
"unres_dst" },
190 { COL_RES_DST_PORT
, COLUMN_FIELD_FILTER
"res_dst_port" },
191 { COL_UNRES_DST_PORT
, COLUMN_FIELD_FILTER
"unres_dst_port" },
192 { COL_DEF_DST
, COLUMN_FIELD_FILTER
"def_dst" },
193 { COL_DEF_DST_PORT
, COLUMN_FIELD_FILTER
"def_dst_port" },
194 { COL_EXPERT
, COLUMN_FIELD_FILTER
"expert" },
195 { COL_IF_DIR
, COLUMN_FIELD_FILTER
"if_dir" },
196 { COL_FREQ_CHAN
, COLUMN_FIELD_FILTER
"freq_chan" },
197 { COL_DEF_DL_DST
, COLUMN_FIELD_FILTER
"def_dl_dst" },
198 { COL_DEF_DL_SRC
, COLUMN_FIELD_FILTER
"def_dl_src" },
199 { COL_RES_DL_DST
, COLUMN_FIELD_FILTER
"res_dl_dst" },
200 { COL_UNRES_DL_DST
, COLUMN_FIELD_FILTER
"unres_dl_dst" },
201 { COL_RES_DL_SRC
, COLUMN_FIELD_FILTER
"res_dl_src" },
202 { COL_UNRES_DL_SRC
, COLUMN_FIELD_FILTER
"unres_dl_src" },
203 { COL_RSSI
, COLUMN_FIELD_FILTER
"rssi" },
204 { COL_TX_RATE
, COLUMN_FIELD_FILTER
"tx_rate" },
205 { COL_DSCP_VALUE
, COLUMN_FIELD_FILTER
"dscp" },
206 { COL_INFO
, COLUMN_FIELD_FILTER
"info" },
207 { COL_RES_NET_DST
, COLUMN_FIELD_FILTER
"res_net_dst" },
208 { COL_UNRES_NET_DST
, COLUMN_FIELD_FILTER
"unres_net_dst" },
209 { COL_RES_NET_SRC
, COLUMN_FIELD_FILTER
"res_net_src" },
210 { COL_UNRES_NET_SRC
, COLUMN_FIELD_FILTER
"unres_net_src" },
211 { COL_DEF_NET_DST
, COLUMN_FIELD_FILTER
"def_net_dst" },
212 { COL_DEF_NET_SRC
, COLUMN_FIELD_FILTER
"def_net_src" },
213 { COL_NUMBER
, COLUMN_FIELD_FILTER
"number" },
214 { COL_PACKET_LENGTH
, COLUMN_FIELD_FILTER
"packet_length" },
215 { COL_PROTOCOL
, COLUMN_FIELD_FILTER
"protocol" },
216 { COL_REL_TIME
, COLUMN_FIELD_FILTER
"rel_time" },
217 { COL_DEF_SRC
, COLUMN_FIELD_FILTER
"def_src" },
218 { COL_DEF_SRC_PORT
, COLUMN_FIELD_FILTER
"def_src_port" },
219 { COL_RES_SRC
, COLUMN_FIELD_FILTER
"res_src" },
220 { COL_UNRES_SRC
, COLUMN_FIELD_FILTER
"unres_src" },
221 { COL_RES_SRC_PORT
, COLUMN_FIELD_FILTER
"res_src_port" },
222 { COL_UNRES_SRC_PORT
, COLUMN_FIELD_FILTER
"unres_src_port" },
223 { COL_CLS_TIME
, COLUMN_FIELD_FILTER
"cls_time" },
224 { COL_UTC_YMD_TIME
, COLUMN_FIELD_FILTER
"utc_ymc_time" },
225 { COL_UTC_YDOY_TIME
, COLUMN_FIELD_FILTER
"utc_ydoy_time" },
226 { COL_UTC_TIME
, COLUMN_FIELD_FILTER
"utc_time" },
231 const char *val_str
= try_val_to_str(fmt_num
, alist_vals
);
232 //ws_assert(val_str != NULL);
235 /* Array of columns that have been migrated to custom columns */
236 struct deprecated_columns
{
238 const char *col_expr
;
241 static struct deprecated_columns migrated_columns
[] = {
242 { /* COL_COS_VALUE */ "%U", "vlan.priority" },
243 { /* COL_CIRCUIT_ID */ "%c", "iax2.call" },
244 { /* COL_BSSGP_TLLI */ "%l", "bssgp.tlli" },
245 { /* COL_HPUX_SUBSYS */ "%H", "nettl.subsys" },
246 { /* COL_HPUX_DEVID */ "%P", "nettl.devid" },
247 { /* COL_FR_DLCI */ "%C", "fr.dlci" },
248 { /* COL_REL_CONV_TIME */ "%rct", "tcp.time_relative" },
249 { /* COL_DELTA_CONV_TIME */ "%dct", "tcp.time_delta" },
250 { /* COL_OXID */ "%XO", "fc.ox_id" },
251 { /* COL_RXID */ "%XR", "fc.rx_id" },
252 { /* COL_SRCIDX */ "%Xd", "mdshdr.srcidx" },
253 { /* COL_DSTIDX */ "%Xs", "mdshdr.dstidx" },
254 { /* COL_DCE_CTX */ "%z", "dcerpc.cn_ctx_id" },
255 /* The columns above here have been migrated since August 2009 and all
256 * completely removed since January 2016. At some point we could remove
257 * these; how many people have a preference file that they haven't opened
258 * and saved since then?
260 { /* COL_8021Q_VLAN_ID */ "%q", "vlan.id||nstrace.vlan" },
261 { /* COL_VSAN */ "%V", "mdshdr.vsan||brdwlk.vsan||fc.vft.vf_id" },
262 { /* COL_DCE_CALL */ "%y", "dcerpc.cn_call_id||dcerpc.dg_seqnum" },
263 { /* COL_TEI */ "%E", "lapd.tei" },
267 try_convert_to_column_field(const char *field
)
269 static const value_string migrated_fields
[] = {
270 { COL_NUMBER
, COLUMN_FIELD_FILTER
"No." },
271 { COL_CLS_TIME
, COLUMN_FIELD_FILTER
"Time" },
272 { COL_DEF_SRC
, COLUMN_FIELD_FILTER
"Source" },
273 { COL_DEF_DST
, COLUMN_FIELD_FILTER
"Destination" },
274 { COL_PROTOCOL
, COLUMN_FIELD_FILTER
"Protocol" },
275 { COL_PACKET_LENGTH
, COLUMN_FIELD_FILTER
"Length" },
276 { COL_INFO
, COLUMN_FIELD_FILTER
"Info" },
282 idx
= str_to_val_idx(field
, migrated_fields
);
285 return col_format_abbrev(migrated_fields
[idx
].value
);
292 * Parse a column format, filling in the relevant fields of a fmt_data.
295 parse_column_format(fmt_data
*cfmt
, const char *fmt
)
297 const char *cust_format
= col_format_to_string(COL_CUSTOM
);
298 size_t cust_format_len
= strlen(cust_format
);
299 GPtrArray
*cust_format_info
;
302 char *col_custom_fields
= NULL
;
303 long col_custom_occurrence
= 0;
304 char col_display
= COLUMN_DISPLAY_STRINGS
;
307 * Is this a custom column?
309 if ((strlen(fmt
) > cust_format_len
) && (fmt
[cust_format_len
] == ':') &&
310 strncmp(fmt
, cust_format
, cust_format_len
) == 0) {
312 col_fmt
= COL_CUSTOM
;
313 cust_format_info
= g_ptr_array_new();
314 char *fmt_copy
= g_strdup(&fmt
[cust_format_len
+ 1]);
315 p
= strrchr(fmt_copy
, ':');
316 /* Pull off the two right most tokens for occurrences and
317 * "show resolved". We do it this way because the filter might
318 * have a ':' in it, e.g. for slices.
320 for (int token
= 2; token
> 0 && p
!= NULL
; token
--) {
321 g_ptr_array_insert(cust_format_info
, 0, &p
[1]);
323 p
= strrchr(fmt_copy
, ':');
325 g_ptr_array_insert(cust_format_info
, 0, fmt_copy
);
326 /* XXX - The last two tokens have been written since at least 1.6.x
327 * (commit f5ab6c1930d588f9f0be453a7be279150922b347). We could
328 * just fail at this point if cust_format_info->len < 3
330 if (cust_format_info
->len
> 0) {
331 col_custom_fields
= g_strdup(cust_format_info
->pdata
[0]);
333 if (cust_format_info
->len
> 1) {
334 col_custom_occurrence
= strtol(cust_format_info
->pdata
[1], &p
, 10);
335 if (p
== cust_format_info
->pdata
[1] || *p
!= '\0') {
336 /* Not a valid number. */
338 g_ptr_array_unref(cust_format_info
);
342 if (cust_format_info
->len
> 2) {
343 p
= cust_format_info
->pdata
[2];
347 g_ptr_array_unref(cust_format_info
);
349 col_fmt
= get_column_format_from_str(fmt
);
355 cfmt
->custom_fields
= col_custom_fields
;
356 cfmt
->custom_occurrence
= (int)col_custom_occurrence
;
357 cfmt
->display
= col_display
;
362 column_fmt_data_to_str(const fmt_data
*cfmt
)
368 if ((cfmt
->fmt
== COL_CUSTOM
) && (cfmt
->custom_fields
)) {
369 return ws_strdup_printf("%s:%s:%d:%c",
370 col_format_to_string(cfmt
->fmt
),
372 cfmt
->custom_occurrence
,
376 return ws_strdup(col_format_to_string(cfmt
->fmt
));
380 try_convert_to_custom_column(char **fmt
)
382 unsigned haystack_idx
;
384 for (haystack_idx
= 0;
385 haystack_idx
< G_N_ELEMENTS(migrated_columns
);
388 if (strcmp(migrated_columns
[haystack_idx
].col_fmt
, *fmt
) == 0) {
389 char *cust_col
= ws_strdup_printf("%%Cus:%s:0",
390 migrated_columns
[haystack_idx
].col_expr
);
399 column_dump_column_formats(void)
403 for (fmt
= 0; fmt
< NUM_COL_FMTS
; fmt
++) {
404 printf("%s\t%-35s\t%s\n", col_format_to_string(fmt
), col_format_desc(fmt
),
405 col_format_abbrev(fmt
) ? col_format_abbrev(fmt
) : "");
408 printf("\nFor each row above, the first field is the format string for specifying the\n"
409 "column in preferences, and the third field is the abbreviation used for the\n"
410 "column text in a packet matching expression. Note that a column with the format\n"
411 "must be configured in preferences for it to be filterable.\n");
413 /* XXX - Actually retrieve the default values from prefs. We could also
414 * then output the default columns for Stratoshark, if this is Stratoshark. (stshark?)
416 printf("\nThese format strings are used to specify a column format in preferences.\n"
417 "For example, to print Wireshark's default columns with tshark:\n\n"
419 "tshark.exe -o \"gui.column.format:"
420 "\\\"No.\\\",\\\"%%m\\\","
421 "\\\"Time\\\",\\\"%%t\\\","
422 "\\\"Source\\\",\\\"%%s\\\","
423 "\\\"Destination\\\",\\\"%%d\\\","
424 "\\\"Protocol\\\",\\\"%%p\\\","
425 "\\\"Length\\\",\\\"%%L\\\","
426 "\\\"Info\\\",\\\"%%i\\\"\"\n");
428 "tshark -o 'gui.column.format:"
431 "\"Source\",\"%%s\","
432 "\"Destination\",\"%%d\","
433 "\"Protocol\",\"%%p\","
434 "\"Length\",\"%%L\","
435 "\"Info\",\"%%i\"'\n");
438 if (prefs
.col_list
) {
441 GString
*current_cols
= g_string_new(NULL
);
442 for (GList
*elem
= g_list_first(prefs
.col_list
); elem
!= NULL
; elem
= elem
->next
) {
443 cfmt
= (fmt_data
*)elem
->data
;
444 prefs_fmt
= column_fmt_data_to_str(cfmt
);
445 if (current_cols
->len
!= 0) {
446 g_string_append_c(current_cols
, ',');
449 g_string_append_printf(current_cols
, "\\\"%s\\\",\\\"%s\\\"", cfmt
->title
, prefs_fmt
);
451 g_string_append_printf(current_cols
, "\"%s\",\"%s\"", cfmt
->title
, prefs_fmt
);
455 printf("\nand to print the current configuration profile's columns with tshark:\n\n"
457 "tshark -o \"gui.column.format:%s\"\n", current_cols
->str
);
459 "tshark -o 'gui.column.format:%s'\n", current_cols
->str
);
461 g_string_free(current_cols
, TRUE
);
465 /* Marks each array element true if it can be substituted for the given
468 get_column_format_matches(bool *fmt_list
, const int format
) {
470 /* Get the obvious: the format itself */
471 if ((format
>= 0) && (format
< NUM_COL_FMTS
))
472 fmt_list
[format
] = true;
474 /* Get any formats lower down on the chain */
477 fmt_list
[COL_RES_DL_SRC
] = true;
478 fmt_list
[COL_RES_NET_SRC
] = true;
481 fmt_list
[COL_RES_DL_SRC
] = true;
482 fmt_list
[COL_RES_NET_SRC
] = true;
485 fmt_list
[COL_UNRES_DL_SRC
] = true;
486 fmt_list
[COL_UNRES_NET_SRC
] = true;
489 fmt_list
[COL_RES_DL_DST
] = true;
490 fmt_list
[COL_RES_NET_DST
] = true;
493 fmt_list
[COL_RES_DL_DST
] = true;
494 fmt_list
[COL_RES_NET_DST
] = true;
497 fmt_list
[COL_UNRES_DL_DST
] = true;
498 fmt_list
[COL_UNRES_NET_DST
] = true;
501 fmt_list
[COL_RES_DL_SRC
] = true;
504 fmt_list
[COL_RES_DL_DST
] = true;
506 case COL_DEF_NET_SRC
:
507 fmt_list
[COL_RES_NET_SRC
] = true;
509 case COL_DEF_NET_DST
:
510 fmt_list
[COL_RES_NET_DST
] = true;
512 case COL_DEF_SRC_PORT
:
513 fmt_list
[COL_RES_SRC_PORT
] = true;
515 case COL_DEF_DST_PORT
:
516 fmt_list
[COL_RES_DST_PORT
] = true;
524 * These tables are indexed by the number of digits of precision for
525 * time stamps; all TS_PREC_FIXED_ types have values equal to the
526 * number of digits of precision, and NUM_WS_TSPREC_VALS is the
527 * total number of such values as there's a one-to-one correspondence
528 * between WS_TSPREC_ values and TS_PREC_FIXED_ values.
532 * Strings for YYYY-MM-DD HH:MM:SS.SSSS dates and times.
533 * (Yes, we know, this has a Y10K problem.)
535 static const char *ts_ymd
[NUM_WS_TSPREC_VALS
] = {
536 "0000-00-00 00:00:00",
537 "0000-00-00 00:00:00.0",
538 "0000-00-00 00:00:00.00",
539 "0000-00-00 00:00:00.000",
540 "0000-00-00 00:00:00.0000",
541 "0000-00-00 00:00:00.00000",
542 "0000-00-00 00:00:00.000000",
543 "0000-00-00 00:00:00.0000000",
544 "0000-00-00 00:00:00.00000000",
545 "0000-00-00 00:00:00.000000000",
548 static const char *ts_ymd_utc
[NUM_WS_TSPREC_VALS
] = {
549 "0000-00-00 00:00:00Z",
550 "0000-00-00 00:00:00.0Z",
551 "0000-00-00 00:00:00.00Z",
552 "0000-00-00 00:00:00.000Z",
553 "0000-00-00 00:00:00.0000Z",
554 "0000-00-00 00:00:00.00000Z",
555 "0000-00-00 00:00:00.000000Z",
556 "0000-00-00 00:00:00.0000000Z",
557 "0000-00-00 00:00:00.00000000Z",
558 "0000-00-00 00:00:00.000000000Z",
562 * Strings for YYYY/DOY HH:MM:SS.SSSS dates and times.
563 * (Yes, we know, this also has a Y10K problem.)
565 static const char *ts_ydoy
[NUM_WS_TSPREC_VALS
] = {
567 "0000/000 00:00:00.0",
568 "0000/000 00:00:00.00",
569 "0000/000 00:00:00.000",
570 "0000/000 00:00:00.0000",
571 "0000/000 00:00:00.00000",
572 "0000/000 00:00:00.000000",
573 "0000/000 00:00:00.0000000",
574 "0000/000 00:00:00.00000000",
575 "0000/000 00:00:00.000000000",
578 static const char *ts_ydoy_utc
[NUM_WS_TSPREC_VALS
] = {
579 "0000/000 00:00:00Z",
580 "0000/000 00:00:00.0Z",
581 "0000/000 00:00:00.00Z",
582 "0000/000 00:00:00.000Z",
583 "0000/000 00:00:00.0000Z",
584 "0000/000 00:00:00.00000Z",
585 "0000/000 00:00:00.000000Z",
586 "0000/000 00:00:00.0000000Z",
587 "0000/000 00:00:00.00000000Z",
588 "0000/000 00:00:00.000000000Z",
592 * Strings for HH:MM:SS.SSSS absolute times without dates.
594 static const char *ts_abstime
[NUM_WS_TSPREC_VALS
] = {
604 "00:00:00.000000000",
607 static const char *ts_abstime_utc
[NUM_WS_TSPREC_VALS
] = {
616 "00:00:00.00000000Z",
617 "00:00:00.000000000Z",
621 * Strings for SSSS.S relative and delta times.
622 * (Yes, this has s 10,000-seconds problem.)
624 static const char *ts_rel_delta_time
[NUM_WS_TSPREC_VALS
] = {
638 * Strings for UN*X/POSIX Epoch times.
640 static const char *ts_epoch_time
[NUM_WS_TSPREC_VALS
] = {
641 "0000000000000000000",
642 "0000000000000000000.0",
643 "0000000000000000000.00",
644 "0000000000000000000.000",
645 "0000000000000000000.0000",
646 "0000000000000000000.00000",
647 "0000000000000000000.000000",
648 "0000000000000000000.0000000",
649 "0000000000000000000.00000000",
650 "0000000000000000000.000000000",
653 /* Returns a string representing the longest possible value for
654 a timestamp column type. */
656 get_timestamp_column_longest_string(const int type
, const int precision
)
660 case(TS_ABSOLUTE_WITH_YMD
):
661 if(precision
== TS_PREC_AUTO
) {
663 * Return the string for the maximum precision, so that
664 * our caller leaves room for that string.
666 return ts_ymd
[WS_TSPREC_MAX
];
667 } else if(precision
>= 0 && precision
< NUM_WS_TSPREC_VALS
)
668 return ts_ymd
[precision
];
670 ws_assert_not_reached();
672 case(TS_UTC_WITH_YMD
):
673 if(precision
== TS_PREC_AUTO
) {
675 * Return the string for the maximum precision, so that
676 * our caller leaves room for that string.
678 return ts_ymd_utc
[WS_TSPREC_MAX
];
679 } else if(precision
>= 0 && precision
< NUM_WS_TSPREC_VALS
)
680 return ts_ymd_utc
[precision
];
682 ws_assert_not_reached();
684 case(TS_ABSOLUTE_WITH_YDOY
):
685 if(precision
== TS_PREC_AUTO
) {
687 * Return the string for the maximum precision, so that
688 * our caller leaves room for that string.
690 return ts_ydoy
[WS_TSPREC_MAX
];
691 } else if(precision
>= 0 && precision
< NUM_WS_TSPREC_VALS
)
692 return ts_ydoy
[precision
];
694 ws_assert_not_reached();
696 case(TS_UTC_WITH_YDOY
):
697 if(precision
== TS_PREC_AUTO
) {
699 * Return the string for the maximum precision, so that
700 * our caller leaves room for that string.
702 return ts_ydoy_utc
[WS_TSPREC_MAX
];
703 } else if(precision
>= 0 && precision
< NUM_WS_TSPREC_VALS
)
704 return ts_ydoy_utc
[precision
];
706 ws_assert_not_reached();
709 if(precision
== TS_PREC_AUTO
) {
711 * Return the string for the maximum precision, so that
712 * our caller leaves room for that string.
714 return ts_abstime
[WS_TSPREC_MAX
];
715 } else if(precision
>= 0 && precision
< NUM_WS_TSPREC_VALS
)
716 return ts_abstime
[precision
];
718 ws_assert_not_reached();
721 if(precision
== TS_PREC_AUTO
) {
723 * Return the string for the maximum precision, so that
724 * our caller leaves room for that string.
726 return ts_abstime_utc
[WS_TSPREC_MAX
];
727 } else if(precision
>= 0 && precision
< NUM_WS_TSPREC_VALS
)
728 return ts_abstime_utc
[precision
];
730 ws_assert_not_reached();
732 case(TS_RELATIVE
): /* fallthrough */
735 if(precision
== TS_PREC_AUTO
) {
737 * Return the string for the maximum precision, so that
738 * our caller leaves room for that string.
740 return ts_rel_delta_time
[WS_TSPREC_MAX
];
741 } else if(precision
>= 0 && precision
< NUM_WS_TSPREC_VALS
)
742 return ts_rel_delta_time
[precision
];
744 ws_assert_not_reached();
747 /* This is enough to represent 2^63 (signed 64-bit integer) + fractions */
748 if(precision
== TS_PREC_AUTO
) {
750 * Return the string for the maximum precision, so that
751 * our caller leaves room for that string.
753 return ts_epoch_time
[WS_TSPREC_MAX
];
754 } else if(precision
>= 0 && precision
< NUM_WS_TSPREC_VALS
)
755 return ts_epoch_time
[precision
];
757 ws_assert_not_reached();
760 /* This should not happen. */
761 return "0000.000000";
763 ws_assert_not_reached();
766 /* never reached, satisfy compiler */
770 /* Returns a string representing the longest possible value for a
771 particular column type. See also get_column_width_string() above.
773 Except for the COL...SRC and COL...DST columns, these are used
774 only when a capture is being displayed while it's taking place;
775 they are arguably somewhat fragile, as changes to the code that
776 generates them don't cause these widths to change, but that's
777 probably not too big a problem, given that the sizes are
778 recomputed based on the actual data in the columns when the capture
779 is done, and given that the width for COL...SRC and COL...DST columns
780 is somewhat arbitrary in any case. We should probably clean
781 that up eventually, though. */
783 get_column_longest_string(const int format
)
790 return get_timestamp_column_longest_string(timestamp_get_type(), timestamp_get_precision());
791 case COL_ABS_YMD_TIME
:
792 return get_timestamp_column_longest_string(TS_ABSOLUTE_WITH_YMD
, timestamp_get_precision());
793 case COL_ABS_YDOY_TIME
:
794 return get_timestamp_column_longest_string(TS_ABSOLUTE_WITH_YDOY
, timestamp_get_precision());
795 case COL_UTC_YMD_TIME
:
796 return get_timestamp_column_longest_string(TS_UTC_WITH_YMD
, timestamp_get_precision());
797 case COL_UTC_YDOY_TIME
:
798 return get_timestamp_column_longest_string(TS_UTC_WITH_YDOY
, timestamp_get_precision());
800 return get_timestamp_column_longest_string(TS_ABSOLUTE
, timestamp_get_precision());
802 return get_timestamp_column_longest_string(TS_UTC
, timestamp_get_precision());
804 return get_timestamp_column_longest_string(TS_RELATIVE
, timestamp_get_precision());
806 return get_timestamp_column_longest_string(TS_DELTA
, timestamp_get_precision());
807 case COL_DELTA_TIME_DIS
:
808 return get_timestamp_column_longest_string(TS_DELTA_DIS
, timestamp_get_precision());
814 case COL_UNRES_DL_SRC
:
815 case COL_DEF_NET_SRC
:
816 case COL_RES_NET_SRC
:
817 case COL_UNRES_NET_SRC
:
823 case COL_UNRES_DL_DST
:
824 case COL_DEF_NET_DST
:
825 case COL_RES_NET_DST
:
826 case COL_UNRES_NET_DST
:
827 return "00000000.000000000000"; /* IPX-style */
828 case COL_DEF_SRC_PORT
:
829 case COL_RES_SRC_PORT
:
830 case COL_UNRES_SRC_PORT
:
831 case COL_DEF_DST_PORT
:
832 case COL_RES_DST_PORT
:
833 case COL_UNRES_DST_PORT
:
836 return "Protocol"; /* not the longest, but the longest is too long */
837 case COL_PACKET_LENGTH
:
839 case COL_CUMULATIVE_BYTES
:
842 return "i 00000000 I";
848 return "AAA BBB"; /* not the longest, but the longest is too long */
852 return "9999 MHz [A 999]";
854 return "0000000000"; /* not the longest, but the longest is too long */
855 default: /* COL_INFO */
856 return "Source port: kerberos-master Destination port: kerberos-master";
860 /* Returns the longer string of the column title or the hard-coded width of
861 * its contents for building the packet list layout. */
863 get_column_width_string(const int format
, const int col
)
865 if(strlen(get_column_longest_string(format
)) >
866 strlen(get_column_title(col
)))
867 return get_column_longest_string(format
);
869 return get_column_title(col
);
872 /* Returns the longest possible width, in characters, for a particular
875 get_column_char_width(const int format
)
877 return (int)strlen(get_column_longest_string(format
));
881 get_column_format(const int col
)
883 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
886 if (!clp
) /* Invalid column requested */
889 cfmt
= (fmt_data
*) clp
->data
;
895 set_column_format(const int col
, const int fmt
)
897 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
900 if (!clp
) /* Invalid column requested */
903 cfmt
= (fmt_data
*) clp
->data
;
909 get_column_format_from_str(const char *str
)
913 for (i
= 0; i
< NUM_COL_FMTS
; i
++) {
914 if (strcmp(str
, col_format_to_string(i
)) == 0)
917 return -1; /* illegal */
921 get_column_title(const int col
)
923 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
926 if (!clp
) /* Invalid column requested */
929 cfmt
= (fmt_data
*) clp
->data
;
935 set_column_title(const int col
, const char *title
)
937 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
940 if (!clp
) /* Invalid column requested */
943 cfmt
= (fmt_data
*) clp
->data
;
945 g_free (cfmt
->title
);
946 cfmt
->title
= g_strdup (title
);
950 get_column_visible(const int col
)
952 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
955 if (!clp
) /* Invalid column requested */
958 cfmt
= (fmt_data
*) clp
->data
;
960 return(cfmt
->visible
);
964 set_column_visible(const int col
, bool visible
)
966 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
969 if (!clp
) /* Invalid column requested */
972 cfmt
= (fmt_data
*) clp
->data
;
974 cfmt
->visible
= visible
;
978 get_column_display_format(const int col
)
980 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
983 if (!clp
) /* Invalid column requested */
986 cfmt
= (fmt_data
*) clp
->data
;
988 return(cfmt
->display
);
992 set_column_display_format(const int col
, char display
)
994 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
997 if (!clp
) /* Invalid column requested */
1000 cfmt
= (fmt_data
*) clp
->data
;
1002 cfmt
->display
= display
;
1006 get_column_custom_fields(const int col
)
1008 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
1011 if (!clp
) /* Invalid column requested */
1014 cfmt
= (fmt_data
*) clp
->data
;
1016 return(cfmt
->custom_fields
);
1020 set_column_custom_fields(const int col
, const char *custom_fields
)
1022 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
1025 if (!clp
) /* Invalid column requested */
1028 cfmt
= (fmt_data
*) clp
->data
;
1030 g_free (cfmt
->custom_fields
);
1031 cfmt
->custom_fields
= g_strdup (custom_fields
);
1035 get_column_custom_occurrence(const int col
)
1037 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
1040 if (!clp
) /* Invalid column requested */
1043 cfmt
= (fmt_data
*) clp
->data
;
1045 return(cfmt
->custom_occurrence
);
1049 set_column_custom_occurrence(const int col
, const int custom_occurrence
)
1051 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
1054 if (!clp
) /* Invalid column requested */
1057 cfmt
= (fmt_data
*) clp
->data
;
1059 cfmt
->custom_occurrence
= custom_occurrence
;
1063 get_custom_field_tooltip (char *custom_field
, int occurrence
)
1065 header_field_info
*hfi
= proto_registrar_get_byname(custom_field
);
1067 /* Not a valid field */
1069 if (dfilter_compile(custom_field
, &dfilter
, NULL
)) {
1070 dfilter_free(dfilter
);
1071 return ws_strdup_printf("Expression: %s", custom_field
);
1073 return ws_strdup_printf("Unknown Field: %s", custom_field
);
1076 if (hfi
->parent
== -1) {
1078 return ws_strdup_printf("%s (%s)", hfi
->name
, hfi
->abbrev
);
1081 if (occurrence
== 0) {
1082 /* All occurrences */
1083 return ws_strdup_printf("%s\n%s (%s)", proto_get_protocol_name(hfi
->parent
), hfi
->name
, hfi
->abbrev
);
1086 /* One given occurrence */
1087 return ws_strdup_printf("%s\n%s (%s#%d)", proto_get_protocol_name(hfi
->parent
), hfi
->name
, hfi
->abbrev
, occurrence
);
1091 get_column_tooltip(const int col
)
1093 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
1097 GString
*column_tooltip
;
1100 if (!clp
) /* Invalid column requested */
1103 cfmt
= (fmt_data
*) clp
->data
;
1105 if (cfmt
->fmt
!= COL_CUSTOM
) {
1106 /* Use format description */
1107 return g_strdup(col_format_desc(cfmt
->fmt
));
1110 fields
= g_regex_split_simple(COL_CUSTOM_PRIME_REGEX
, cfmt
->custom_fields
,
1111 (GRegexCompileFlags
) (G_REGEX_RAW
),
1113 column_tooltip
= g_string_new("");
1115 for (i
= 0; i
< g_strv_length(fields
); i
++) {
1116 if (fields
[i
] && *fields
[i
]) {
1117 char *field_tooltip
= get_custom_field_tooltip(fields
[i
], cfmt
->custom_occurrence
);
1119 g_string_append(column_tooltip
, "\n\nOR\n\n");
1121 g_string_append(column_tooltip
, field_tooltip
);
1122 g_free (field_tooltip
);
1129 return g_string_free (column_tooltip
, FALSE
);
1133 get_column_text(column_info
*cinfo
, const int col
)
1136 ws_assert(col
< cinfo
->num_cols
);
1138 if ((get_column_display_format(col
) == COLUMN_DISPLAY_VALUES
) && cinfo
->col_expr
.col_expr_val
[col
]) {
1139 /* Use the unresolved value in col_expr_val */
1140 return cinfo
->col_expr
.col_expr_val
[col
];
1143 return cinfo
->columns
[col
].col_data
;
1147 col_finalize(column_info
*cinfo
)
1150 col_item_t
* col_item
;
1153 for (i
= 0; i
< cinfo
->num_cols
; i
++) {
1154 col_item
= &cinfo
->columns
[i
];
1156 if (col_item
->col_fmt
== COL_CUSTOM
) {
1157 if(!dfilter_compile(col_item
->col_custom_fields
, &col_item
->col_custom_dfilter
, NULL
)) {
1158 /* XXX: Should we issue a warning? */
1159 g_free(col_item
->col_custom_fields
);
1160 col_item
->col_custom_fields
= NULL
;
1161 col_item
->col_custom_occurrence
= 0;
1162 col_item
->col_custom_dfilter
= NULL
;
1164 if (col_item
->col_custom_fields
) {
1165 char **fields
= g_regex_split(cinfo
->prime_regex
, col_item
->col_custom_fields
,
1169 for (i_field
= 0; i_field
< g_strv_length(fields
); i_field
++) {
1170 if (fields
[i_field
] && *fields
[i_field
]) {
1171 if (dfilter_compile_full(fields
[i_field
], &dfilter
, NULL
, DF_EXPAND_MACROS
|DF_OPTIMIZE
|DF_RETURN_VALUES
, __func__
)) {
1172 col_custom_t
*custom_info
= g_new0(col_custom_t
, 1);
1173 custom_info
->dftext
= g_strdup(fields
[i_field
]);
1174 custom_info
->dfilter
= dfilter
;
1175 header_field_info
*hfinfo
= proto_registrar_get_byname(fields
[i_field
]);
1177 custom_info
->field_id
= hfinfo
->id
;
1179 col_item
->col_custom_fields_ids
= g_slist_append(col_item
->col_custom_fields_ids
, custom_info
);
1186 col_item
->col_custom_fields
= NULL
;
1187 col_item
->col_custom_occurrence
= 0;
1188 col_item
->col_custom_dfilter
= NULL
;
1191 col_item
->fmt_matx
= g_new0(bool, NUM_COL_FMTS
);
1192 get_column_format_matches(col_item
->fmt_matx
, col_item
->col_fmt
);
1193 col_item
->col_data
= NULL
;
1195 if (col_item
->col_fmt
== COL_INFO
) {
1196 col_item
->col_buf
= g_new(char, COL_MAX_INFO_LEN
);
1197 cinfo
->col_expr
.col_expr_val
[i
] = g_new(char, COL_MAX_INFO_LEN
);
1199 col_item
->col_buf
= g_new(char, COL_MAX_LEN
);
1200 cinfo
->col_expr
.col_expr_val
[i
] = g_new(char, COL_MAX_LEN
);
1203 cinfo
->col_expr
.col_expr
[i
] = "";
1206 cinfo
->col_expr
.col_expr
[i
] = NULL
;
1207 cinfo
->col_expr
.col_expr_val
[i
] = NULL
;
1209 for (i
= 0; i
< cinfo
->num_cols
; i
++) {
1212 for (j
= 0; j
< NUM_COL_FMTS
; j
++) {
1213 if (!cinfo
->columns
[i
].fmt_matx
[j
])
1216 if (cinfo
->col_first
[j
] == -1)
1217 cinfo
->col_first
[j
] = i
;
1219 cinfo
->col_last
[j
] = i
;
1225 build_column_format_array(column_info
*cinfo
, const int num_cols
, const bool reset_fences
)
1228 col_item_t
* col_item
;
1230 /* Build the column format array */
1231 col_setup(cinfo
, num_cols
);
1233 for (i
= 0; i
< cinfo
->num_cols
; i
++) {
1234 col_item
= &cinfo
->columns
[i
];
1235 col_item
->col_fmt
= get_column_format(i
);
1236 col_item
->col_title
= g_strdup(get_column_title(i
));
1237 if (col_item
->col_fmt
== COL_CUSTOM
) {
1238 col_item
->col_custom_fields
= g_strdup(get_column_custom_fields(i
));
1239 col_item
->col_custom_occurrence
= get_column_custom_occurrence(i
);
1241 col_item
->hf_id
= proto_registrar_get_id_byname(col_format_abbrev(col_item
->col_fmt
));
1244 col_item
->col_fence
= 0;
1247 col_finalize(cinfo
);
1251 column_deregister_fields(void)
1254 for (unsigned int i
= 0; i
< hf_cols_cleanup
; ++i
) {
1255 proto_deregister_field(proto_cols
, *(hf_cols
[i
].p_id
));
1256 g_free(hf_cols
[i
].p_id
);
1258 proto_add_deregistered_data(hf_cols
);
1260 hf_cols_cleanup
= 0;
1265 column_register_fields(void)
1269 GArray
*hf_col_array
;
1270 hf_register_info new_hf
;
1273 if (proto_cols
<= 0) {
1274 proto_cols
= proto_get_id_by_filter_name("_ws.col");
1276 if (proto_cols
<= 0) {
1277 proto_cols
= proto_register_protocol("Wireshark Columns", "Columns", "_ws.col");
1279 column_deregister_fields();
1280 if (prefs
.col_list
!= NULL
) {
1281 prefs
.num_cols
= g_list_length(prefs
.col_list
);
1282 hf_col_array
= g_array_new(false, true, sizeof(hf_register_info
));
1283 used_fmts
= g_new0(bool, NUM_COL_FMTS
);
1284 for (GList
*elem
= g_list_first(prefs
.col_list
); elem
!= NULL
; elem
= elem
->next
) {
1285 cfmt
= (fmt_data
*)elem
->data
;
1286 if (col_format_abbrev(cfmt
->fmt
) && !used_fmts
[cfmt
->fmt
]) {
1287 used_fmts
[cfmt
->fmt
] = true;
1288 hf_id
= g_new(int, 1);
1290 new_hf
.p_id
= hf_id
;
1291 new_hf
.hfinfo
.name
= g_strdup(col_format_desc(cfmt
->fmt
));
1292 new_hf
.hfinfo
.abbrev
= g_strdup(col_format_abbrev(cfmt
->fmt
));
1293 new_hf
.hfinfo
.type
= FT_STRING
;
1294 new_hf
.hfinfo
.display
= BASE_NONE
;
1295 new_hf
.hfinfo
.strings
= NULL
;
1296 new_hf
.hfinfo
.bitmask
= 0;
1297 new_hf
.hfinfo
.blurb
= NULL
;
1299 g_array_append_vals(hf_col_array
, &new_hf
, 1);
1303 hf_cols_cleanup
= hf_col_array
->len
;
1305 proto_register_field_array(proto_cols
, (hf_register_info
*)hf_col_array
->data
, hf_col_array
->len
);
1306 hf_cols
= (hf_register_info
*)g_array_free(hf_col_array
, false);
1311 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1316 * indent-tabs-mode: nil
1319 * vi: set shiftwidth=2 tabstop=8 expandtab:
1320 * :indentSize=2:tabSize=8:noTabs=true: