Add the relative time to the frame tree, at the request of Manfred Young.
[obnox/wireshark/wip.git] / column.c
1 /* column.c
2  * Routines for handling column preferences
3  *
4  * $Id: column.c,v 1.30 2000/11/17 21:00:35 gram Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
32 #endif
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <errno.h>
38
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42
43 #ifdef HAVE_SYS_STAT_H
44 #include <sys/stat.h>
45 #endif
46
47 #include "timestamp.h"
48 #include "prefs.h"
49 #include "column.h"
50 #include "packet.h"
51
52 /* Given a format number (as defined in packet.h), returns its equivalent
53    string */
54 gchar *
55 col_format_to_string(gint fmt) {
56   gchar *slist[] = { "%m", "%t", "%Rt", "%At", "%Yt", "%Tt", "%s", "%rs",
57                      "%us","%hs", "%rhs", "%uhs", "%ns", "%rns", "%uns", "%d",
58                      "%rd", "%ud", "%hd", "%rhd", "%uhd", "%nd", "%rnd",
59                      "%und", "%S", "%rS", "%uS", "%D", "%rD", "%uD", "%p",
60                      "%i", "%L" };
61   
62   if (fmt < 0 || fmt > NUM_COL_FMTS)
63     return NULL;
64   
65   return(slist[fmt]);
66 }
67
68 /* Given a format number (as defined in packet.h), returns its
69   description */
70 gchar *
71 col_format_desc(gint fmt) {
72   gchar *dlist[] = { "Number", "Time (command line specified)",
73                      "Relative time", "Absolute time",
74                      "Absolute date and time", "Delta time",
75                      "Source address", "Src addr (resolved)",
76                      "Src addr (unresolved)", "Hardware src addr",
77                      "Hw src addr (resolved)", "Hw src addr (unresolved)",
78                      "Network src addr", "Net src addr (resolved)",
79                      "Net src addr (unresolved)", "Destination address",
80                      "Dest addr (resolved)", "Dest addr (unresolved)",
81                      "Hardware dest addr", "Hw dest addr (resolved)",
82                      "Hw dest addr (unresolved)", "Network dest addr",
83                      "Net dest addr (resolved)", "Net dest addr (unresolved)",
84                      "Source port", "Src port (resolved)",
85                      "Src port (unresolved)", "Destination port",
86                      "Dest port (resolved)", "Dest port (unresolved)",
87                      "Protocol", "Information", "Packet length (bytes)" };
88   
89   if (fmt < 0 || fmt > NUM_COL_FMTS)
90     return NULL;
91   
92   return(dlist[fmt]);
93 }
94
95 /* Marks each array element true if it can be substituted for the given
96    column format */
97 void
98 get_column_format_matches(gboolean *fmt_list, gint format) {
99   int i;
100   
101   for (i = 0; i < NUM_COL_FMTS; i++) {
102     /* Get the obvious: the format itself */
103     if (i == format)
104       fmt_list[i] = TRUE;
105     /* Get any formats lower down on the chain */
106     switch (format) {
107       case COL_DEF_SRC:
108         fmt_list[COL_RES_DL_SRC] = TRUE;
109         fmt_list[COL_RES_NET_SRC] = TRUE;
110         break;
111       case COL_RES_SRC:
112         fmt_list[COL_RES_DL_SRC] = TRUE;
113         fmt_list[COL_RES_NET_SRC] = TRUE;
114         break;
115       case COL_UNRES_SRC:
116         fmt_list[COL_UNRES_DL_SRC] = TRUE;
117         fmt_list[COL_UNRES_NET_SRC] = TRUE;
118         break;
119       case COL_DEF_DST:
120         fmt_list[COL_RES_DL_DST] = TRUE;
121         fmt_list[COL_RES_NET_DST] = TRUE;
122         break;
123       case COL_RES_DST:
124         fmt_list[COL_RES_DL_DST] = TRUE;
125         fmt_list[COL_RES_NET_DST] = TRUE;
126         break;
127       case COL_UNRES_DST:
128         fmt_list[COL_UNRES_DL_DST] = TRUE;
129         fmt_list[COL_UNRES_NET_DST] = TRUE;
130         break;
131       case COL_DEF_DL_SRC:
132         fmt_list[COL_RES_DL_SRC] = TRUE;
133         break;
134       case COL_DEF_DL_DST:
135         fmt_list[COL_RES_DL_DST] = TRUE;
136         break;
137       case COL_DEF_NET_SRC:
138         fmt_list[COL_RES_NET_SRC] = TRUE;
139         break;
140       case COL_DEF_NET_DST:
141         fmt_list[COL_RES_NET_DST] = TRUE;
142         break;
143       case COL_DEF_SRC_PORT:
144         fmt_list[COL_RES_SRC_PORT] = TRUE;
145         break;
146       case COL_DEF_DST_PORT:
147         fmt_list[COL_RES_DST_PORT] = TRUE;
148         break;
149       default:
150         break;
151     }
152   }
153 }
154
155 /* Returns a string representing the longest possible value for a
156    particular column type.
157
158    Except for the COL...SRC and COL...DST columns, these are used
159    only when a capture is being displayed while it's taking place;
160    they are arguably somewhat fragile, as changes to the code that
161    generates them don't cause these widths to change, but that's
162    probably not too big a problem, given that the sizes are
163    recomputed based on the actual data in the columns when the capture
164    is done, and given that the width for COL...SRC and COL...DST columns
165    is somewhat arbitrary in any case.  We should probably clean
166    that up eventually, though. */
167 char *
168 get_column_longest_string(gint format)
169 {
170   switch (format) {
171     case COL_NUMBER:
172       return "0000000";
173       break;
174     case COL_CLS_TIME:
175       if (timestamp_type == ABSOLUTE)
176         return "00:00:00.000000";
177       else if (timestamp_type == ABSOLUTE_WITH_DATE)
178         return "0000-00-00 00:00:00.000000";
179       else
180         return "0000.000000";
181       break;
182     case COL_ABS_TIME:
183       return "00:00:00.000000";
184       break;
185     case COL_ABS_DATE_TIME:
186       return "0000-00-00 00:00:00.000000";
187       break;
188     case COL_REL_TIME:
189     case COL_DELTA_TIME:
190       return "0000.000000";
191       break;
192     case COL_DEF_SRC:
193     case COL_RES_SRC:
194     case COL_UNRES_SRC:
195     case COL_DEF_DL_SRC:
196     case COL_RES_DL_SRC:
197     case COL_UNRES_DL_SRC:
198     case COL_DEF_NET_SRC:
199     case COL_RES_NET_SRC:
200     case COL_UNRES_NET_SRC:
201     case COL_DEF_DST:
202     case COL_RES_DST:
203     case COL_UNRES_DST:
204     case COL_DEF_DL_DST:
205     case COL_RES_DL_DST:
206     case COL_UNRES_DL_DST:
207     case COL_DEF_NET_DST:
208     case COL_RES_NET_DST:
209     case COL_UNRES_NET_DST:
210       return "00000000.000000000000"; /* IPX-style */
211       break;
212     case COL_DEF_SRC_PORT:
213     case COL_RES_SRC_PORT:
214     case COL_UNRES_SRC_PORT:
215     case COL_DEF_DST_PORT:
216     case COL_RES_DST_PORT:
217     case COL_UNRES_DST_PORT:
218       return "000000";
219       break;
220     case COL_PROTOCOL:
221       return "NetBIOS"; /* not the longest, but the longest is too long */
222       break;
223     case COL_PACKET_LENGTH:
224       return "000000";
225       break;
226     default: /* COL_INFO */
227       return "Source port: kerberos-master  Destination port: kerberos-master";
228       break;
229   }
230 }
231
232 /* Returns the longest possible width, in characters, for a particular
233    column type. */
234 gint
235 get_column_char_width(gint format)
236 {
237   return strlen(get_column_longest_string(format));
238 }
239
240 enum col_resize_type
241 get_column_resize_type(gint format) {
242   switch (format) {
243     case COL_NUMBER:
244     case COL_CLS_TIME:
245     case COL_ABS_TIME:
246     case COL_ABS_DATE_TIME:
247     case COL_REL_TIME:
248     case COL_DELTA_TIME:
249     case COL_DEF_SRC_PORT:
250     case COL_RES_SRC_PORT:
251     case COL_UNRES_SRC_PORT:
252     case COL_DEF_DST_PORT:
253     case COL_RES_DST_PORT:
254     case COL_UNRES_DST_PORT:
255     case COL_PROTOCOL:
256     case COL_PACKET_LENGTH:
257       /* We don't want these to resize during a live capture, as that
258          gets in the way of trying to look at the data while it's being
259          captured. */
260       return (RESIZE_AUTO);
261       break;
262     case COL_DEF_SRC:
263     case COL_RES_SRC:
264     case COL_UNRES_SRC:
265     case COL_DEF_DL_SRC:
266     case COL_RES_DL_SRC:
267     case COL_UNRES_DL_SRC:
268     case COL_DEF_NET_SRC:
269     case COL_RES_NET_SRC:
270     case COL_UNRES_NET_SRC:
271     case COL_DEF_DST:
272     case COL_RES_DST:
273     case COL_UNRES_DST:
274     case COL_DEF_DL_DST:
275     case COL_RES_DL_DST:
276     case COL_UNRES_DL_DST:
277     case COL_DEF_NET_DST:
278     case COL_RES_NET_DST:
279     case COL_UNRES_NET_DST:
280       /* We don't want these to resize dynamically; if they get resolved
281          to names, those names could be very long, and auto-resizing
282          columns showing those names may leave too little room for
283          other columns such as the "Info" column. */
284       return (RESIZE_MANUAL);
285       break;
286     default: /* COL_INFO */
287       /* We want this to resize dynamically, even during a live capture,
288          because otherewise you won't be able to see all that's in
289          it. */
290       return (RESIZE_LIVE);
291       break;
292   }
293 }
294
295 #define TIME_DEF      0
296 #define TIME_REL      1
297 #define TIME_ABS      2
298 #define DATE_TIME_ABS 3
299 #define TIME_DEL      4
300
301 #define RES_DEF  0
302 #define RES_DO   1
303 #define RES_DONT 2
304
305 #define ADDR_DEF 0
306 #define ADDR_DL  3
307 #define ADDR_NET 6
308
309 gint
310 get_column_format(gint col) {
311   GList    *clp = g_list_nth(prefs.col_list, col);
312   fmt_data *cfmt;
313   
314   cfmt = (fmt_data *) clp->data;
315   
316   return(get_column_format_from_str(cfmt->fmt));
317 }
318
319 gint
320 get_column_format_from_str(gchar *str) {
321   gchar *cptr = str;
322   gint      res_off = RES_DEF, addr_off = ADDR_DEF, time_off = TIME_DEF;
323
324   /* To do: Make this parse %-formatted strings "for real" */
325   while (*cptr != '\0') {
326     switch (*cptr) {
327       case 't':  /* To do: fix for absolute and delta */
328         return COL_CLS_TIME + time_off;
329         break;
330       case 'm':
331         return COL_NUMBER;
332         break;
333       case 's':
334         return COL_DEF_SRC + res_off + addr_off;
335         break;
336       case 'd':
337         return COL_DEF_DST + res_off + addr_off;
338         break;
339       case 'S':
340         return COL_DEF_SRC_PORT + res_off;
341         break;
342       case 'D':
343         return COL_DEF_DST_PORT + res_off;
344         break;
345       case 'p':
346         return COL_PROTOCOL;
347         break;
348       case 'i':
349         return COL_INFO;
350         break;
351       case 'r':
352         res_off = RES_DO;
353         break;
354       case 'u':
355         res_off = RES_DONT;
356         break;
357       case 'h':
358         addr_off = ADDR_DL;
359         break;
360       case 'n':
361         addr_off = ADDR_NET;
362         break;
363       case 'R':
364         time_off = TIME_REL;
365         break;
366       case 'A':
367         time_off = TIME_ABS;
368         break;
369       case 'Y':
370         time_off = DATE_TIME_ABS;
371         break;
372       case 'T':
373         time_off = TIME_DEL;
374         break;
375       case 'L':
376         return COL_PACKET_LENGTH;
377         break;
378     }
379     cptr++;
380   }
381   return COL_NUMBER;
382 }
383
384 gchar *
385 get_column_title(gint col) {
386   GList    *clp = g_list_nth(prefs.col_list, col);
387   fmt_data *cfmt;
388   
389   cfmt = (fmt_data *) clp->data;
390
391   return(cfmt->title);  
392 }
393
394 #define MAX_FMT_PREF_LEN      1024
395 #define MAX_FMT_PREF_LINE_LEN   60
396 gchar *
397 col_format_to_pref_str() {
398   static gchar  pref_str[MAX_FMT_PREF_LEN] = "";
399   GList        *clp = g_list_first(prefs.col_list);
400   fmt_data     *cfmt;
401   int           cur_pos = 0, cur_len = 0, fmt_len;
402   
403   while (clp) {
404     cfmt = (fmt_data *) clp->data;
405     
406     fmt_len = strlen(cfmt->title) + 4;
407     if ((fmt_len + cur_len) < (MAX_FMT_PREF_LEN - 1)) {
408       if ((fmt_len + cur_pos) > MAX_FMT_PREF_LINE_LEN) {
409         cur_len--;
410         cur_pos = 0;
411                 pref_str[cur_len] = '\n'; cur_len++;
412         pref_str[cur_len] = '\t'; cur_len++;
413       }
414       sprintf(&pref_str[cur_len], "\"%s\", ", cfmt->title);
415       cur_len += fmt_len;
416       cur_pos += fmt_len;
417     }
418
419     fmt_len = strlen(cfmt->fmt) + 4;
420     if ((fmt_len + cur_len) < (MAX_FMT_PREF_LEN - 1)) {
421       if ((fmt_len + cur_pos) > MAX_FMT_PREF_LINE_LEN) {
422         cur_len--;
423         cur_pos = 0;
424         pref_str[cur_len] = '\n'; cur_len++;
425         pref_str[cur_len] = '\t'; cur_len++;
426       }
427       sprintf(&pref_str[cur_len], "\"%s\", ", cfmt->fmt);
428       cur_len += fmt_len;
429       cur_pos += fmt_len;
430     }
431     
432     clp = clp->next;
433   }
434   
435   if (cur_len > 2)
436     pref_str[cur_len - 2] = '\0';
437
438   return(pref_str);
439 }