1 /* column.c
2  * Routines for handling column preferences
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10 
11 #include "config.h"
12 
13 #include <stdio.h>
14 #include <string.h>
15 #include <errno.h>
16 
17 #ifdef HAVE_UNISTD_H
18 #include <unistd.h>
19 #endif
20 
21 #include <epan/timestamp.h>
22 #include <epan/prefs.h>
23 #include <epan/dfilter/dfilter.h>
24 #include <epan/column.h>
25 #include <epan/packet.h>
26 #include <wsutil/ws_assert.h>
27 
28 /* Given a format number (as defined in column-utils.h), returns its equivalent
29    string */
30 const gchar *
col_format_to_string(const gint fmt)31 col_format_to_string(const gint fmt) {
32   static const gchar *const slist[NUM_COL_FMTS] = {
33     "%q",                                       /* 0) COL_8021Q_VLAN_ID */
34     "%Yt",                                      /* 1) COL_ABS_YMD_TIME */
35     "%YDOYt",                                   /* 2) COL_ABS_YDOY_TIME */
36     "%At",                                      /* 3) COL_ABS_TIME */
37     "%V",                                       /* 4) COL_VSAN - !! DEPRECATED !!*/
38     "%B",                                       /* 5) COL_CUMULATIVE_BYTES */
39     "%Cus",                                     /* 6) COL_CUSTOM */
40     "%y",                                       /* 7) COL_DCE_CALL */
41     "%Tt",                                      /* 8) COL_DELTA_TIME */
42     "%Gt",                                      /* 9) COL_DELTA_TIME_DIS */
43     "%rd",                                      /* 10) COL_RES_DST */
44     "%ud",                                      /* 11) COL_UNRES_DST */
45     "%rD",                                      /* 12) COL_RES_DST_PORT */
46     "%uD",                                      /* 13) COL_UNRES_DST_PORT */
47     "%d",                                       /* 14) COL_DEF_DST */
48     "%D",                                       /* 15) COL_DEF_DST_PORT */
49     "%a",                                       /* 16) COL_EXPERT */
50     "%I",                                       /* 17) COL_IF_DIR */
51     "%F",                                       /* 18) COL_FREQ_CHAN */
52     "%hd",                                      /* 19) COL_DEF_DL_DST */
53     "%hs",                                      /* 20) COL_DEF_DL_SRC */
54     "%rhd",                                     /* 21) COL_RES_DL_DST */
55     "%uhd",                                     /* 22) COL_UNRES_DL_DST */
56     "%rhs",                                     /* 23) COL_RES_DL_SRC*/
57     "%uhs",                                     /* 24) COL_UNRES_DL_SRC */
58     "%e",                                       /* 25) COL_RSSI */
59     "%x",                                       /* 26) COL_TX_RATE */
60     "%f",                                       /* 27) COL_DSCP_VALUE */
61     "%i",                                       /* 28) COL_INFO */
62     "%rnd",                                     /* 29) COL_RES_NET_DST */
63     "%und",                                     /* 30) COL_UNRES_NET_DST */
64     "%rns",                                     /* 31) COL_RES_NET_SRC */
65     "%uns",                                     /* 32) COL_UNRES_NET_SRC */
66     "%nd",                                      /* 33) COL_DEF_NET_DST */
67     "%ns",                                      /* 34) COL_DEF_NET_SRC */
68     "%m",                                       /* 35) COL_NUMBER */
69     "%L",                                       /* 36) COL_PACKET_LENGTH */
70     "%p",                                       /* 37) COL_PROTOCOL */
71     "%Rt",                                      /* 38) COL_REL_TIME */
72     "%s",                                       /* 39) COL_DEF_SRC */
73     "%S",                                       /* 40) COL_DEF_SRC_PORT */
74     "%rs",                                      /* 41) COL_RES_SRC */
75     "%us",                                      /* 42) COL_UNRES_SRC */
76     "%rS",                                      /* 43) COL_RES_SRC_PORT */
77     "%uS",                                      /* 44) COL_UNRES_SRC_PORT */
78     "%E",                                       /* 45) COL_TEI */
79     "%Yut",                                     /* 46) COL_UTC_YMD_TIME */
80     "%YDOYut",                                  /* 47) COL_UTC_YDOY_TIME */
81     "%Aut",                                     /* 48) COL_UTC_TIME */
82     "%t"                                        /* 49) COL_CLS_TIME */
83   };
84 
85  /* The following formats have been used in deprecated columns.  Noted here
86   * so they aren't reused
87   *
88   *  "%U",                                             COL_COS_VALUE
89   *  "%c",                                             COL_CIRCUIT_ID
90   *  "%l",                                             COL_BSSGP_TLLI
91   *  "%H",                                             COL_HPUX_SUBSYS
92   *  "%P",                                             COL_HPUX_DEVID
93   *  "%C",                                             COL_FR_DLCI
94   *  "%rct",                                           COL_REL_CONV_TIME
95   *  "%dct",                                           COL_DELTA_CONV_TIME
96   *  "%XO",                                            COL_OXID
97   *  "%XR",                                            COL_RXID
98   *  "%Xd",                                            COL_SRCIDX
99   *  "%Xs",                                            COL_DSTIDX
100   *  "%z",                                             COL_DCE_CTX
101   */
102   if (fmt < 0 || fmt >= NUM_COL_FMTS)
103     return NULL;
104 
105   return(slist[fmt]);
106 }
107 
108 /* Given a format number (as defined in column-utils.h), returns its
109   description */
110 const gchar *
col_format_desc(const gint fmt_num)111 col_format_desc(const gint fmt_num) {
112 
113   /* This should be sorted alphabetically, e.g. `sort -t, -k2` */
114   /*
115    * This is currently used in the preferences UI, so out-of-numeric-order
116    * performance shouldn't be an issue.
117    */
118   static const value_string dlist_vals[] = {
119 
120     { COL_8021Q_VLAN_ID, "802.1Q VLAN id" },
121     { COL_ABS_YMD_TIME, "Absolute date, as YYYY-MM-DD, and time" },
122     { COL_ABS_YDOY_TIME, "Absolute date, as YYYY/DOY, and time" },
123     { COL_ABS_TIME, "Absolute time" },
124     { COL_VSAN, "Cisco VSAN" },
125     { COL_CUMULATIVE_BYTES, "Cumulative Bytes" },
126     { COL_CUSTOM, "Custom" },
127     { COL_DCE_CALL, "DCE/RPC call (cn_call_id / dg_seqnum)" },
128     { COL_DELTA_TIME_DIS, "Delta time displayed" },
129     { COL_DELTA_TIME, "Delta time" },
130     { COL_RES_DST, "Dest addr (resolved)" },
131     { COL_UNRES_DST, "Dest addr (unresolved)" },
132     { COL_RES_DST_PORT, "Dest port (resolved)" },
133     { COL_UNRES_DST_PORT, "Dest port (unresolved)" },
134     { COL_DEF_DST, "Destination address" },
135     { COL_DEF_DST_PORT, "Destination port" },
136     { COL_EXPERT, "Expert Info Severity" },
137     { COL_IF_DIR, "FW-1 monitor if/direction" },
138     { COL_FREQ_CHAN, "Frequency/Channel" },
139     { COL_DEF_DL_DST, "Hardware dest addr" },
140     { COL_DEF_DL_SRC, "Hardware src addr" },
141     { COL_RES_DL_DST, "Hw dest addr (resolved)" },
142     { COL_UNRES_DL_DST, "Hw dest addr (unresolved)" },
143     { COL_RES_DL_SRC, "Hw src addr (resolved)" },
144     { COL_UNRES_DL_SRC, "Hw src addr (unresolved)" },
145     { COL_RSSI, "IEEE 802.11 RSSI" },
146     { COL_TX_RATE, "IEEE 802.11 TX rate" },
147     { COL_DSCP_VALUE, "IP DSCP Value" },
148     { COL_INFO, "Information" },
149     { COL_RES_NET_DST, "Net dest addr (resolved)" },
150     { COL_UNRES_NET_DST, "Net dest addr (unresolved)" },
151     { COL_RES_NET_SRC, "Net src addr (resolved)" },
152     { COL_UNRES_NET_SRC, "Net src addr (unresolved)" },
153     { COL_DEF_NET_DST, "Network dest addr" },
154     { COL_DEF_NET_SRC, "Network src addr" },
155     { COL_NUMBER, "Number" },
156     { COL_PACKET_LENGTH, "Packet length (bytes)" },
157     { COL_PROTOCOL, "Protocol" },
158     { COL_REL_TIME, "Relative time" },
159     { COL_DEF_SRC, "Source address" },
160     { COL_DEF_SRC_PORT, "Source port" },
161     { COL_RES_SRC, "Src addr (resolved)" },
162     { COL_UNRES_SRC, "Src addr (unresolved)" },
163     { COL_RES_SRC_PORT, "Src port (resolved)" },
164     { COL_UNRES_SRC_PORT, "Src port (unresolved)" },
165     { COL_TEI, "TEI" },
166     { COL_CLS_TIME, "Time (format as specified)" },
167     { COL_UTC_YMD_TIME, "UTC date, as YYYY-MM-DD, and time" },
168     { COL_UTC_YDOY_TIME, "UTC date, as YYYY/DOY, and time" },
169     { COL_UTC_TIME, "UTC time" },
170 
171     { 0, NULL }
172   };
173 
174   const gchar *val_str = try_val_to_str(fmt_num, dlist_vals);
175   ws_assert(val_str != NULL);
176   return val_str;
177 }
178 
179 void
column_dump_column_formats(void)180 column_dump_column_formats(void)
181 {
182   gint fmt;
183 
184   for (fmt = 0; fmt < NUM_COL_FMTS; fmt++) {
185     printf("%s\t%s\n", col_format_to_string(fmt), col_format_desc(fmt));
186   }
187 
188   printf("\nFor example, to print Wireshark's default columns with tshark:\n\n"
189 #ifdef _WIN32
190   "tshark.exe -o \"gui.column.format:"
191     "\\\"No.\\\",\\\"%%m\\\","
192     "\\\"Time\\\",\\\"%%t\\\","
193     "\\\"Source\\\",\\\"%%s\\\","
194     "\\\"Destination\\\",\\\"%%d\\\","
195     "\\\"Protocol\\\",\\\"%%p\\\","
196     "\\\"Length\\\",\\\"%%L\\\","
197     "\\\"Info\\\",\\\"%%i\\\"\"\n");
198 #else
199   "tshark -o 'gui.column.format:"
200     "\"No.\",\"%%m\","
201     "\"Time\",\"%%t\","
202     "\"Source\",\"%%s\","
203     "\"Destination\",\"%%d\","
204     "\"Protocol\",\"%%p\","
205     "\"Length\",\"%%L\","
206     "\"Info\",\"%%i\"'\n");
207 #endif
208 }
209 
210 /* Marks each array element true if it can be substituted for the given
211    column format */
212 void
get_column_format_matches(gboolean * fmt_list,const gint format)213 get_column_format_matches(gboolean *fmt_list, const gint format) {
214 
215   /* Get the obvious: the format itself */
216   if ((format >= 0) && (format < NUM_COL_FMTS))
217     fmt_list[format] = TRUE;
218 
219   /* Get any formats lower down on the chain */
220   switch (format) {
221     case COL_DEF_SRC:
222       fmt_list[COL_RES_DL_SRC] = TRUE;
223       fmt_list[COL_RES_NET_SRC] = TRUE;
224       break;
225     case COL_RES_SRC:
226       fmt_list[COL_RES_DL_SRC] = TRUE;
227       fmt_list[COL_RES_NET_SRC] = TRUE;
228       break;
229     case COL_UNRES_SRC:
230       fmt_list[COL_UNRES_DL_SRC] = TRUE;
231       fmt_list[COL_UNRES_NET_SRC] = TRUE;
232       break;
233     case COL_DEF_DST:
234       fmt_list[COL_RES_DL_DST] = TRUE;
235       fmt_list[COL_RES_NET_DST] = TRUE;
236       break;
237     case COL_RES_DST:
238       fmt_list[COL_RES_DL_DST] = TRUE;
239       fmt_list[COL_RES_NET_DST] = TRUE;
240       break;
241     case COL_UNRES_DST:
242       fmt_list[COL_UNRES_DL_DST] = TRUE;
243       fmt_list[COL_UNRES_NET_DST] = TRUE;
244       break;
245     case COL_DEF_DL_SRC:
246       fmt_list[COL_RES_DL_SRC] = TRUE;
247       break;
248     case COL_DEF_DL_DST:
249       fmt_list[COL_RES_DL_DST] = TRUE;
250       break;
251     case COL_DEF_NET_SRC:
252       fmt_list[COL_RES_NET_SRC] = TRUE;
253       break;
254     case COL_DEF_NET_DST:
255       fmt_list[COL_RES_NET_DST] = TRUE;
256       break;
257     case COL_DEF_SRC_PORT:
258       fmt_list[COL_RES_SRC_PORT] = TRUE;
259       break;
260     case COL_DEF_DST_PORT:
261       fmt_list[COL_RES_DST_PORT] = TRUE;
262       break;
263     default:
264       break;
265   }
266 }
267 
268 /* Returns a string representing the longest possible value for
269    a timestamp column type. */
270 static const char *
get_timestamp_column_longest_string(const gint type,const gint precision)271 get_timestamp_column_longest_string(const gint type, const gint precision)
272 {
273 
274     switch(type) {
275     case(TS_ABSOLUTE_WITH_YMD):
276     case(TS_UTC_WITH_YMD):
277         switch(precision) {
278             case(TS_PREC_FIXED_SEC):
279                 return "0000-00-00 00:00:00";
280                 break;
281             case(TS_PREC_FIXED_DSEC):
282                 return "0000-00-00 00:00:00.0";
283                 break;
284             case(TS_PREC_FIXED_CSEC):
285                 return "0000-00-00 00:00:00.00";
286                 break;
287             case(TS_PREC_FIXED_MSEC):
288                 return "0000-00-00 00:00:00.000";
289                 break;
290             case(TS_PREC_FIXED_USEC):
291                 return "0000-00-00 00:00:00.000000";
292                 break;
293             case(TS_PREC_FIXED_NSEC):
294             case(TS_PREC_AUTO):    /* Leave enough room for the maximum */
295                 return "0000-00-00 00:00:00.000000000";
296                 break;
297             default:
298                 ws_assert_not_reached();
299         }
300             break;
301     case(TS_ABSOLUTE_WITH_YDOY):
302     case(TS_UTC_WITH_YDOY):
303         switch(precision) {
304             case(TS_PREC_FIXED_SEC):
305                 return "0000/000 00:00:00";
306                 break;
307             case(TS_PREC_FIXED_DSEC):
308                 return "0000/000 00:00:00.0";
309                 break;
310             case(TS_PREC_FIXED_CSEC):
311                 return "0000/000 00:00:00.00";
312                 break;
313             case(TS_PREC_FIXED_MSEC):
314                 return "0000/000 00:00:00.000";
315                 break;
316             case(TS_PREC_FIXED_USEC):
317                 return "0000/000 00:00:00.000000";
318                 break;
319             case(TS_PREC_FIXED_NSEC):
320             case(TS_PREC_AUTO):    /* Leave enough room for the maximum */
321                 return "0000/000 00:00:00.000000000";
322                 break;
323             default:
324                 ws_assert_not_reached();
325         }
326             break;
327     case(TS_ABSOLUTE):
328     case(TS_UTC):
329         switch(precision) {
330             case(TS_PREC_FIXED_SEC):
331                 return "00:00:00";
332                 break;
333             case(TS_PREC_FIXED_DSEC):
334                 return "00:00:00.0";
335                 break;
336             case(TS_PREC_FIXED_CSEC):
337                 return "00:00:00.00";
338                 break;
339             case(TS_PREC_FIXED_MSEC):
340                 return "00:00:00.000";
341                 break;
342             case(TS_PREC_FIXED_USEC):
343                 return "00:00:00.000000";
344                 break;
345             case(TS_PREC_FIXED_NSEC):
346             case(TS_PREC_AUTO):    /* Leave enough room for the maximum */
347                 return "00:00:00.000000000";
348                 break;
349             default:
350                 ws_assert_not_reached();
351         }
352         break;
353     case(TS_RELATIVE):  /* fallthrough */
354     case(TS_DELTA):
355     case(TS_DELTA_DIS):
356         switch(precision) {
357             case(TS_PREC_FIXED_SEC):
358                 return "0000";
359                 break;
360             case(TS_PREC_FIXED_DSEC):
361                 return "0000.0";
362                 break;
363             case(TS_PREC_FIXED_CSEC):
364                 return "0000.00";
365                 break;
366             case(TS_PREC_FIXED_MSEC):
367                 return "0000.000";
368                 break;
369             case(TS_PREC_FIXED_USEC):
370                 return "0000.000000";
371                 break;
372             case(TS_PREC_FIXED_NSEC):
373             case(TS_PREC_AUTO):    /* Leave enough room for the maximum */
374                 return "0000.000000000";
375                 break;
376             default:
377                 ws_assert_not_reached();
378         }
379         break;
380     case(TS_EPOCH):
381         /* This is enough to represent 2^63 (signed 64-bit integer) + fractions */
382         switch(precision) {
383             case(TS_PREC_FIXED_SEC):
384                 return "0000000000000000000";
385                 break;
386             case(TS_PREC_FIXED_DSEC):
387                 return "0000000000000000000.0";
388                 break;
389             case(TS_PREC_FIXED_CSEC):
390                 return "0000000000000000000.00";
391                 break;
392             case(TS_PREC_FIXED_MSEC):
393                 return "0000000000000000000.000";
394                 break;
395             case(TS_PREC_FIXED_USEC):
396                 return "0000000000000000000.000000";
397                 break;
398             case(TS_PREC_FIXED_NSEC):
399             case(TS_PREC_AUTO):    /* Leave enough room for the maximum */
400                 return "0000000000000000000.000000000";
401                 break;
402             default:
403                 ws_assert_not_reached();
404         }
405         break;
406     case(TS_NOT_SET):
407         return "0000.000000";
408         break;
409     default:
410         ws_assert_not_reached();
411     }
412 
413     /* never reached, satisfy compiler */
414     return "";
415 }
416 
417 /* Returns a string representing the longest possible value for a
418    particular column type.  See also get_column_width_string() above.
419 
420    Except for the COL...SRC and COL...DST columns, these are used
421    only when a capture is being displayed while it's taking place;
422    they are arguably somewhat fragile, as changes to the code that
423    generates them don't cause these widths to change, but that's
424    probably not too big a problem, given that the sizes are
425    recomputed based on the actual data in the columns when the capture
426    is done, and given that the width for COL...SRC and COL...DST columns
427    is somewhat arbitrary in any case.  We should probably clean
428    that up eventually, though. */
429 static const char *
get_column_longest_string(const gint format)430 get_column_longest_string(const gint format)
431 {
432   switch (format) {
433     case COL_NUMBER:
434       return "0000000";
435       break;
436     case COL_CLS_TIME:
437       return get_timestamp_column_longest_string(timestamp_get_type(), timestamp_get_precision());
438       break;
439     case COL_ABS_YMD_TIME:
440       return get_timestamp_column_longest_string(TS_ABSOLUTE_WITH_YMD, timestamp_get_precision());
441       break;
442     case COL_ABS_YDOY_TIME:
443       return get_timestamp_column_longest_string(TS_ABSOLUTE_WITH_YDOY, timestamp_get_precision());
444       break;
445     case COL_UTC_YMD_TIME:
446       return get_timestamp_column_longest_string(TS_UTC_WITH_YMD, timestamp_get_precision());
447       break;
448     case COL_UTC_YDOY_TIME:
449       return get_timestamp_column_longest_string(TS_UTC_WITH_YDOY, timestamp_get_precision());
450       break;
451     case COL_ABS_TIME:
452       return get_timestamp_column_longest_string(TS_ABSOLUTE, timestamp_get_precision());
453       break;
454     case COL_UTC_TIME:
455       return get_timestamp_column_longest_string(TS_UTC, timestamp_get_precision());
456       break;
457     case COL_REL_TIME:
458       return get_timestamp_column_longest_string(TS_RELATIVE, timestamp_get_precision());
459       break;
460     case COL_DELTA_TIME:
461       return get_timestamp_column_longest_string(TS_DELTA, timestamp_get_precision());
462       break;
463     case COL_DELTA_TIME_DIS:
464       return get_timestamp_column_longest_string(TS_DELTA_DIS, timestamp_get_precision());
465       break;
466     case COL_DEF_SRC:
467     case COL_RES_SRC:
468     case COL_UNRES_SRC:
469     case COL_DEF_DL_SRC:
470     case COL_RES_DL_SRC:
471     case COL_UNRES_DL_SRC:
472     case COL_DEF_NET_SRC:
473     case COL_RES_NET_SRC:
474     case COL_UNRES_NET_SRC:
475     case COL_DEF_DST:
476     case COL_RES_DST:
477     case COL_UNRES_DST:
478     case COL_DEF_DL_DST:
479     case COL_RES_DL_DST:
480     case COL_UNRES_DL_DST:
481     case COL_DEF_NET_DST:
482     case COL_RES_NET_DST:
483     case COL_UNRES_NET_DST:
484       return "00000000.000000000000"; /* IPX-style */
485       break;
486     case COL_DEF_SRC_PORT:
487     case COL_RES_SRC_PORT:
488     case COL_UNRES_SRC_PORT:
489     case COL_DEF_DST_PORT:
490     case COL_RES_DST_PORT:
491     case COL_UNRES_DST_PORT:
492       return "000000";
493       break;
494     case COL_PROTOCOL:
495       return "Protocol";    /* not the longest, but the longest is too long */
496       break;
497     case COL_PACKET_LENGTH:
498       return "00000";
499       break;
500     case COL_CUMULATIVE_BYTES:
501       return "00000000";
502       break;
503     case COL_IF_DIR:
504       return "i 00000000 I";
505       break;
506     case COL_VSAN:
507      return "000000";
508       break;
509     case COL_TX_RATE:
510       return "108.0";
511       break;
512     case COL_RSSI:
513       return "100";
514       break;
515     case COL_DCE_CALL:
516       return "0000";
517       break;
518     case COL_8021Q_VLAN_ID:
519       return "0000";
520       break;
521     case COL_DSCP_VALUE:
522       return "AAA BBB";    /* not the longest, but the longest is too long */
523       break;
524     case COL_TEI:
525       return "127";
526       break;
527     case COL_EXPERT:
528       return "ERROR";
529       break;
530     case COL_FREQ_CHAN:
531       return "9999 MHz [A 999]";
532       break;
533     case COL_CUSTOM:
534       return "0000000000";  /* not the longest, but the longest is too long */
535       break;
536     default: /* COL_INFO */
537       return "Source port: kerberos-master  Destination port: kerberos-master";
538       break;
539   }
540 }
541 
542 /* Returns the longer string of the column title or the hard-coded width of
543  * its contents for building the packet list layout. */
544 const gchar *
get_column_width_string(const gint format,const gint col)545 get_column_width_string(const gint format, const gint col)
546 {
547     if(strlen(get_column_longest_string(format)) >
548        strlen(get_column_title(col)))
549         return get_column_longest_string(format);
550     else
551         return get_column_title(col);
552 }
553 
554 /* Returns the longest possible width, in characters, for a particular
555    column type. */
556 gint
get_column_char_width(const gint format)557 get_column_char_width(const gint format)
558 {
559   return (gint)strlen(get_column_longest_string(format));
560 }
561 
562 gint
get_column_format(const gint col)563 get_column_format(const gint col)
564 {
565   GList    *clp = g_list_nth(prefs.col_list, col);
566   fmt_data *cfmt;
567 
568   if (!clp)  /* Invalid column requested */
569     return -1;
570 
571   cfmt = (fmt_data *) clp->data;
572 
573   return(cfmt->fmt);
574 }
575 
576 void
set_column_format(const gint col,const gint fmt)577 set_column_format(const gint col, const gint fmt)
578 {
579   GList    *clp = g_list_nth(prefs.col_list, col);
580   fmt_data *cfmt;
581 
582   if (!clp)  /* Invalid column requested */
583     return;
584 
585   cfmt = (fmt_data *) clp->data;
586 
587   cfmt->fmt = fmt;
588 }
589 
590 gint
get_column_format_from_str(const gchar * str)591 get_column_format_from_str(const gchar *str)
592 {
593   gint i;
594 
595   for (i = 0; i < NUM_COL_FMTS; i++) {
596     if (strcmp(str, col_format_to_string(i)) == 0)
597       return i;
598   }
599   return -1;    /* illegal */
600 }
601 
602 gchar *
get_column_title(const gint col)603 get_column_title(const gint col)
604 {
605   GList    *clp = g_list_nth(prefs.col_list, col);
606   fmt_data *cfmt;
607 
608   if (!clp)  /* Invalid column requested */
609     return NULL;
610 
611   cfmt = (fmt_data *) clp->data;
612 
613   return(cfmt->title);
614 }
615 
616 void
set_column_title(const gint col,const gchar * title)617 set_column_title(const gint col, const gchar *title)
618 {
619   GList    *clp = g_list_nth(prefs.col_list, col);
620   fmt_data *cfmt;
621 
622   if (!clp)  /* Invalid column requested */
623     return;
624 
625   cfmt = (fmt_data *) clp->data;
626 
627   g_free (cfmt->title);
628   cfmt->title = g_strdup (title);
629 }
630 
631 gboolean
get_column_visible(const gint col)632 get_column_visible(const gint col)
633 {
634   GList    *clp = g_list_nth(prefs.col_list, col);
635   fmt_data *cfmt;
636 
637   if (!clp)  /* Invalid column requested */
638     return TRUE;
639 
640   cfmt = (fmt_data *) clp->data;
641 
642   return(cfmt->visible);
643 }
644 
645 void
set_column_visible(const gint col,gboolean visible)646 set_column_visible(const gint col, gboolean visible)
647 {
648   GList    *clp = g_list_nth(prefs.col_list, col);
649   fmt_data *cfmt;
650 
651   if (!clp)  /* Invalid column requested */
652     return;
653 
654   cfmt = (fmt_data *) clp->data;
655 
656   cfmt->visible = visible;
657 }
658 
659 gboolean
get_column_resolved(const gint col)660 get_column_resolved(const gint col)
661 {
662   GList    *clp = g_list_nth(prefs.col_list, col);
663   fmt_data *cfmt;
664 
665   if (!clp)  /* Invalid column requested */
666     return TRUE;
667 
668   cfmt = (fmt_data *) clp->data;
669 
670   return(cfmt->resolved);
671 }
672 
673 void
set_column_resolved(const gint col,gboolean resolved)674 set_column_resolved(const gint col, gboolean resolved)
675 {
676   GList    *clp = g_list_nth(prefs.col_list, col);
677   fmt_data *cfmt;
678 
679   if (!clp)  /* Invalid column requested */
680     return;
681 
682   cfmt = (fmt_data *) clp->data;
683 
684   cfmt->resolved = resolved;
685 }
686 
687 const gchar *
get_column_custom_fields(const gint col)688 get_column_custom_fields(const gint col)
689 {
690   GList    *clp = g_list_nth(prefs.col_list, col);
691   fmt_data *cfmt;
692 
693   if (!clp)  /* Invalid column requested */
694     return NULL;
695 
696   cfmt = (fmt_data *) clp->data;
697 
698   return(cfmt->custom_fields);
699 }
700 
701 void
set_column_custom_fields(const gint col,const char * custom_fields)702 set_column_custom_fields(const gint col, const char *custom_fields)
703 {
704   GList    *clp = g_list_nth(prefs.col_list, col);
705   fmt_data *cfmt;
706 
707   if (!clp)  /* Invalid column requested */
708     return;
709 
710   cfmt = (fmt_data *) clp->data;
711 
712   g_free (cfmt->custom_fields);
713   cfmt->custom_fields = g_strdup (custom_fields);
714 }
715 
716 gint
get_column_custom_occurrence(const gint col)717 get_column_custom_occurrence(const gint col)
718 {
719   GList    *clp = g_list_nth(prefs.col_list, col);
720   fmt_data *cfmt;
721 
722   if (!clp)  /* Invalid column requested */
723     return 0;
724 
725   cfmt = (fmt_data *) clp->data;
726 
727   return(cfmt->custom_occurrence);
728 }
729 
730 void
set_column_custom_occurrence(const gint col,const gint custom_occurrence)731 set_column_custom_occurrence(const gint col, const gint custom_occurrence)
732 {
733   GList    *clp = g_list_nth(prefs.col_list, col);
734   fmt_data *cfmt;
735 
736   if (!clp)  /* Invalid column requested */
737     return;
738 
739   cfmt = (fmt_data *) clp->data;
740 
741   cfmt->custom_occurrence = custom_occurrence;
742 }
743 
744 static gchar *
get_custom_field_tooltip(gchar * custom_field,gint occurrence)745 get_custom_field_tooltip (gchar *custom_field, gint occurrence)
746 {
747     header_field_info *hfi = proto_registrar_get_byname(custom_field);
748     if (hfi == NULL) {
749         /* Not a valid field */
750         return g_strdup_printf("Unknown Field: %s", custom_field);
751     }
752 
753     if (hfi->parent == -1) {
754         /* Protocol */
755         return g_strdup_printf("%s (%s)", hfi->name, hfi->abbrev);
756     }
757 
758     if (occurrence == 0) {
759         /* All occurrences */
760         return g_strdup_printf("%s\n%s (%s)", proto_get_protocol_name(hfi->parent), hfi->name, hfi->abbrev);
761     }
762 
763     /* One given occurrence */
764     return g_strdup_printf("%s\n%s (%s#%d)", proto_get_protocol_name(hfi->parent), hfi->name, hfi->abbrev, occurrence);
765 }
766 
767 gchar *
get_column_tooltip(const gint col)768 get_column_tooltip(const gint col)
769 {
770     GList    *clp = g_list_nth(prefs.col_list, col);
771     fmt_data *cfmt;
772     gchar   **fields;
773     gboolean  first = TRUE;
774     GString  *column_tooltip;
775     guint     i;
776 
777     if (!clp)  /* Invalid column requested */
778         return NULL;
779 
780     cfmt = (fmt_data *) clp->data;
781 
782     if (cfmt->fmt != COL_CUSTOM) {
783         /* Use format description */
784         return g_strdup(col_format_desc(cfmt->fmt));
785     }
786 
787     fields = g_regex_split_simple(COL_CUSTOM_PRIME_REGEX, cfmt->custom_fields,
788                                   (GRegexCompileFlags) (G_REGEX_ANCHORED | G_REGEX_RAW),
789                                   G_REGEX_MATCH_ANCHORED);
790     column_tooltip = g_string_new("");
791 
792     for (i = 0; i < g_strv_length(fields); i++) {
793         if (fields[i] && *fields[i]) {
794             gchar *field_tooltip = get_custom_field_tooltip(fields[i], cfmt->custom_occurrence);
795             if (!first) {
796                 g_string_append(column_tooltip, "\n\nOR\n\n");
797             }
798             g_string_append(column_tooltip, field_tooltip);
799             g_free (field_tooltip);
800             first = FALSE;
801         }
802     }
803 
804     g_strfreev(fields);
805 
806     return g_string_free (column_tooltip, FALSE);
807 }
808 
809 void
col_finalize(column_info * cinfo)810 col_finalize(column_info *cinfo)
811 {
812   int i;
813   col_item_t* col_item;
814 
815   for (i = 0; i < cinfo->num_cols; i++) {
816     col_item = &cinfo->columns[i];
817 
818     if (col_item->col_fmt == COL_CUSTOM) {
819       if(!dfilter_compile(col_item->col_custom_fields, &col_item->col_custom_dfilter, NULL)) {
820         /* XXX: Should we issue a warning? */
821         g_free(col_item->col_custom_fields);
822         col_item->col_custom_fields = NULL;
823         col_item->col_custom_occurrence = 0;
824         col_item->col_custom_dfilter = NULL;
825       }
826       if (col_item->col_custom_fields) {
827         gchar **fields = g_regex_split(cinfo->prime_regex, col_item->col_custom_fields,
828                                        G_REGEX_MATCH_ANCHORED);
829         guint i_field;
830 
831         for (i_field = 0; i_field < g_strv_length(fields); i_field++) {
832           if (fields[i_field] && *fields[i_field]) {
833             header_field_info *hfinfo = proto_registrar_get_byname(fields[i_field]);
834             if (hfinfo) {
835               int *idx = g_new(int, 1);
836               *idx = hfinfo->id;
837               col_item->col_custom_fields_ids = g_slist_append(col_item->col_custom_fields_ids, idx);
838             }
839           }
840         }
841         g_strfreev(fields);
842       }
843     } else {
844       col_item->col_custom_fields = NULL;
845       col_item->col_custom_occurrence = 0;
846       col_item->col_custom_dfilter = NULL;
847     }
848 
849     col_item->fmt_matx = g_new0(gboolean, NUM_COL_FMTS);
850     get_column_format_matches(col_item->fmt_matx, col_item->col_fmt);
851     col_item->col_data = NULL;
852 
853     if (col_item->col_fmt == COL_INFO)
854       col_item->col_buf = g_new(gchar, COL_MAX_INFO_LEN);
855     else
856       col_item->col_buf = g_new(gchar, COL_MAX_LEN);
857 
858     cinfo->col_expr.col_expr[i] = "";
859     cinfo->col_expr.col_expr_val[i] = g_new(gchar, COL_MAX_LEN);
860   }
861 
862   cinfo->col_expr.col_expr[i] = NULL;
863   cinfo->col_expr.col_expr_val[i] = NULL;
864 
865   for (i = 0; i < cinfo->num_cols; i++) {
866     int j;
867 
868     for (j = 0; j < NUM_COL_FMTS; j++) {
869       if (!cinfo->columns[i].fmt_matx[j])
870           continue;
871 
872       if (cinfo->col_first[j] == -1)
873         cinfo->col_first[j] = i;
874 
875       cinfo->col_last[j] = i;
876     }
877   }
878 }
879 
880 void
build_column_format_array(column_info * cinfo,const gint num_cols,const gboolean reset_fences)881 build_column_format_array(column_info *cinfo, const gint num_cols, const gboolean reset_fences)
882 {
883   int i;
884   col_item_t* col_item;
885 
886   /* Build the column format array */
887   col_setup(cinfo, num_cols);
888 
889   for (i = 0; i < cinfo->num_cols; i++) {
890     col_item = &cinfo->columns[i];
891     col_item->col_fmt = get_column_format(i);
892     col_item->col_title = g_strdup(get_column_title(i));
893     if (col_item->col_fmt == COL_CUSTOM) {
894       col_item->col_custom_fields = g_strdup(get_column_custom_fields(i));
895       col_item->col_custom_occurrence = get_column_custom_occurrence(i);
896     }
897 
898     if(reset_fences)
899       col_item->col_fence = 0;
900   }
901 
902   col_finalize(cinfo);
903 }
904 
905 /*
906  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
907  *
908  * Local variables:
909  * c-basic-offset: 2
910  * tab-width: 8
911  * indent-tabs-mode: nil
912  * End:
913  *
914  * vi: set shiftwidth=2 tabstop=8 expandtab:
915  * :indentSize=2:tabSize=8:noTabs=true:
916  */
917 
918