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",
549 * Strings for YYYY/DOY HH:MM:SS.SSSS dates and times.
550 * (Yes, we know, this also has a Y10K problem.)
552 static const char *ts_ydoy
[NUM_WS_TSPREC_VALS
] = {
554 "0000/000 00:00:00.0",
555 "0000/000 00:00:00.00",
556 "0000/000 00:00:00.000",
557 "0000/000 00:00:00.0000",
558 "0000/000 00:00:00.00000",
559 "0000/000 00:00:00.000000",
560 "0000/000 00:00:00.0000000",
561 "0000/000 00:00:00.00000000",
562 "0000/000 00:00:00.000000000",
566 * Strings for HH:MM:SS.SSSS absolute times without dates.
568 static const char *ts_abstime
[NUM_WS_TSPREC_VALS
] = {
578 "00:00:00.000000000",
582 * Strings for SSSS.S relative and delta times.
583 * (Yes, this has s 10,000-seconds problem.)
585 static const char *ts_rel_delta_time
[NUM_WS_TSPREC_VALS
] = {
599 * Strings for UN*X/POSIX Epoch times.
601 static const char *ts_epoch_time
[NUM_WS_TSPREC_VALS
] = {
602 "0000000000000000000",
603 "0000000000000000000.0",
604 "0000000000000000000.00",
605 "0000000000000000000.000",
606 "0000000000000000000.0000",
607 "0000000000000000000.00000",
608 "0000000000000000000.000000",
609 "0000000000000000000.0000000",
610 "0000000000000000000.00000000",
611 "0000000000000000000.000000000",
614 /* Returns a string representing the longest possible value for
615 a timestamp column type. */
617 get_timestamp_column_longest_string(const int type
, const int precision
)
621 case(TS_ABSOLUTE_WITH_YMD
):
622 case(TS_UTC_WITH_YMD
):
623 if(precision
== TS_PREC_AUTO
) {
625 * Return the string for the maximum precision, so that
626 * our caller leaves room for that string.
628 return ts_ymd
[WS_TSPREC_MAX
];
629 } else if(precision
>= 0 && precision
< NUM_WS_TSPREC_VALS
)
630 return ts_ymd
[precision
];
632 ws_assert_not_reached();
634 case(TS_ABSOLUTE_WITH_YDOY
):
635 case(TS_UTC_WITH_YDOY
):
636 if(precision
== TS_PREC_AUTO
) {
638 * Return the string for the maximum precision, so that
639 * our caller leaves room for that string.
641 return ts_ydoy
[WS_TSPREC_MAX
];
642 } else if(precision
>= 0 && precision
< NUM_WS_TSPREC_VALS
)
643 return ts_ydoy
[precision
];
645 ws_assert_not_reached();
649 if(precision
== TS_PREC_AUTO
) {
651 * Return the string for the maximum precision, so that
652 * our caller leaves room for that string.
654 return ts_abstime
[WS_TSPREC_MAX
];
655 } else if(precision
>= 0 && precision
< NUM_WS_TSPREC_VALS
)
656 return ts_abstime
[precision
];
658 ws_assert_not_reached();
660 case(TS_RELATIVE
): /* fallthrough */
663 if(precision
== TS_PREC_AUTO
) {
665 * Return the string for the maximum precision, so that
666 * our caller leaves room for that string.
668 return ts_rel_delta_time
[WS_TSPREC_MAX
];
669 } else if(precision
>= 0 && precision
< NUM_WS_TSPREC_VALS
)
670 return ts_rel_delta_time
[precision
];
672 ws_assert_not_reached();
675 /* This is enough to represent 2^63 (signed 64-bit integer) + fractions */
676 if(precision
== TS_PREC_AUTO
) {
678 * Return the string for the maximum precision, so that
679 * our caller leaves room for that string.
681 return ts_epoch_time
[WS_TSPREC_MAX
];
682 } else if(precision
>= 0 && precision
< NUM_WS_TSPREC_VALS
)
683 return ts_epoch_time
[precision
];
685 ws_assert_not_reached();
688 /* This should not happen. */
689 return "0000.000000";
691 ws_assert_not_reached();
694 /* never reached, satisfy compiler */
698 /* Returns a string representing the longest possible value for a
699 particular column type. See also get_column_width_string() above.
701 Except for the COL...SRC and COL...DST columns, these are used
702 only when a capture is being displayed while it's taking place;
703 they are arguably somewhat fragile, as changes to the code that
704 generates them don't cause these widths to change, but that's
705 probably not too big a problem, given that the sizes are
706 recomputed based on the actual data in the columns when the capture
707 is done, and given that the width for COL...SRC and COL...DST columns
708 is somewhat arbitrary in any case. We should probably clean
709 that up eventually, though. */
711 get_column_longest_string(const int format
)
718 return get_timestamp_column_longest_string(timestamp_get_type(), timestamp_get_precision());
719 case COL_ABS_YMD_TIME
:
720 return get_timestamp_column_longest_string(TS_ABSOLUTE_WITH_YMD
, timestamp_get_precision());
721 case COL_ABS_YDOY_TIME
:
722 return get_timestamp_column_longest_string(TS_ABSOLUTE_WITH_YDOY
, timestamp_get_precision());
723 case COL_UTC_YMD_TIME
:
724 return get_timestamp_column_longest_string(TS_UTC_WITH_YMD
, timestamp_get_precision());
725 case COL_UTC_YDOY_TIME
:
726 return get_timestamp_column_longest_string(TS_UTC_WITH_YDOY
, timestamp_get_precision());
728 return get_timestamp_column_longest_string(TS_ABSOLUTE
, timestamp_get_precision());
730 return get_timestamp_column_longest_string(TS_UTC
, timestamp_get_precision());
732 return get_timestamp_column_longest_string(TS_RELATIVE
, timestamp_get_precision());
734 return get_timestamp_column_longest_string(TS_DELTA
, timestamp_get_precision());
735 case COL_DELTA_TIME_DIS
:
736 return get_timestamp_column_longest_string(TS_DELTA_DIS
, timestamp_get_precision());
742 case COL_UNRES_DL_SRC
:
743 case COL_DEF_NET_SRC
:
744 case COL_RES_NET_SRC
:
745 case COL_UNRES_NET_SRC
:
751 case COL_UNRES_DL_DST
:
752 case COL_DEF_NET_DST
:
753 case COL_RES_NET_DST
:
754 case COL_UNRES_NET_DST
:
755 return "00000000.000000000000"; /* IPX-style */
756 case COL_DEF_SRC_PORT
:
757 case COL_RES_SRC_PORT
:
758 case COL_UNRES_SRC_PORT
:
759 case COL_DEF_DST_PORT
:
760 case COL_RES_DST_PORT
:
761 case COL_UNRES_DST_PORT
:
764 return "Protocol"; /* not the longest, but the longest is too long */
765 case COL_PACKET_LENGTH
:
767 case COL_CUMULATIVE_BYTES
:
770 return "i 00000000 I";
776 return "AAA BBB"; /* not the longest, but the longest is too long */
780 return "9999 MHz [A 999]";
782 return "0000000000"; /* not the longest, but the longest is too long */
783 default: /* COL_INFO */
784 return "Source port: kerberos-master Destination port: kerberos-master";
788 /* Returns the longer string of the column title or the hard-coded width of
789 * its contents for building the packet list layout. */
791 get_column_width_string(const int format
, const int col
)
793 if(strlen(get_column_longest_string(format
)) >
794 strlen(get_column_title(col
)))
795 return get_column_longest_string(format
);
797 return get_column_title(col
);
800 /* Returns the longest possible width, in characters, for a particular
803 get_column_char_width(const int format
)
805 return (int)strlen(get_column_longest_string(format
));
809 get_column_format(const int col
)
811 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
814 if (!clp
) /* Invalid column requested */
817 cfmt
= (fmt_data
*) clp
->data
;
823 set_column_format(const int col
, const int fmt
)
825 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
828 if (!clp
) /* Invalid column requested */
831 cfmt
= (fmt_data
*) clp
->data
;
837 get_column_format_from_str(const char *str
)
841 for (i
= 0; i
< NUM_COL_FMTS
; i
++) {
842 if (strcmp(str
, col_format_to_string(i
)) == 0)
845 return -1; /* illegal */
849 get_column_title(const int col
)
851 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
854 if (!clp
) /* Invalid column requested */
857 cfmt
= (fmt_data
*) clp
->data
;
863 set_column_title(const int col
, const char *title
)
865 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
868 if (!clp
) /* Invalid column requested */
871 cfmt
= (fmt_data
*) clp
->data
;
873 g_free (cfmt
->title
);
874 cfmt
->title
= g_strdup (title
);
878 get_column_visible(const int col
)
880 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
883 if (!clp
) /* Invalid column requested */
886 cfmt
= (fmt_data
*) clp
->data
;
888 return(cfmt
->visible
);
892 set_column_visible(const int col
, bool visible
)
894 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
897 if (!clp
) /* Invalid column requested */
900 cfmt
= (fmt_data
*) clp
->data
;
902 cfmt
->visible
= visible
;
906 get_column_display_format(const int col
)
908 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
911 if (!clp
) /* Invalid column requested */
914 cfmt
= (fmt_data
*) clp
->data
;
916 return(cfmt
->display
);
920 set_column_display_format(const int col
, char display
)
922 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
925 if (!clp
) /* Invalid column requested */
928 cfmt
= (fmt_data
*) clp
->data
;
930 cfmt
->display
= display
;
934 get_column_custom_fields(const int col
)
936 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
939 if (!clp
) /* Invalid column requested */
942 cfmt
= (fmt_data
*) clp
->data
;
944 return(cfmt
->custom_fields
);
948 set_column_custom_fields(const int col
, const char *custom_fields
)
950 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
953 if (!clp
) /* Invalid column requested */
956 cfmt
= (fmt_data
*) clp
->data
;
958 g_free (cfmt
->custom_fields
);
959 cfmt
->custom_fields
= g_strdup (custom_fields
);
963 get_column_custom_occurrence(const int col
)
965 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
968 if (!clp
) /* Invalid column requested */
971 cfmt
= (fmt_data
*) clp
->data
;
973 return(cfmt
->custom_occurrence
);
977 set_column_custom_occurrence(const int col
, const int custom_occurrence
)
979 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
982 if (!clp
) /* Invalid column requested */
985 cfmt
= (fmt_data
*) clp
->data
;
987 cfmt
->custom_occurrence
= custom_occurrence
;
991 get_custom_field_tooltip (char *custom_field
, int occurrence
)
993 header_field_info
*hfi
= proto_registrar_get_byname(custom_field
);
995 /* Not a valid field */
997 if (dfilter_compile(custom_field
, &dfilter
, NULL
)) {
998 dfilter_free(dfilter
);
999 return ws_strdup_printf("Expression: %s", custom_field
);
1001 return ws_strdup_printf("Unknown Field: %s", custom_field
);
1004 if (hfi
->parent
== -1) {
1006 return ws_strdup_printf("%s (%s)", hfi
->name
, hfi
->abbrev
);
1009 if (occurrence
== 0) {
1010 /* All occurrences */
1011 return ws_strdup_printf("%s\n%s (%s)", proto_get_protocol_name(hfi
->parent
), hfi
->name
, hfi
->abbrev
);
1014 /* One given occurrence */
1015 return ws_strdup_printf("%s\n%s (%s#%d)", proto_get_protocol_name(hfi
->parent
), hfi
->name
, hfi
->abbrev
, occurrence
);
1019 get_column_tooltip(const int col
)
1021 GList
*clp
= g_list_nth(prefs
.col_list
, col
);
1025 GString
*column_tooltip
;
1028 if (!clp
) /* Invalid column requested */
1031 cfmt
= (fmt_data
*) clp
->data
;
1033 if (cfmt
->fmt
!= COL_CUSTOM
) {
1034 /* Use format description */
1035 return g_strdup(col_format_desc(cfmt
->fmt
));
1038 fields
= g_regex_split_simple(COL_CUSTOM_PRIME_REGEX
, cfmt
->custom_fields
,
1039 (GRegexCompileFlags
) (G_REGEX_RAW
),
1041 column_tooltip
= g_string_new("");
1043 for (i
= 0; i
< g_strv_length(fields
); i
++) {
1044 if (fields
[i
] && *fields
[i
]) {
1045 char *field_tooltip
= get_custom_field_tooltip(fields
[i
], cfmt
->custom_occurrence
);
1047 g_string_append(column_tooltip
, "\n\nOR\n\n");
1049 g_string_append(column_tooltip
, field_tooltip
);
1050 g_free (field_tooltip
);
1057 return g_string_free (column_tooltip
, FALSE
);
1061 get_column_text(column_info
*cinfo
, const int col
)
1064 ws_assert(col
< cinfo
->num_cols
);
1066 if ((get_column_display_format(col
) == COLUMN_DISPLAY_VALUES
) && cinfo
->col_expr
.col_expr_val
[col
]) {
1067 /* Use the unresolved value in col_expr_val */
1068 return cinfo
->col_expr
.col_expr_val
[col
];
1071 return cinfo
->columns
[col
].col_data
;
1075 col_finalize(column_info
*cinfo
)
1078 col_item_t
* col_item
;
1081 for (i
= 0; i
< cinfo
->num_cols
; i
++) {
1082 col_item
= &cinfo
->columns
[i
];
1084 if (col_item
->col_fmt
== COL_CUSTOM
) {
1085 if(!dfilter_compile(col_item
->col_custom_fields
, &col_item
->col_custom_dfilter
, NULL
)) {
1086 /* XXX: Should we issue a warning? */
1087 g_free(col_item
->col_custom_fields
);
1088 col_item
->col_custom_fields
= NULL
;
1089 col_item
->col_custom_occurrence
= 0;
1090 col_item
->col_custom_dfilter
= NULL
;
1092 if (col_item
->col_custom_fields
) {
1093 char **fields
= g_regex_split(cinfo
->prime_regex
, col_item
->col_custom_fields
,
1097 for (i_field
= 0; i_field
< g_strv_length(fields
); i_field
++) {
1098 if (fields
[i_field
] && *fields
[i_field
]) {
1099 if (dfilter_compile_full(fields
[i_field
], &dfilter
, NULL
, DF_EXPAND_MACROS
|DF_OPTIMIZE
|DF_RETURN_VALUES
, __func__
)) {
1100 col_custom_t
*custom_info
= g_new0(col_custom_t
, 1);
1101 custom_info
->dftext
= g_strdup(fields
[i_field
]);
1102 custom_info
->dfilter
= dfilter
;
1103 header_field_info
*hfinfo
= proto_registrar_get_byname(fields
[i_field
]);
1105 custom_info
->field_id
= hfinfo
->id
;
1107 col_item
->col_custom_fields_ids
= g_slist_append(col_item
->col_custom_fields_ids
, custom_info
);
1114 col_item
->col_custom_fields
= NULL
;
1115 col_item
->col_custom_occurrence
= 0;
1116 col_item
->col_custom_dfilter
= NULL
;
1119 col_item
->fmt_matx
= g_new0(bool, NUM_COL_FMTS
);
1120 get_column_format_matches(col_item
->fmt_matx
, col_item
->col_fmt
);
1121 col_item
->col_data
= NULL
;
1123 if (col_item
->col_fmt
== COL_INFO
) {
1124 col_item
->col_buf
= g_new(char, COL_MAX_INFO_LEN
);
1125 cinfo
->col_expr
.col_expr_val
[i
] = g_new(char, COL_MAX_INFO_LEN
);
1127 col_item
->col_buf
= g_new(char, COL_MAX_LEN
);
1128 cinfo
->col_expr
.col_expr_val
[i
] = g_new(char, COL_MAX_LEN
);
1131 cinfo
->col_expr
.col_expr
[i
] = "";
1134 cinfo
->col_expr
.col_expr
[i
] = NULL
;
1135 cinfo
->col_expr
.col_expr_val
[i
] = NULL
;
1137 for (i
= 0; i
< cinfo
->num_cols
; i
++) {
1140 for (j
= 0; j
< NUM_COL_FMTS
; j
++) {
1141 if (!cinfo
->columns
[i
].fmt_matx
[j
])
1144 if (cinfo
->col_first
[j
] == -1)
1145 cinfo
->col_first
[j
] = i
;
1147 cinfo
->col_last
[j
] = i
;
1153 build_column_format_array(column_info
*cinfo
, const int num_cols
, const bool reset_fences
)
1156 col_item_t
* col_item
;
1158 /* Build the column format array */
1159 col_setup(cinfo
, num_cols
);
1161 for (i
= 0; i
< cinfo
->num_cols
; i
++) {
1162 col_item
= &cinfo
->columns
[i
];
1163 col_item
->col_fmt
= get_column_format(i
);
1164 col_item
->col_title
= g_strdup(get_column_title(i
));
1165 if (col_item
->col_fmt
== COL_CUSTOM
) {
1166 col_item
->col_custom_fields
= g_strdup(get_column_custom_fields(i
));
1167 col_item
->col_custom_occurrence
= get_column_custom_occurrence(i
);
1169 col_item
->hf_id
= proto_registrar_get_id_byname(col_format_abbrev(col_item
->col_fmt
));
1172 col_item
->col_fence
= 0;
1175 col_finalize(cinfo
);
1179 column_deregister_fields(void)
1182 for (unsigned int i
= 0; i
< hf_cols_cleanup
; ++i
) {
1183 proto_deregister_field(proto_cols
, *(hf_cols
[i
].p_id
));
1184 g_free(hf_cols
[i
].p_id
);
1186 proto_add_deregistered_data(hf_cols
);
1188 hf_cols_cleanup
= 0;
1193 column_register_fields(void)
1197 GArray
*hf_col_array
;
1198 hf_register_info new_hf
;
1201 if (proto_cols
<= 0) {
1202 proto_cols
= proto_get_id_by_filter_name("_ws.col");
1204 if (proto_cols
<= 0) {
1205 proto_cols
= proto_register_protocol("Wireshark Columns", "Columns", "_ws.col");
1207 column_deregister_fields();
1208 if (prefs
.col_list
!= NULL
) {
1209 prefs
.num_cols
= g_list_length(prefs
.col_list
);
1210 hf_col_array
= g_array_new(false, true, sizeof(hf_register_info
));
1211 used_fmts
= g_new0(bool, NUM_COL_FMTS
);
1212 for (GList
*elem
= g_list_first(prefs
.col_list
); elem
!= NULL
; elem
= elem
->next
) {
1213 cfmt
= (fmt_data
*)elem
->data
;
1214 if (col_format_abbrev(cfmt
->fmt
) && !used_fmts
[cfmt
->fmt
]) {
1215 used_fmts
[cfmt
->fmt
] = true;
1216 hf_id
= g_new(int, 1);
1218 new_hf
.p_id
= hf_id
;
1219 new_hf
.hfinfo
.name
= g_strdup(col_format_desc(cfmt
->fmt
));
1220 new_hf
.hfinfo
.abbrev
= g_strdup(col_format_abbrev(cfmt
->fmt
));
1221 new_hf
.hfinfo
.type
= FT_STRING
;
1222 new_hf
.hfinfo
.display
= BASE_NONE
;
1223 new_hf
.hfinfo
.strings
= NULL
;
1224 new_hf
.hfinfo
.bitmask
= 0;
1225 new_hf
.hfinfo
.blurb
= NULL
;
1227 g_array_append_vals(hf_col_array
, &new_hf
, 1);
1231 hf_cols_cleanup
= hf_col_array
->len
;
1233 proto_register_field_array(proto_cols
, (hf_register_info
*)hf_col_array
->data
, hf_col_array
->len
);
1234 hf_cols
= (hf_register_info
*)g_array_free(hf_col_array
, false);
1239 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1244 * indent-tabs-mode: nil
1247 * vi: set shiftwidth=2 tabstop=8 expandtab:
1248 * :indentSize=2:tabSize=8:noTabs=true: