drsuapi_SupportedExtensionsExt
[wireshark-sm.git] / epan / column.c
blob285ddbca885309f41899249edaf34b049a3695b1
1 /* column.c
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
9 */
11 #include "config.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
17 #ifdef HAVE_UNISTD_H
18 #include <unistd.h>
19 #endif
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
34 string */
35 const char *
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)
91 return NULL;
93 return(slist[fmt]);
96 /* Given a format number (as defined in column-utils.h), returns its
97 description */
98 const char *
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" },
156 { 0, NULL }
159 const char *val_str = try_val_to_str(fmt_num, dlist_vals);
160 ws_assert(val_str != NULL);
161 return val_str;
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. */
167 const char *
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" },
175 #if 0
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" },
186 #endif
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" },
228 { 0, NULL }
231 const char *val_str = try_val_to_str(fmt_num, alist_vals);
232 //ws_assert(val_str != NULL);
233 return val_str;
235 /* Array of columns that have been migrated to custom columns */
236 struct deprecated_columns {
237 const char *col_fmt;
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" },
266 const char*
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" },
277 { 0, NULL },
280 int idx;
282 idx = str_to_val_idx(field, migrated_fields);
284 if (idx >= 0) {
285 return col_format_abbrev(migrated_fields[idx].value);
288 return NULL;
292 * Parse a column format, filling in the relevant fields of a fmt_data.
294 bool
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;
300 char *p;
301 int col_fmt;
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) {
311 /* Yes. */
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]);
322 *p = '\0';
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. */
337 g_free(fmt_copy);
338 g_ptr_array_unref(cust_format_info);
339 return false;
342 if (cust_format_info->len > 2) {
343 p = cust_format_info->pdata[2];
344 col_display = p[0];
346 g_free(fmt_copy);
347 g_ptr_array_unref(cust_format_info);
348 } else {
349 col_fmt = get_column_format_from_str(fmt);
350 if (col_fmt == -1)
351 return false;
354 cfmt->fmt = col_fmt;
355 cfmt->custom_fields = col_custom_fields;
356 cfmt->custom_occurrence = (int)col_custom_occurrence;
357 cfmt->display = col_display;
358 return true;
361 char *
362 column_fmt_data_to_str(const fmt_data *cfmt)
364 if (!cfmt) {
365 return NULL;
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),
371 cfmt->custom_fields,
372 cfmt->custom_occurrence,
373 cfmt->display);
376 return ws_strdup(col_format_to_string(cfmt->fmt));
379 void
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);
386 ++haystack_idx) {
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);
392 g_free(*fmt);
393 *fmt = cust_col;
398 void
399 column_dump_column_formats(void)
401 int fmt;
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"
418 #ifdef _WIN32
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");
427 #else
428 "tshark -o 'gui.column.format:"
429 "\"No.\",\"%%m\","
430 "\"Time\",\"%%t\","
431 "\"Source\",\"%%s\","
432 "\"Destination\",\"%%d\","
433 "\"Protocol\",\"%%p\","
434 "\"Length\",\"%%L\","
435 "\"Info\",\"%%i\"'\n");
436 #endif
438 if (prefs.col_list) {
439 fmt_data *cfmt;
440 char *prefs_fmt;
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, ',');
448 #ifdef _WIN32
449 g_string_append_printf(current_cols, "\\\"%s\\\",\\\"%s\\\"", cfmt->title, prefs_fmt);
450 #else
451 g_string_append_printf(current_cols, "\"%s\",\"%s\"", cfmt->title, prefs_fmt);
452 #endif
453 g_free(prefs_fmt);
455 printf("\nand to print the current configuration profile's columns with tshark:\n\n"
456 #ifdef _WIN32
457 "tshark -o \"gui.column.format:%s\"\n", current_cols->str);
458 #else
459 "tshark -o 'gui.column.format:%s'\n", current_cols->str);
460 #endif
461 g_string_free(current_cols, TRUE);
465 /* Marks each array element true if it can be substituted for the given
466 column format */
467 void
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 */
475 switch (format) {
476 case COL_DEF_SRC:
477 fmt_list[COL_RES_DL_SRC] = true;
478 fmt_list[COL_RES_NET_SRC] = true;
479 break;
480 case COL_RES_SRC:
481 fmt_list[COL_RES_DL_SRC] = true;
482 fmt_list[COL_RES_NET_SRC] = true;
483 break;
484 case COL_UNRES_SRC:
485 fmt_list[COL_UNRES_DL_SRC] = true;
486 fmt_list[COL_UNRES_NET_SRC] = true;
487 break;
488 case COL_DEF_DST:
489 fmt_list[COL_RES_DL_DST] = true;
490 fmt_list[COL_RES_NET_DST] = true;
491 break;
492 case COL_RES_DST:
493 fmt_list[COL_RES_DL_DST] = true;
494 fmt_list[COL_RES_NET_DST] = true;
495 break;
496 case COL_UNRES_DST:
497 fmt_list[COL_UNRES_DL_DST] = true;
498 fmt_list[COL_UNRES_NET_DST] = true;
499 break;
500 case COL_DEF_DL_SRC:
501 fmt_list[COL_RES_DL_SRC] = true;
502 break;
503 case COL_DEF_DL_DST:
504 fmt_list[COL_RES_DL_DST] = true;
505 break;
506 case COL_DEF_NET_SRC:
507 fmt_list[COL_RES_NET_SRC] = true;
508 break;
509 case COL_DEF_NET_DST:
510 fmt_list[COL_RES_NET_DST] = true;
511 break;
512 case COL_DEF_SRC_PORT:
513 fmt_list[COL_RES_SRC_PORT] = true;
514 break;
515 case COL_DEF_DST_PORT:
516 fmt_list[COL_RES_DST_PORT] = true;
517 break;
518 default:
519 break;
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] = {
553 "0000/000 00:00:00",
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] = {
569 "00:00:00",
570 "00:00:00.0",
571 "00:00:00.00",
572 "00:00:00.000",
573 "00:00:00.0000",
574 "00:00:00.00000",
575 "00:00:00.000000",
576 "00:00:00.0000000",
577 "00:00:00.00000000",
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] = {
586 "0000",
587 "0000.0",
588 "0000.00",
589 "0000.000",
590 "0000.0000",
591 "0000.00000",
592 "0000.000000",
593 "0000.0000000",
594 "0000.00000000",
595 "0000.000000000",
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. */
616 static const char *
617 get_timestamp_column_longest_string(const int type, const int precision)
620 switch(type) {
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];
631 else
632 ws_assert_not_reached();
633 break;
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];
644 else
645 ws_assert_not_reached();
646 break;
647 case(TS_ABSOLUTE):
648 case(TS_UTC):
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];
657 else
658 ws_assert_not_reached();
659 break;
660 case(TS_RELATIVE): /* fallthrough */
661 case(TS_DELTA):
662 case(TS_DELTA_DIS):
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];
671 else
672 ws_assert_not_reached();
673 break;
674 case(TS_EPOCH):
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];
684 else
685 ws_assert_not_reached();
686 break;
687 case(TS_NOT_SET):
688 /* This should not happen. */
689 return "0000.000000";
690 default:
691 ws_assert_not_reached();
694 /* never reached, satisfy compiler */
695 return "";
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. */
710 const char *
711 get_column_longest_string(const int format)
713 switch (format) {
714 case COL_NUMBER:
715 case COL_NUMBER_DIS:
716 return "0000000";
717 case COL_CLS_TIME:
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());
727 case COL_ABS_TIME:
728 return get_timestamp_column_longest_string(TS_ABSOLUTE, timestamp_get_precision());
729 case COL_UTC_TIME:
730 return get_timestamp_column_longest_string(TS_UTC, timestamp_get_precision());
731 case COL_REL_TIME:
732 return get_timestamp_column_longest_string(TS_RELATIVE, timestamp_get_precision());
733 case COL_DELTA_TIME:
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());
737 case COL_DEF_SRC:
738 case COL_RES_SRC:
739 case COL_UNRES_SRC:
740 case COL_DEF_DL_SRC:
741 case COL_RES_DL_SRC:
742 case COL_UNRES_DL_SRC:
743 case COL_DEF_NET_SRC:
744 case COL_RES_NET_SRC:
745 case COL_UNRES_NET_SRC:
746 case COL_DEF_DST:
747 case COL_RES_DST:
748 case COL_UNRES_DST:
749 case COL_DEF_DL_DST:
750 case COL_RES_DL_DST:
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:
762 return "000000";
763 case COL_PROTOCOL:
764 return "Protocol"; /* not the longest, but the longest is too long */
765 case COL_PACKET_LENGTH:
766 return "00000";
767 case COL_CUMULATIVE_BYTES:
768 return "00000000";
769 case COL_IF_DIR:
770 return "i 00000000 I";
771 case COL_TX_RATE:
772 return "108.0";
773 case COL_RSSI:
774 return "100";
775 case COL_DSCP_VALUE:
776 return "AAA BBB"; /* not the longest, but the longest is too long */
777 case COL_EXPERT:
778 return "ERROR";
779 case COL_FREQ_CHAN:
780 return "9999 MHz [A 999]";
781 case COL_CUSTOM:
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. */
790 const char *
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);
796 else
797 return get_column_title(col);
800 /* Returns the longest possible width, in characters, for a particular
801 column type. */
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);
812 fmt_data *cfmt;
814 if (!clp) /* Invalid column requested */
815 return -1;
817 cfmt = (fmt_data *) clp->data;
819 return(cfmt->fmt);
822 void
823 set_column_format(const int col, const int fmt)
825 GList *clp = g_list_nth(prefs.col_list, col);
826 fmt_data *cfmt;
828 if (!clp) /* Invalid column requested */
829 return;
831 cfmt = (fmt_data *) clp->data;
833 cfmt->fmt = fmt;
837 get_column_format_from_str(const char *str)
839 int i;
841 for (i = 0; i < NUM_COL_FMTS; i++) {
842 if (strcmp(str, col_format_to_string(i)) == 0)
843 return i;
845 return -1; /* illegal */
848 char *
849 get_column_title(const int col)
851 GList *clp = g_list_nth(prefs.col_list, col);
852 fmt_data *cfmt;
854 if (!clp) /* Invalid column requested */
855 return NULL;
857 cfmt = (fmt_data *) clp->data;
859 return(cfmt->title);
862 void
863 set_column_title(const int col, const char *title)
865 GList *clp = g_list_nth(prefs.col_list, col);
866 fmt_data *cfmt;
868 if (!clp) /* Invalid column requested */
869 return;
871 cfmt = (fmt_data *) clp->data;
873 g_free (cfmt->title);
874 cfmt->title = g_strdup (title);
877 bool
878 get_column_visible(const int col)
880 GList *clp = g_list_nth(prefs.col_list, col);
881 fmt_data *cfmt;
883 if (!clp) /* Invalid column requested */
884 return true;
886 cfmt = (fmt_data *) clp->data;
888 return(cfmt->visible);
891 void
892 set_column_visible(const int col, bool visible)
894 GList *clp = g_list_nth(prefs.col_list, col);
895 fmt_data *cfmt;
897 if (!clp) /* Invalid column requested */
898 return;
900 cfmt = (fmt_data *) clp->data;
902 cfmt->visible = visible;
905 char
906 get_column_display_format(const int col)
908 GList *clp = g_list_nth(prefs.col_list, col);
909 fmt_data *cfmt;
911 if (!clp) /* Invalid column requested */
912 return true;
914 cfmt = (fmt_data *) clp->data;
916 return(cfmt->display);
919 void
920 set_column_display_format(const int col, char display)
922 GList *clp = g_list_nth(prefs.col_list, col);
923 fmt_data *cfmt;
925 if (!clp) /* Invalid column requested */
926 return;
928 cfmt = (fmt_data *) clp->data;
930 cfmt->display = display;
933 const char *
934 get_column_custom_fields(const int col)
936 GList *clp = g_list_nth(prefs.col_list, col);
937 fmt_data *cfmt;
939 if (!clp) /* Invalid column requested */
940 return NULL;
942 cfmt = (fmt_data *) clp->data;
944 return(cfmt->custom_fields);
947 void
948 set_column_custom_fields(const int col, const char *custom_fields)
950 GList *clp = g_list_nth(prefs.col_list, col);
951 fmt_data *cfmt;
953 if (!clp) /* Invalid column requested */
954 return;
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);
966 fmt_data *cfmt;
968 if (!clp) /* Invalid column requested */
969 return 0;
971 cfmt = (fmt_data *) clp->data;
973 return(cfmt->custom_occurrence);
976 void
977 set_column_custom_occurrence(const int col, const int custom_occurrence)
979 GList *clp = g_list_nth(prefs.col_list, col);
980 fmt_data *cfmt;
982 if (!clp) /* Invalid column requested */
983 return;
985 cfmt = (fmt_data *) clp->data;
987 cfmt->custom_occurrence = custom_occurrence;
990 static char *
991 get_custom_field_tooltip (char *custom_field, int occurrence)
993 header_field_info *hfi = proto_registrar_get_byname(custom_field);
994 if (hfi == NULL) {
995 /* Not a valid field */
996 dfilter_t *dfilter;
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) {
1005 /* Protocol */
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);
1018 char *
1019 get_column_tooltip(const int col)
1021 GList *clp = g_list_nth(prefs.col_list, col);
1022 fmt_data *cfmt;
1023 char **fields;
1024 bool first = true;
1025 GString *column_tooltip;
1026 unsigned i;
1028 if (!clp) /* Invalid column requested */
1029 return NULL;
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);
1046 if (!first) {
1047 g_string_append(column_tooltip, "\n\nOR\n\n");
1049 g_string_append(column_tooltip, field_tooltip);
1050 g_free (field_tooltip);
1051 first = false;
1055 g_strfreev(fields);
1057 return g_string_free (column_tooltip, FALSE);
1060 const char*
1061 get_column_text(column_info *cinfo, const int col)
1063 ws_assert(cinfo);
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;
1074 void
1075 col_finalize(column_info *cinfo)
1077 int i;
1078 col_item_t* col_item;
1079 dfilter_t *dfilter;
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,
1095 unsigned i_field;
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]);
1104 if (hfinfo) {
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);
1111 g_strfreev(fields);
1113 } else {
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);
1126 } else {
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++) {
1138 int j;
1140 for (j = 0; j < NUM_COL_FMTS; j++) {
1141 if (!cinfo->columns[i].fmt_matx[j])
1142 continue;
1144 if (cinfo->col_first[j] == -1)
1145 cinfo->col_first[j] = i;
1147 cinfo->col_last[j] = i;
1152 void
1153 build_column_format_array(column_info *cinfo, const int num_cols, const bool reset_fences)
1155 int i;
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));
1171 if(reset_fences)
1172 col_item->col_fence = 0;
1175 col_finalize(cinfo);
1178 static void
1179 column_deregister_fields(void)
1181 if (hf_cols) {
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);
1187 hf_cols = NULL;
1188 hf_cols_cleanup = 0;
1192 void
1193 column_register_fields(void)
1196 int* hf_id;
1197 GArray *hf_col_array;
1198 hf_register_info new_hf;
1199 fmt_data *cfmt;
1200 bool *used_fmts;
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);
1217 *hf_id = -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;
1226 HFILL_INIT(new_hf);
1227 g_array_append_vals(hf_col_array, &new_hf, 1);
1230 g_free(used_fmts);
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
1241 * Local variables:
1242 * c-basic-offset: 2
1243 * tab-width: 8
1244 * indent-tabs-mode: nil
1245 * End:
1247 * vi: set shiftwidth=2 tabstop=8 expandtab:
1248 * :indentSize=2:tabSize=8:noTabs=true: