dcerpc SPLIT auth_session_key
[wireshark-sm.git] / epan / column.c
blobdf9f9d48bc499e548775302f4a33b4b9d1987dfb
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",
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] = {
566 "0000/000 00:00:00",
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] = {
595 "00:00:00",
596 "00:00:00.0",
597 "00:00:00.00",
598 "00:00:00.000",
599 "00:00:00.0000",
600 "00:00:00.00000",
601 "00:00:00.000000",
602 "00:00:00.0000000",
603 "00:00:00.00000000",
604 "00:00:00.000000000",
607 static const char *ts_abstime_utc[NUM_WS_TSPREC_VALS] = {
608 "00:00:00Z",
609 "00:00:00.0Z",
610 "00:00:00.00Z",
611 "00:00:00.000Z",
612 "00:00:00.0000Z",
613 "00:00:00.00000Z",
614 "00:00:00.000000Z",
615 "00:00:00.0000000Z",
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] = {
625 "0000",
626 "0000.0",
627 "0000.00",
628 "0000.000",
629 "0000.0000",
630 "0000.00000",
631 "0000.000000",
632 "0000.0000000",
633 "0000.00000000",
634 "0000.000000000",
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. */
655 static const char *
656 get_timestamp_column_longest_string(const int type, const int precision)
659 switch(type) {
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];
669 else
670 ws_assert_not_reached();
671 break;
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];
681 else
682 ws_assert_not_reached();
683 break;
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];
693 else
694 ws_assert_not_reached();
695 break;
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];
705 else
706 ws_assert_not_reached();
707 break;
708 case(TS_ABSOLUTE):
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];
717 else
718 ws_assert_not_reached();
719 break;
720 case(TS_UTC):
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];
729 else
730 ws_assert_not_reached();
731 break;
732 case(TS_RELATIVE): /* fallthrough */
733 case(TS_DELTA):
734 case(TS_DELTA_DIS):
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];
743 else
744 ws_assert_not_reached();
745 break;
746 case(TS_EPOCH):
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];
756 else
757 ws_assert_not_reached();
758 break;
759 case(TS_NOT_SET):
760 /* This should not happen. */
761 return "0000.000000";
762 default:
763 ws_assert_not_reached();
766 /* never reached, satisfy compiler */
767 return "";
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. */
782 const char *
783 get_column_longest_string(const int format)
785 switch (format) {
786 case COL_NUMBER:
787 case COL_NUMBER_DIS:
788 return "0000000";
789 case COL_CLS_TIME:
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());
799 case COL_ABS_TIME:
800 return get_timestamp_column_longest_string(TS_ABSOLUTE, timestamp_get_precision());
801 case COL_UTC_TIME:
802 return get_timestamp_column_longest_string(TS_UTC, timestamp_get_precision());
803 case COL_REL_TIME:
804 return get_timestamp_column_longest_string(TS_RELATIVE, timestamp_get_precision());
805 case COL_DELTA_TIME:
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());
809 case COL_DEF_SRC:
810 case COL_RES_SRC:
811 case COL_UNRES_SRC:
812 case COL_DEF_DL_SRC:
813 case COL_RES_DL_SRC:
814 case COL_UNRES_DL_SRC:
815 case COL_DEF_NET_SRC:
816 case COL_RES_NET_SRC:
817 case COL_UNRES_NET_SRC:
818 case COL_DEF_DST:
819 case COL_RES_DST:
820 case COL_UNRES_DST:
821 case COL_DEF_DL_DST:
822 case COL_RES_DL_DST:
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:
834 return "000000";
835 case COL_PROTOCOL:
836 return "Protocol"; /* not the longest, but the longest is too long */
837 case COL_PACKET_LENGTH:
838 return "00000";
839 case COL_CUMULATIVE_BYTES:
840 return "00000000";
841 case COL_IF_DIR:
842 return "i 00000000 I";
843 case COL_TX_RATE:
844 return "108.0";
845 case COL_RSSI:
846 return "100";
847 case COL_DSCP_VALUE:
848 return "AAA BBB"; /* not the longest, but the longest is too long */
849 case COL_EXPERT:
850 return "ERROR";
851 case COL_FREQ_CHAN:
852 return "9999 MHz [A 999]";
853 case COL_CUSTOM:
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. */
862 const char *
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);
868 else
869 return get_column_title(col);
872 /* Returns the longest possible width, in characters, for a particular
873 column type. */
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);
884 fmt_data *cfmt;
886 if (!clp) /* Invalid column requested */
887 return -1;
889 cfmt = (fmt_data *) clp->data;
891 return(cfmt->fmt);
894 void
895 set_column_format(const int col, const int fmt)
897 GList *clp = g_list_nth(prefs.col_list, col);
898 fmt_data *cfmt;
900 if (!clp) /* Invalid column requested */
901 return;
903 cfmt = (fmt_data *) clp->data;
905 cfmt->fmt = fmt;
909 get_column_format_from_str(const char *str)
911 int i;
913 for (i = 0; i < NUM_COL_FMTS; i++) {
914 if (strcmp(str, col_format_to_string(i)) == 0)
915 return i;
917 return -1; /* illegal */
920 char *
921 get_column_title(const int col)
923 GList *clp = g_list_nth(prefs.col_list, col);
924 fmt_data *cfmt;
926 if (!clp) /* Invalid column requested */
927 return NULL;
929 cfmt = (fmt_data *) clp->data;
931 return(cfmt->title);
934 void
935 set_column_title(const int col, const char *title)
937 GList *clp = g_list_nth(prefs.col_list, col);
938 fmt_data *cfmt;
940 if (!clp) /* Invalid column requested */
941 return;
943 cfmt = (fmt_data *) clp->data;
945 g_free (cfmt->title);
946 cfmt->title = g_strdup (title);
949 bool
950 get_column_visible(const int col)
952 GList *clp = g_list_nth(prefs.col_list, col);
953 fmt_data *cfmt;
955 if (!clp) /* Invalid column requested */
956 return true;
958 cfmt = (fmt_data *) clp->data;
960 return(cfmt->visible);
963 void
964 set_column_visible(const int col, bool visible)
966 GList *clp = g_list_nth(prefs.col_list, col);
967 fmt_data *cfmt;
969 if (!clp) /* Invalid column requested */
970 return;
972 cfmt = (fmt_data *) clp->data;
974 cfmt->visible = visible;
977 char
978 get_column_display_format(const int col)
980 GList *clp = g_list_nth(prefs.col_list, col);
981 fmt_data *cfmt;
983 if (!clp) /* Invalid column requested */
984 return true;
986 cfmt = (fmt_data *) clp->data;
988 return(cfmt->display);
991 void
992 set_column_display_format(const int col, char display)
994 GList *clp = g_list_nth(prefs.col_list, col);
995 fmt_data *cfmt;
997 if (!clp) /* Invalid column requested */
998 return;
1000 cfmt = (fmt_data *) clp->data;
1002 cfmt->display = display;
1005 const char *
1006 get_column_custom_fields(const int col)
1008 GList *clp = g_list_nth(prefs.col_list, col);
1009 fmt_data *cfmt;
1011 if (!clp) /* Invalid column requested */
1012 return NULL;
1014 cfmt = (fmt_data *) clp->data;
1016 return(cfmt->custom_fields);
1019 void
1020 set_column_custom_fields(const int col, const char *custom_fields)
1022 GList *clp = g_list_nth(prefs.col_list, col);
1023 fmt_data *cfmt;
1025 if (!clp) /* Invalid column requested */
1026 return;
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);
1038 fmt_data *cfmt;
1040 if (!clp) /* Invalid column requested */
1041 return 0;
1043 cfmt = (fmt_data *) clp->data;
1045 return(cfmt->custom_occurrence);
1048 void
1049 set_column_custom_occurrence(const int col, const int custom_occurrence)
1051 GList *clp = g_list_nth(prefs.col_list, col);
1052 fmt_data *cfmt;
1054 if (!clp) /* Invalid column requested */
1055 return;
1057 cfmt = (fmt_data *) clp->data;
1059 cfmt->custom_occurrence = custom_occurrence;
1062 static char *
1063 get_custom_field_tooltip (char *custom_field, int occurrence)
1065 header_field_info *hfi = proto_registrar_get_byname(custom_field);
1066 if (hfi == NULL) {
1067 /* Not a valid field */
1068 dfilter_t *dfilter;
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) {
1077 /* Protocol */
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);
1090 char *
1091 get_column_tooltip(const int col)
1093 GList *clp = g_list_nth(prefs.col_list, col);
1094 fmt_data *cfmt;
1095 char **fields;
1096 bool first = true;
1097 GString *column_tooltip;
1098 unsigned i;
1100 if (!clp) /* Invalid column requested */
1101 return NULL;
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);
1118 if (!first) {
1119 g_string_append(column_tooltip, "\n\nOR\n\n");
1121 g_string_append(column_tooltip, field_tooltip);
1122 g_free (field_tooltip);
1123 first = false;
1127 g_strfreev(fields);
1129 return g_string_free (column_tooltip, FALSE);
1132 const char*
1133 get_column_text(column_info *cinfo, const int col)
1135 ws_assert(cinfo);
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;
1146 void
1147 col_finalize(column_info *cinfo)
1149 int i;
1150 col_item_t* col_item;
1151 dfilter_t *dfilter;
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,
1167 unsigned i_field;
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]);
1176 if (hfinfo) {
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);
1183 g_strfreev(fields);
1185 } else {
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);
1198 } else {
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++) {
1210 int j;
1212 for (j = 0; j < NUM_COL_FMTS; j++) {
1213 if (!cinfo->columns[i].fmt_matx[j])
1214 continue;
1216 if (cinfo->col_first[j] == -1)
1217 cinfo->col_first[j] = i;
1219 cinfo->col_last[j] = i;
1224 void
1225 build_column_format_array(column_info *cinfo, const int num_cols, const bool reset_fences)
1227 int i;
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));
1243 if(reset_fences)
1244 col_item->col_fence = 0;
1247 col_finalize(cinfo);
1250 static void
1251 column_deregister_fields(void)
1253 if (hf_cols) {
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);
1259 hf_cols = NULL;
1260 hf_cols_cleanup = 0;
1264 void
1265 column_register_fields(void)
1268 int* hf_id;
1269 GArray *hf_col_array;
1270 hf_register_info new_hf;
1271 fmt_data *cfmt;
1272 bool *used_fmts;
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);
1289 *hf_id = -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;
1298 HFILL_INIT(new_hf);
1299 g_array_append_vals(hf_col_array, &new_hf, 1);
1302 g_free(used_fmts);
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
1313 * Local variables:
1314 * c-basic-offset: 2
1315 * tab-width: 8
1316 * indent-tabs-mode: nil
1317 * End:
1319 * vi: set shiftwidth=2 tabstop=8 expandtab:
1320 * :indentSize=2:tabSize=8:noTabs=true: