Store pointers to previously displayed and captured packet, not nstime_t deltas.
[metze/wireshark/wip.git] / epan / column-utils.c
index e4dd9b15414c8fbfd6d5b71fed0f3f45fa0f5f10..7737ec99dc13fc8900604768a994e62c409b57f8 100644 (file)
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
+#include "config.h"
 
 #include <string.h>
 #include <time.h>
 #include <epan/strutil.h>
 #include <epan/epan.h>
 
-static column_info *ci;
-
 /* Allocate all the data structures for constructing column data, given
    the number of columns. */
 void
-col_setup(column_info *cinfo, gint num_cols)
+col_setup(column_info *cinfo, const gint num_cols)
 {
   int i;
 
-  cinfo->num_cols      = num_cols;
-  cinfo->col_fmt       = g_new(gint, num_cols);
-  cinfo->fmt_matx      = g_new(gboolean*, num_cols);
-  cinfo->col_first     = g_new(int, NUM_COL_FMTS);
-  cinfo->col_last      = g_new(int, NUM_COL_FMTS);
-  cinfo->col_title     = g_new(gchar*, num_cols);
+  cinfo->num_cols   = num_cols;
+  cinfo->col_fmt    = g_new(gint, num_cols);
+  cinfo->fmt_matx   = g_new(gboolean*, num_cols);
+  cinfo->col_first  = g_new(int, NUM_COL_FMTS);
+  cinfo->col_last   = g_new(int, NUM_COL_FMTS);
+  cinfo->col_title  = g_new(gchar*, num_cols);
   cinfo->col_custom_field = g_new(gchar*, num_cols);
+  cinfo->col_custom_occurrence = g_new(gint, num_cols);
+  cinfo->col_custom_field_id = g_new(int, num_cols);
   cinfo->col_custom_dfilter = g_new(dfilter_t*, num_cols);
-  cinfo->col_data      = (const gchar **)g_new(gchar*, num_cols);
-  cinfo->col_buf       = g_new(gchar*, num_cols);
-  cinfo->col_fence     = g_new(int, num_cols);
-  cinfo->col_expr.col_expr = g_new(gchar*, num_cols + 1);
+  cinfo->col_data   = (const gchar **)g_new(gchar*, num_cols);
+  cinfo->col_buf    = g_new(gchar*, num_cols);
+  cinfo->col_fence  = g_new(int, num_cols);
+  cinfo->col_expr.col_expr = (const gchar **) g_new(gchar*, num_cols + 1);
   cinfo->col_expr.col_expr_val = g_new(gchar*, num_cols + 1);
 
   for (i = 0; i < NUM_COL_FMTS; i++) {
@@ -80,51 +78,54 @@ col_init(column_info *cinfo)
 {
   int i;
 
+  if (!cinfo)
+    return;
+
   for (i = 0; i < cinfo->num_cols; i++) {
     cinfo->col_buf[i][0] = '\0';
     cinfo->col_data[i] = cinfo->col_buf[i];
     cinfo->col_fence[i] = 0;
-    cinfo->col_expr.col_expr[i][0] = '\0';
+    cinfo->col_expr.col_expr[i] = "";
     cinfo->col_expr.col_expr_val[i][0] = '\0';
   }
   cinfo->writable = TRUE;
 }
 
+#define COL_GET_WRITABLE(cinfo) (cinfo ? cinfo->writable : FALSE)
+
 gboolean
 col_get_writable(column_info *cinfo)
 {
-       return (cinfo ? cinfo->writable : FALSE);
+    return COL_GET_WRITABLE(cinfo);
 }
 
 void
-col_set_writable(column_info *cinfo, gboolean writable)
+col_set_writable(column_info *cinfo, const gboolean writable)
 {
-       if (cinfo)
-               cinfo->writable = writable;
+    if (cinfo)
+        cinfo->writable = writable;
 }
 
-/* Checks to see if a particular packet information element is needed for
-   the packet list */
-gint
-check_col(column_info *cinfo, gint el) {
+/* Checks to see if a particular packet information element is needed for the packet list */
+#define CHECK_COL(cinfo, el) \
+    /* We are constructing columns, and they're writable */ \
+    (COL_GET_WRITABLE(cinfo) && \
+      /* There is at least one column in that format */ \
+    ((cinfo)->col_first[el] >= 0))
 
-  if (col_get_writable(cinfo)) {
-    /* We are constructing columns, and they're writable */
-    if (cinfo->col_first[el] >= 0) {
-      /* There is at least one column in that format */
-      return TRUE;
-    }
-  }
-  return FALSE;
+gint
+check_col(column_info *cinfo, const gint el)
+{
+  return CHECK_COL(cinfo, el);
 }
 
 /* Sets the fence for a column to be at the end of the column. */
 void
-col_set_fence(column_info *cinfo, gint el)
+col_set_fence(column_info *cinfo, const gint el)
 {
   int i;
 
-  if (!check_col(cinfo, el))
+  if (!CHECK_COL(cinfo, el))
     return;
 
   for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) {
@@ -141,12 +142,12 @@ col_set_fence(column_info *cinfo, gint el)
    later append to it, as the later append will cause a string
    copy to be done. */
 void
-col_clear(column_info *cinfo, gint el)
+col_clear(column_info *cinfo, const gint el)
 {
   int    i;
   int    fence;
 
-  if (!check_col(cinfo, el))
+  if (!CHECK_COL(cinfo, el))
     return;
 
   for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) {
@@ -168,7 +169,7 @@ col_clear(column_info *cinfo, gint el)
        *      we don't do anything.
        */
       fence = cinfo->col_fence[i];
-      if (fence == 0 || cinfo->col_buf[i] == cinfo->col_data[i]) {
+      if (cinfo->col_buf[i] == cinfo->col_data[i] || fence == 0) {
         /*
          * The fence isn't at the end of the column, or the column wasn't
          * last set with "col_set_str()", so clear the column out.
@@ -176,198 +177,143 @@ col_clear(column_info *cinfo, gint el)
         cinfo->col_buf[i][fence] = '\0';
         cinfo->col_data[i] = cinfo->col_buf[i];
       }
-      cinfo->col_expr.col_expr[i][0] = '\0';
+      cinfo->col_expr.col_expr[i] = "";
       cinfo->col_expr.col_expr_val[i][0] = '\0';
     }
   }
 }
 
 #define COL_CHECK_APPEND(cinfo, i, max_len) \
-  if (cinfo->col_data[i] != cinfo->col_buf[i]) {               \
-    /* This was set with "col_set_str()"; copy the string they \
-       set it to into the buffer, so we can append to it. */   \
-    g_strlcpy(cinfo->col_buf[i], cinfo->col_data[i], max_len); \
-    cinfo->col_data[i] = cinfo->col_buf[i];                    \
+  if (cinfo->col_data[i] != cinfo->col_buf[i]) {        \
+    /* This was set with "col_set_str()"; copy the string they  \
+       set it to into the buffer, so we can append to it. */    \
+    g_strlcpy(cinfo->col_buf[i], cinfo->col_data[i], max_len);  \
+    cinfo->col_data[i] = cinfo->col_buf[i];         \
   }
 
-#define COL_CHECK_REF_TIME(fd, cinfo, col)     \
-  if(fd->flags.ref_time){                                      \
-    g_snprintf(cinfo->col_buf[col], COL_MAX_LEN, "*REF*");     \
-    cinfo->col_data[col] = cinfo->col_buf[col];                        \
-    return;                                                    \
+#define COL_CHECK_REF_TIME(fd, buf)         \
+  if(fd->flags.ref_time){                   \
+    g_strlcpy(buf, "*REF*", COL_MAX_LEN );  \
+    return;                                 \
   }
 
-/* Use this if "str" points to something that will stay around (and thus
-   needn't be copied). */
-void
-col_set_str(column_info *cinfo, gint el, const gchar* str)
-{
-  int i;
-  int fence;
-  size_t max_len;
+/* The same as CHECK_COL(), but without the check to see if the column is writable. */
+#define HAVE_CUSTOM_COLS(cinfo) ((cinfo) && (cinfo)->col_first[COL_CUSTOM] >= 0)
 
-  if (!check_col(cinfo, el))
-    return;
+gboolean
+have_custom_cols(column_info *cinfo)
+{
+  return HAVE_CUSTOM_COLS(cinfo);
+}
 
-  if (el == COL_INFO)
-       max_len = COL_MAX_INFO_LEN;
-  else
-       max_len = COL_MAX_LEN;
+/* search in edt tree custom fields */
+void col_custom_set_edt(epan_dissect_t *edt, column_info *cinfo)
+{
+  int i;
 
-  for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) {
-    if (cinfo->fmt_matx[i][el]) {
-      fence = cinfo->col_fence[i];
-      if (fence != 0) {
-        /*
-         * We will append the string after the fence.
-         * First arrange that we can append, if necessary.
-         */
-        COL_CHECK_APPEND(cinfo, i, max_len);
+  if(!HAVE_CUSTOM_COLS(cinfo))
+      return;
 
-        g_strlcpy(&cinfo->col_buf[i][fence], str, max_len - fence);
-      } else {
-        /*
-         * There's no fence, so we can just set the column to point
-         * to the string.
-         */
-        cinfo->col_data[i] = str;
-      }
+  for (i = cinfo->col_first[COL_CUSTOM];
+       i <= cinfo->col_last[COL_CUSTOM]; i++) {
+    if (cinfo->fmt_matx[i][COL_CUSTOM] &&
+        cinfo->col_custom_field[i] &&
+        cinfo->col_custom_field_id[i] != -1) {
+       cinfo->col_data[i] = cinfo->col_buf[i];
+       cinfo->col_expr.col_expr[i] = epan_custom_set(edt, cinfo->col_custom_field_id[i],
+                                     cinfo->col_custom_occurrence[i],
+                                     cinfo->col_buf[i],
+                                     cinfo->col_expr.col_expr_val[i],
+                                     COL_MAX_LEN);
     }
   }
 }
 
-/* Adds a vararg list to a packet info string. */
 void
-col_add_fstr(column_info *cinfo, gint el, const gchar *format, ...) {
-  va_list ap;
-  int     i;
-  int     fence;
-  int     max_len;
+col_custom_prime_edt(epan_dissect_t *edt, column_info *cinfo)
+{
+  int i;
 
-  if (!check_col(cinfo, el))
-    return;
+  if(!HAVE_CUSTOM_COLS(cinfo))
+      return;
 
-  if (el == COL_INFO)
-       max_len = COL_MAX_INFO_LEN;
-  else
-       max_len = COL_MAX_LEN;
+  for (i = cinfo->col_first[COL_CUSTOM];
+       i <= cinfo->col_last[COL_CUSTOM]; i++) {
 
-  va_start(ap, format);
-  for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) {
-    if (cinfo->fmt_matx[i][el]) {
-      fence = cinfo->col_fence[i];
-      if (fence != 0) {
-        /*
-         * We will append the string after the fence.
-         * First arrange that we can append, if necessary.
-         */
-        COL_CHECK_APPEND(cinfo, i, max_len);
-      } else {
-        /*
-         * There's no fence, so we can just write to the string.
-         */
-        cinfo->col_data[i] = cinfo->col_buf[i];
-      }
-      g_vsnprintf(&cinfo->col_buf[i][fence], max_len - fence, format, ap);
-      cinfo->col_buf[i][max_len - 1] = '\0';
+    cinfo->col_custom_field_id[i] = -1;
+    if (cinfo->fmt_matx[i][COL_CUSTOM] &&
+        cinfo->col_custom_dfilter[i]){
+        epan_dissect_prime_dfilter(edt, cinfo->col_custom_dfilter[i]);
+        if (cinfo->col_custom_field) {
+            header_field_info* hfinfo = proto_registrar_get_byname(cinfo->col_custom_field[i]);
+            cinfo->col_custom_field_id[i] = hfinfo ? hfinfo->id : -1;
+        }
     }
   }
-  va_end(ap);
 }
 
+/*  Appends a vararg list to a packet info string.
+ *  This function's code is duplicated in col_append_sep_fstr() below because
+ *  the for() loop below requires us to call va_start/va_end so intermediate
+ *  functions are a problem.
+ */
 void
-col_custom_set_fstr(header_field_info *hfinfo, const gchar *format, ...)
+col_append_fstr(column_info *cinfo, const gint el, const gchar *format, ...)
 {
+  int  i;
+  int  len, max_len;
   va_list ap;
-  int     i;
 
-  if (!have_custom_cols(ci))
+  if (!CHECK_COL(cinfo, el))
     return;
 
-  va_start(ap, format);
-  for (i = ci->col_first[COL_CUSTOM];
-       i <= ci->col_last[COL_CUSTOM]; i++) {
-    if (ci->fmt_matx[i][COL_CUSTOM] &&
-        ci->col_custom_field[i] &&
-        strcmp(ci->col_custom_field[i], hfinfo->abbrev) == 0) {
-      ci->col_data[i] = ci->col_buf[i];
-      g_vsnprintf(ci->col_buf[i], COL_MAX_LEN, format, ap);
+  if (el == COL_INFO)
+    max_len = COL_MAX_INFO_LEN;
+  else
+    max_len = COL_MAX_LEN;
 
-      g_strlcpy(ci->col_expr.col_expr[i], hfinfo->abbrev, COL_MAX_LEN);
+  for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) {
+    if (cinfo->fmt_matx[i][el]) {
+      /*
+       * First arrange that we can append, if necessary.
+       */
+      COL_CHECK_APPEND(cinfo, i, max_len);
 
-      switch(hfinfo->type) {
-      case FT_STRING:
-      case FT_STRINGZ:
-        g_snprintf(ci->col_expr.col_expr_val[i], COL_MAX_LEN, "\"%s\"",
-           ci->col_buf[i]);
-       break;
+      len = (int) strlen(cinfo->col_buf[i]);
 
-      default:
-       g_strlcpy(ci->col_expr.col_expr_val[i], ci->col_buf[i], COL_MAX_LEN);
-       break;
-      }
+      va_start(ap, format);
+      g_vsnprintf(&cinfo->col_buf[i][len], max_len - len, format, ap);
+      va_end(ap);
     }
   }
-  va_end(ap);
+
 }
 
+/*  Appends a vararg list to a packet info string.
+ *  Prefixes it with the given separator if the column is not empty.
+ *  Code is duplicated from col_append_fstr above().
+ */
 void
-col_custom_prime_edt(epan_dissect_t *edt, column_info *cinfo)
+col_append_sep_fstr(column_info *cinfo, const gint el, const gchar *separator,
+                   const gchar *format, ...)
 {
-  int i;
-
-  ci = cinfo; /* Save this into the static variable ci for use by
-              * col_custom_set_fstr() later. */
-
-  if(!have_custom_cols(cinfo))
-      return;
-
-  for (i = cinfo->col_first[COL_CUSTOM];
-       i <= cinfo->col_last[COL_CUSTOM]; i++) {
-    if (cinfo->fmt_matx[i][COL_CUSTOM] &&
-        cinfo->col_custom_dfilter[i])
-        epan_dissect_prime_dfilter(edt, cinfo->col_custom_dfilter[i]);
-  }
-}
+  int  i;
+  int  len, max_len, sep_len;
+  va_list ap;
 
-gboolean
-have_custom_cols(column_info *cinfo)
-{
-  /* The same as check_col(), but without the check to see if the column
-   * is writable. */
-  if (cinfo && cinfo->col_first[COL_CUSTOM] >= 0)
-    return TRUE;
-  else
-    return FALSE;
-}
+  if (!CHECK_COL(cinfo, el))
+    return;
 
-gboolean
-col_has_time_fmt(column_info *cinfo, gint col)
-{
-  return ((cinfo->fmt_matx[col][COL_CLS_TIME]) ||
-          (cinfo->fmt_matx[col][COL_ABS_TIME]) ||
-          (cinfo->fmt_matx[col][COL_ABS_DATE_TIME]) ||
-          (cinfo->fmt_matx[col][COL_REL_TIME]) ||
-          (cinfo->fmt_matx[col][COL_DELTA_TIME]) ||
-          (cinfo->fmt_matx[col][COL_DELTA_TIME_DIS]));
-}
+  if (separator == NULL)
+    separator = ", ";    /* default */
 
-static void
-col_do_append_sep_va_fstr(column_info *cinfo, gint el, const gchar *separator,
-                         const gchar *format, va_list ap)
-{
-  int  i;
-  int  len, max_len, sep_len;
+  sep_len = (int) strlen(separator);
 
   if (el == COL_INFO)
-       max_len = COL_MAX_INFO_LEN;
+    max_len = COL_MAX_INFO_LEN;
   else
-       max_len = COL_MAX_LEN;
+    max_len = COL_MAX_LEN;
 
-  if (separator == NULL)
-    sep_len = 0;
-  else
-    sep_len = (int) strlen(separator);
   for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) {
     if (cinfo->fmt_matx[i][el]) {
       /*
@@ -380,57 +326,24 @@ col_do_append_sep_va_fstr(column_info *cinfo, gint el, const gchar *separator,
       /*
        * If we have a separator, append it if the column isn't empty.
        */
-      if (separator != NULL) {
+      if (sep_len != 0) {
         if (len != 0) {
           g_strlcat(cinfo->col_buf[i], separator, max_len);
           len += sep_len;
         }
       }
+      va_start(ap, format);
       g_vsnprintf(&cinfo->col_buf[i][len], max_len - len, format, ap);
-      cinfo->col_buf[i][max_len-1] = 0;
+      va_end(ap);
     }
   }
 }
 
-/* Appends a vararg list to a packet info string. */
-void
-col_append_fstr(column_info *cinfo, gint el, const gchar *format, ...)
-{
-  va_list ap;
-
-  if (!check_col(cinfo, el))
-    return;
-
-  va_start(ap, format);
-  col_do_append_sep_va_fstr(cinfo, el, NULL, format, ap);
-  va_end(ap);
-}
-
-/* Appends a vararg list to a packet info string.
- * Prefixes it with the given separator if the column is not empty. */
-void
-col_append_sep_fstr(column_info *cinfo, gint el, const gchar *separator,
-               const gchar *format, ...)
-{
-  va_list ap;
-
-  if (!check_col(cinfo, el))
-    return;
-
-  if (separator == NULL)
-    separator = ", ";    /* default */
-  va_start(ap, format);
-  col_do_append_sep_va_fstr(cinfo, el, separator, format, ap);
-  va_end(ap);
-}
-
-
-
 /* Prepends a vararg list to a packet info string. */
 #define COL_BUF_MAX_LEN (((COL_MAX_INFO_LEN) > (COL_MAX_LEN)) ? \
-       (COL_MAX_INFO_LEN) : (COL_MAX_LEN))
+    (COL_MAX_INFO_LEN) : (COL_MAX_LEN))
 void
-col_prepend_fstr(column_info *cinfo, gint el, const gchar *format, ...)
+col_prepend_fstr(column_info *cinfo, const gint el, const gchar *format, ...)
 {
   va_list     ap;
   int         i;
@@ -438,15 +351,14 @@ col_prepend_fstr(column_info *cinfo, gint el, const gchar *format, ...)
   const char *orig;
   int         max_len;
 
-  if (!check_col(cinfo, el))
+  if (!CHECK_COL(cinfo, el))
     return;
 
   if (el == COL_INFO)
-       max_len = COL_MAX_INFO_LEN;
+    max_len = COL_MAX_INFO_LEN;
   else
-       max_len = COL_MAX_LEN;
+    max_len = COL_MAX_LEN;
 
-  va_start(ap, format);
   for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) {
     if (cinfo->fmt_matx[i][el]) {
       if (cinfo->col_data[i] != cinfo->col_buf[i]) {
@@ -456,8 +368,9 @@ col_prepend_fstr(column_info *cinfo, gint el, const gchar *format, ...)
         g_strlcpy(orig_buf, cinfo->col_buf[i], max_len);
         orig = orig_buf;
       }
+      va_start(ap, format);
       g_vsnprintf(cinfo->col_buf[i], max_len, format, ap);
-      cinfo->col_buf[i][max_len - 1] = '\0';
+      va_end(ap);
 
       /*
        * Move the fence, unless it's at the beginning of the string.
@@ -469,10 +382,9 @@ col_prepend_fstr(column_info *cinfo, gint el, const gchar *format, ...)
       cinfo->col_data[i] = cinfo->col_buf[i];
     }
   }
-  va_end(ap);
 }
 void
-col_prepend_fence_fstr(column_info *cinfo, gint el, const gchar *format, ...)
+col_prepend_fence_fstr(column_info *cinfo, const gint el, const gchar *format, ...)
 {
   va_list     ap;
   int         i;
@@ -480,15 +392,14 @@ col_prepend_fence_fstr(column_info *cinfo, gint el, const gchar *format, ...)
   const char *orig;
   int         max_len;
 
-  if (!check_col(cinfo, el))
+  if (!CHECK_COL(cinfo, el))
     return;
 
   if (el == COL_INFO)
-       max_len = COL_MAX_INFO_LEN;
+    max_len = COL_MAX_INFO_LEN;
   else
-       max_len = COL_MAX_LEN;
+    max_len = COL_MAX_LEN;
 
-  va_start(ap, format);
   for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) {
     if (cinfo->fmt_matx[i][el]) {
       if (cinfo->col_data[i] != cinfo->col_buf[i]) {
@@ -498,8 +409,9 @@ col_prepend_fence_fstr(column_info *cinfo, gint el, const gchar *format, ...)
         g_strlcpy(orig_buf, cinfo->col_buf[i], max_len);
         orig = orig_buf;
       }
+      va_start(ap, format);
       g_vsnprintf(cinfo->col_buf[i], max_len, format, ap);
-      cinfo->col_buf[i][max_len - 1] = '\0';
+      va_end(ap);
 
       /*
        * Move the fence if it exists, else create a new fence at the
@@ -514,25 +426,24 @@ col_prepend_fence_fstr(column_info *cinfo, gint el, const gchar *format, ...)
       cinfo->col_data[i] = cinfo->col_buf[i];
     }
   }
-  va_end(ap);
 }
 
 /* Use this if "str" points to something that won't stay around (and
    must thus be copied). */
 void
-col_add_str(column_info *cinfo, gint el, const gchar* str)
+col_add_str(column_info *cinfo, const gint el, const gchar* str)
 {
   int    i;
   int    fence;
   size_t max_len;
 
-  if (!check_col(cinfo, el))
+  if (!CHECK_COL(cinfo, el))
     return;
 
   if (el == COL_INFO)
-       max_len = COL_MAX_INFO_LEN;
+    max_len = COL_MAX_INFO_LEN;
   else
-       max_len = COL_MAX_LEN;
+    max_len = COL_MAX_LEN;
 
   for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) {
     if (cinfo->fmt_matx[i][el]) {
@@ -554,25 +465,100 @@ col_add_str(column_info *cinfo, gint el, const gchar* str)
   }
 }
 
-static void
-col_do_append_str(column_info *cinfo, gint el, const gchar* separator,
-    const gchar* str)
+/* Use this if "str" points to something that will stay around (and thus
+   needn't be copied). */
+void
+col_set_str(column_info *cinfo, const gint el, const gchar* str)
 {
-  int    i;
-  size_t len, max_len, sep_len;
+  int i;
+  int fence;
+  size_t max_len;
+
+  DISSECTOR_ASSERT(str);
 
-  if (!check_col(cinfo, el))
+  /* The caller is expected to pass in something that 'will stay around' and
+   * something from the ephemeral pool certainly doesn't fit the bill. */
+  DISSECTOR_ASSERT(!ep_verify_pointer(str));
+
+  if (!CHECK_COL(cinfo, el))
     return;
 
   if (el == COL_INFO)
-       max_len = COL_MAX_INFO_LEN;
+    max_len = COL_MAX_INFO_LEN;
   else
-       max_len = COL_MAX_LEN;
+    max_len = COL_MAX_LEN;
 
-  if (separator == NULL)
-    sep_len = 0;
+  for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) {
+    if (cinfo->fmt_matx[i][el]) {
+      fence = cinfo->col_fence[i];
+      if (fence != 0) {
+        /*
+         * We will append the string after the fence.
+         * First arrange that we can append, if necessary.
+         */
+        COL_CHECK_APPEND(cinfo, i, max_len);
+
+        g_strlcpy(&cinfo->col_buf[i][fence], str, max_len - fence);
+      } else {
+        /*
+         * There's no fence, so we can just set the column to point
+         * to the string.
+         */
+        cinfo->col_data[i] = str;
+      }
+    }
+  }
+}
+
+/* Adds a vararg list to a packet info string. */
+void
+col_add_fstr(column_info *cinfo, const gint el, const gchar *format, ...) {
+  va_list ap;
+  int     i;
+  int     fence;
+  int     max_len;
+
+  if (!CHECK_COL(cinfo, el))
+    return;
+
+  if (el == COL_INFO)
+    max_len = COL_MAX_INFO_LEN;
+  else
+    max_len = COL_MAX_LEN;
+
+  for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) {
+    if (cinfo->fmt_matx[i][el]) {
+      fence = cinfo->col_fence[i];
+      if (fence != 0) {
+        /*
+         * We will append the string after the fence.
+         * First arrange that we can append, if necessary.
+         */
+        COL_CHECK_APPEND(cinfo, i, max_len);
+      } else {
+        /*
+         * There's no fence, so we can just write to the string.
+         */
+        cinfo->col_data[i] = cinfo->col_buf[i];
+      }
+      va_start(ap, format);
+      g_vsnprintf(&cinfo->col_buf[i][fence], max_len - fence, format, ap);
+      va_end(ap);
+    }
+  }
+}
+
+static void
+col_do_append_str(column_info *cinfo, const gint el, const gchar* separator,
+    const gchar* str)
+{
+  int    i;
+  size_t len, max_len;
+
+  if (el == COL_INFO)
+    max_len = COL_MAX_INFO_LEN;
   else
-    sep_len = strlen(separator);
+    max_len = COL_MAX_LEN;
 
   for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) {
     if (cinfo->fmt_matx[i][el]) {
@@ -597,47 +583,70 @@ col_do_append_str(column_info *cinfo, gint el, const gchar* separator,
 }
 
 void
-col_append_str(column_info *cinfo, gint el, const gchar* str)
+col_append_str(column_info *cinfo, const gint el, const gchar* str)
 {
+  if (!CHECK_COL(cinfo, el))
+    return;
+
   col_do_append_str(cinfo, el, NULL, str);
 }
 
 void
-col_append_sep_str(column_info *cinfo, gint el, const gchar* separator,
+col_append_sep_str(column_info *cinfo, const gint el, const gchar* separator,
     const gchar* str)
 {
+  if (!CHECK_COL(cinfo, el))
+    return;
+
   if (separator == NULL)
     separator = ", ";    /* default */
+
   col_do_append_str(cinfo, el, separator, str);
 }
 
+/* --------------------------------- */
+gboolean
+col_has_time_fmt(column_info *cinfo, const gint col)
+{
+  return ((cinfo->fmt_matx[col][COL_CLS_TIME]) ||
+          (cinfo->fmt_matx[col][COL_ABS_TIME]) ||
+          (cinfo->fmt_matx[col][COL_ABS_DATE_TIME]) ||
+          (cinfo->fmt_matx[col][COL_UTC_TIME]) ||
+          (cinfo->fmt_matx[col][COL_UTC_DATE_TIME]) ||
+          (cinfo->fmt_matx[col][COL_REL_TIME]) ||
+          (cinfo->fmt_matx[col][COL_DELTA_TIME]) ||
+          (cinfo->fmt_matx[col][COL_DELTA_TIME_DIS]));
+}
+
 static void
-col_set_abs_date_time(frame_data *fd, column_info *cinfo, int col)
+set_abs_date_time(const frame_data *fd, gchar *buf, gboolean local)
 {
   struct tm *tmp;
   time_t then;
 
-  COL_CHECK_REF_TIME(fd, cinfo, col);
-
-  then = fd->abs_ts.secs;
-  tmp = localtime(&then);
+  if (fd->flags.has_ts) {
+    then = fd->abs_ts.secs;
+    if (local)
+       tmp = localtime(&then);
+    else
+       tmp = gmtime(&then);
+  } else
+    tmp = NULL;
   if (tmp != NULL) {
-         switch(timestamp_get_precision()) {
-         case(TS_PREC_FIXED_SEC):
-         case(TS_PREC_AUTO_SEC):
-                 g_snprintf(cinfo->col_buf[col], COL_MAX_LEN,
-             "%04d-%02d-%02d %02d:%02d:%02d",
+      switch(timestamp_get_precision()) {
+      case TS_PREC_FIXED_SEC:
+      case TS_PREC_AUTO_SEC:
+          g_snprintf(buf, COL_MAX_LEN,"%04d-%02d-%02d %02d:%02d:%02d",
              tmp->tm_year + 1900,
              tmp->tm_mon + 1,
              tmp->tm_mday,
              tmp->tm_hour,
              tmp->tm_min,
              tmp->tm_sec);
-                 break;
-         case(TS_PREC_FIXED_DSEC):
-         case(TS_PREC_AUTO_DSEC):
-                 g_snprintf(cinfo->col_buf[col], COL_MAX_LEN,
-             "%04d-%02d-%02d %02d:%02d:%02d.%01ld",
+          break;
+      case TS_PREC_FIXED_DSEC:
+      case TS_PREC_AUTO_DSEC:
+          g_snprintf(buf, COL_MAX_LEN,"%04d-%02d-%02d %02d:%02d:%02d.%01ld",
              tmp->tm_year + 1900,
              tmp->tm_mon + 1,
              tmp->tm_mday,
@@ -645,11 +654,10 @@ col_set_abs_date_time(frame_data *fd, column_info *cinfo, int col)
              tmp->tm_min,
              tmp->tm_sec,
              (long)fd->abs_ts.nsecs / 100000000);
-                 break;
-         case(TS_PREC_FIXED_CSEC):
-         case(TS_PREC_AUTO_CSEC):
-                 g_snprintf(cinfo->col_buf[col], COL_MAX_LEN,
-             "%04d-%02d-%02d %02d:%02d:%02d.%02ld",
+          break;
+      case TS_PREC_FIXED_CSEC:
+      case TS_PREC_AUTO_CSEC:
+          g_snprintf(buf, COL_MAX_LEN,"%04d-%02d-%02d %02d:%02d:%02d.%02ld",
              tmp->tm_year + 1900,
              tmp->tm_mon + 1,
              tmp->tm_mday,
@@ -657,11 +665,10 @@ col_set_abs_date_time(frame_data *fd, column_info *cinfo, int col)
              tmp->tm_min,
              tmp->tm_sec,
              (long)fd->abs_ts.nsecs / 10000000);
-                 break;
-         case(TS_PREC_FIXED_MSEC):
-         case(TS_PREC_AUTO_MSEC):
-                 g_snprintf(cinfo->col_buf[col], COL_MAX_LEN,
-             "%04d-%02d-%02d %02d:%02d:%02d.%03ld",
+          break;
+      case TS_PREC_FIXED_MSEC:
+      case TS_PREC_AUTO_MSEC:
+          g_snprintf(buf, COL_MAX_LEN, "%04d-%02d-%02d %02d:%02d:%02d.%03ld",
              tmp->tm_year + 1900,
              tmp->tm_mon + 1,
              tmp->tm_mday,
@@ -669,11 +676,10 @@ col_set_abs_date_time(frame_data *fd, column_info *cinfo, int col)
              tmp->tm_min,
              tmp->tm_sec,
              (long)fd->abs_ts.nsecs / 1000000);
-                 break;
-         case(TS_PREC_FIXED_USEC):
-         case(TS_PREC_AUTO_USEC):
-                 g_snprintf(cinfo->col_buf[col], COL_MAX_LEN,
-             "%04d-%02d-%02d %02d:%02d:%02d.%06ld",
+          break;
+      case TS_PREC_FIXED_USEC:
+      case TS_PREC_AUTO_USEC:
+          g_snprintf(buf, COL_MAX_LEN, "%04d-%02d-%02d %02d:%02d:%02d.%06ld",
              tmp->tm_year + 1900,
              tmp->tm_mon + 1,
              tmp->tm_mday,
@@ -681,11 +687,10 @@ col_set_abs_date_time(frame_data *fd, column_info *cinfo, int col)
              tmp->tm_min,
              tmp->tm_sec,
              (long)fd->abs_ts.nsecs / 1000);
-                 break;
-         case(TS_PREC_FIXED_NSEC):
-         case(TS_PREC_AUTO_NSEC):
-                 g_snprintf(cinfo->col_buf[col], COL_MAX_LEN,
-             "%04d-%02d-%02d %02d:%02d:%02d.%09ld",
+          break;
+      case TS_PREC_FIXED_NSEC:
+      case TS_PREC_AUTO_NSEC:
+          g_snprintf(buf, COL_MAX_LEN, "%04d-%02d-%02d %02d:%02d:%02d.%09ld",
              tmp->tm_year + 1900,
              tmp->tm_mon + 1,
              tmp->tm_mday,
@@ -693,276 +698,543 @@ col_set_abs_date_time(frame_data *fd, column_info *cinfo, int col)
              tmp->tm_min,
              tmp->tm_sec,
              (long)fd->abs_ts.nsecs);
-                 break;
-         default:
-                 g_assert_not_reached();
-         }
+          break;
+      default:
+          g_assert_not_reached();
+      }
   } else {
-    cinfo->col_buf[col][0] = '\0';
+    buf[0] = '\0';
   }
-  cinfo->col_data[col] = cinfo->col_buf[col];
-  g_strlcpy(cinfo->col_expr.col_expr[col],"frame.time",COL_MAX_LEN);
-  g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
 }
 
 static void
-col_set_rel_time(frame_data *fd, column_info *cinfo, int col)
+col_set_abs_date_time(const frame_data *fd, column_info *cinfo, const int col)
 {
-  COL_CHECK_REF_TIME(fd, cinfo, col);
+  set_abs_date_time(fd, cinfo->col_buf[col], TRUE);
+  cinfo->col_expr.col_expr[col] = "frame.time";
+  g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
 
-  switch(timestamp_get_precision()) {
-         case(TS_PREC_FIXED_SEC):
-         case(TS_PREC_AUTO_SEC):
-                 display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       (gint32) fd->rel_ts.secs, fd->rel_ts.nsecs / 1000000000, SECS);
-                 break;
-         case(TS_PREC_FIXED_DSEC):
-         case(TS_PREC_AUTO_DSEC):
-                 display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       (gint32) fd->rel_ts.secs, fd->rel_ts.nsecs / 100000000, DSECS);
-                 break;
-         case(TS_PREC_FIXED_CSEC):
-         case(TS_PREC_AUTO_CSEC):
-                 display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       (gint32) fd->rel_ts.secs, fd->rel_ts.nsecs / 10000000, CSECS);
-                 break;
-         case(TS_PREC_FIXED_MSEC):
-         case(TS_PREC_AUTO_MSEC):
-                 display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       (gint32) fd->rel_ts.secs, fd->rel_ts.nsecs / 1000000, MSECS);
-                 break;
-         case(TS_PREC_FIXED_USEC):
-         case(TS_PREC_AUTO_USEC):
-                 display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       (gint32) fd->rel_ts.secs, fd->rel_ts.nsecs / 1000, USECS);
-                 break;
-         case(TS_PREC_FIXED_NSEC):
-         case(TS_PREC_AUTO_NSEC):
-                 display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       (gint32) fd->rel_ts.secs, fd->rel_ts.nsecs, NSECS);
-                 break;
-         default:
-                 g_assert_not_reached();
-  }
   cinfo->col_data[col] = cinfo->col_buf[col];
-  g_strlcpy(cinfo->col_expr.col_expr[col],"frame.time_relative", COL_MAX_LEN);
+}
+
+static void
+col_set_utc_date_time(const frame_data *fd, column_info *cinfo, const int col)
+{
+  set_abs_date_time(fd, cinfo->col_buf[col], FALSE);
+  cinfo->col_expr.col_expr[col] = "frame.time";
   g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
+
+  cinfo->col_data[col] = cinfo->col_buf[col];
+}
+
+static void
+set_time_seconds(const nstime_t *ts, gchar *buf)
+{
+  switch(timestamp_get_precision()) {
+      case TS_PREC_FIXED_SEC:
+      case TS_PREC_AUTO_SEC:
+          display_signed_time(buf, COL_MAX_LEN,
+            (gint32) ts->secs, ts->nsecs / 1000000000, TO_STR_TIME_RES_T_SECS);
+          break;
+      case TS_PREC_FIXED_DSEC:
+      case TS_PREC_AUTO_DSEC:
+          display_signed_time(buf, COL_MAX_LEN,
+            (gint32) ts->secs, ts->nsecs / 100000000, TO_STR_TIME_RES_T_DSECS);
+          break;
+      case TS_PREC_FIXED_CSEC:
+      case TS_PREC_AUTO_CSEC:
+          display_signed_time(buf, COL_MAX_LEN,
+            (gint32) ts->secs, ts->nsecs / 10000000, TO_STR_TIME_RES_T_CSECS);
+          break;
+      case TS_PREC_FIXED_MSEC:
+      case TS_PREC_AUTO_MSEC:
+          display_signed_time(buf, COL_MAX_LEN,
+            (gint32) ts->secs, ts->nsecs / 1000000, TO_STR_TIME_RES_T_MSECS);
+          break;
+      case TS_PREC_FIXED_USEC:
+      case TS_PREC_AUTO_USEC:
+          display_signed_time(buf, COL_MAX_LEN,
+            (gint32) ts->secs, ts->nsecs / 1000, TO_STR_TIME_RES_T_USECS);
+          break;
+      case TS_PREC_FIXED_NSEC:
+      case TS_PREC_AUTO_NSEC:
+          display_signed_time(buf, COL_MAX_LEN,
+            (gint32) ts->secs, ts->nsecs, TO_STR_TIME_RES_T_NSECS);
+          break;
+      default:
+          g_assert_not_reached();
+  }
 }
 
 static void
-col_set_delta_time(frame_data *fd, column_info *cinfo, int col)
+set_time_hour_min_sec(const nstime_t *ts, gchar *buf)
 {
-  COL_CHECK_REF_TIME(fd, cinfo, col);
+  time_t secs = ts->secs;
+  long nsecs = (long) ts->nsecs;
+  gboolean negative = FALSE;
+
+  if (secs < 0) {
+    secs = -secs;
+    negative = TRUE;
+  }
+  if (nsecs < 0) {
+    nsecs = -nsecs;
+    negative = TRUE;
+  }
 
   switch(timestamp_get_precision()) {
-         case(TS_PREC_FIXED_SEC):
-         case(TS_PREC_AUTO_SEC):
-                 display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       (gint32) fd->del_cap_ts.secs, fd->del_cap_ts.nsecs / 1000000000, SECS);
-                 break;
-         case(TS_PREC_FIXED_DSEC):
-         case(TS_PREC_AUTO_DSEC):
-                 display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       (gint32) fd->del_cap_ts.secs, fd->del_cap_ts.nsecs / 100000000, DSECS);
-                 break;
-         case(TS_PREC_FIXED_CSEC):
-         case(TS_PREC_AUTO_CSEC):
-                 display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       (gint32) fd->del_cap_ts.secs, fd->del_cap_ts.nsecs / 10000000, CSECS);
-                 break;
-         case(TS_PREC_FIXED_MSEC):
-         case(TS_PREC_AUTO_MSEC):
-                 display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       (gint32) fd->del_cap_ts.secs, fd->del_cap_ts.nsecs / 1000000, MSECS);
-                 break;
-         case(TS_PREC_FIXED_USEC):
-         case(TS_PREC_AUTO_USEC):
-                 display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       (gint32) fd->del_cap_ts.secs, fd->del_cap_ts.nsecs / 1000, USECS);
-                 break;
-         case(TS_PREC_FIXED_NSEC):
-         case(TS_PREC_AUTO_NSEC):
-                 display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       (gint32) fd->del_cap_ts.secs, fd->del_cap_ts.nsecs, NSECS);
-                 break;
-         default:
-                 g_assert_not_reached();
+  case TS_PREC_FIXED_SEC:
+  case TS_PREC_AUTO_SEC:
+    if (secs >= (60*60)) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dh %2dm %2ds",
+                negative ? "- " : "",
+                (gint32) secs / (60 * 60),
+                (gint32) (secs / 60) % 60,
+                (gint32) secs % 60);
+    } else if (secs >= 60) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dm %2ds",
+                negative ? "- " : "",
+                (gint32) secs / 60,
+                (gint32) secs % 60);
+    } else {
+      g_snprintf(buf, COL_MAX_LEN, "%s%ds",
+                negative ? "- " : "",
+                (gint32) secs);
+    }
+    break;
+  case TS_PREC_FIXED_DSEC:
+  case TS_PREC_AUTO_DSEC:
+    if (secs >= (60*60)) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dh %2dm %2d.%01lds",
+                negative ? "- " : "",
+                (gint32) secs / (60 * 60),
+                (gint32) (secs / 60) % 60,
+                (gint32) secs % 60,
+                nsecs / 100000000);
+    } else if (secs >= 60) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dm %2d.%01lds",
+                negative ? "- " : "",
+                (gint32) secs / 60,
+                (gint32) secs % 60,
+                nsecs / 100000000);
+    } else {
+      g_snprintf(buf, COL_MAX_LEN, "%s%d.%01lds",
+                negative ? "- " : "",
+                (gint32) secs,
+                nsecs / 100000000);
+    }
+    break;
+  case TS_PREC_FIXED_CSEC:
+  case TS_PREC_AUTO_CSEC:
+    if (secs >= (60*60)) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dh %2dm %2d.%02lds",
+                negative ? "- " : "",
+                (gint32) secs / (60 * 60),
+                (gint32) (secs / 60) % 60,
+                (gint32) secs % 60,
+                nsecs / 10000000);
+    } else if (secs >= 60) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dm %2d.%02lds",
+                negative ? "- " : "",
+                (gint32) secs / 60,
+                (gint32) secs % 60,
+                nsecs / 10000000);
+    } else {
+      g_snprintf(buf, COL_MAX_LEN, "%s%d.%02lds",
+                negative ? "- " : "",
+                (gint32) secs,
+                nsecs / 10000000);
+    }
+    break;
+  case TS_PREC_FIXED_MSEC:
+  case TS_PREC_AUTO_MSEC:
+    if (secs >= (60*60)) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dh %2dm %2d.%03lds",
+                negative ? "- " : "",
+                (gint32) secs / (60 * 60),
+                (gint32) (secs / 60) % 60,
+                (gint32) secs % 60,
+                nsecs / 1000000);
+    } else if (secs >= 60) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dm %2d.%03lds",
+                negative ? "- " : "",
+                (gint32) secs / 60,
+                (gint32) secs % 60,
+                nsecs / 1000000);
+    } else {
+      g_snprintf(buf, COL_MAX_LEN, "%s%d.%03lds",
+                negative ? "- " : "",
+                (gint32) secs,
+                nsecs / 1000000);
+    }
+    break;
+  case TS_PREC_FIXED_USEC:
+  case TS_PREC_AUTO_USEC:
+    if (secs >= (60*60)) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dh %2dm %2d.%06lds",
+                negative ? "- " : "",
+                (gint32) secs / (60 * 60),
+                (gint32) (secs / 60) % 60,
+                (gint32) secs % 60,
+                nsecs / 1000);
+    } else if (secs >= 60) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dm %2d.%06lds",
+                negative ? "- " : "",
+                (gint32) secs / 60,
+                (gint32) secs % 60,
+                nsecs / 1000);
+    } else {
+      g_snprintf(buf, COL_MAX_LEN, "%s%d.%06lds",
+                negative ? "- " : "",
+                (gint32) secs,
+                nsecs / 1000);
+    }
+    break;
+  case TS_PREC_FIXED_NSEC:
+  case TS_PREC_AUTO_NSEC:
+    if (secs >= (60*60)) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dh %2dm %2d.%09lds",
+                negative ? "- " : "",
+                (gint32) secs / (60 * 60),
+                (gint32) (secs / 60) % 60,
+                (gint32) secs % 60,
+                nsecs);
+    } else if (secs >= 60) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dm %2d.%09lds",
+                negative ? "- " : "",
+                (gint32) secs / 60,
+                (gint32) secs % 60,
+                nsecs);
+    } else {
+      g_snprintf(buf, COL_MAX_LEN, "%s%d.%09lds",
+                negative ? "- " : "",
+                (gint32) secs,
+                nsecs);
+    }
+    break;
+  default:
+    g_assert_not_reached();
+  }
+}
+
+static void
+col_set_rel_time(const frame_data *fd, column_info *cinfo, const int col)
+{
+  if (!fd->flags.has_ts) {
+    cinfo->col_buf[col][0] = '\0';
+    return;
+  }
+  switch (timestamp_get_seconds_type()) {
+  case TS_SECONDS_DEFAULT:
+    set_time_seconds(&fd->rel_ts, cinfo->col_buf[col]);
+    cinfo->col_expr.col_expr[col] = "frame.time_relative";
+    g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
+    break;
+  case TS_SECONDS_HOUR_MIN_SEC:
+    set_time_hour_min_sec(&fd->rel_ts, cinfo->col_buf[col]);
+    cinfo->col_expr.col_expr[col] = "frame.time_relative";
+    set_time_seconds(&fd->rel_ts, cinfo->col_expr.col_expr_val[col]);
+    break;
+  default:
+    g_assert_not_reached();
   }
   cinfo->col_data[col] = cinfo->col_buf[col];
-  g_strlcpy(cinfo->col_expr.col_expr[col],"frame.time_delta",COL_MAX_LEN);
-  g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
 }
 
 static void
-col_set_delta_time_dis(frame_data *fd, column_info *cinfo, int col)
+col_set_delta_time(const frame_data *fd, column_info *cinfo, const int col)
 {
-  COL_CHECK_REF_TIME(fd, cinfo, col);
+  nstime_t del_cap_ts;
 
-  switch(timestamp_get_precision()) {
-         case(TS_PREC_FIXED_SEC):
-         case(TS_PREC_AUTO_SEC):
-                 display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       (gint32) fd->del_dis_ts.secs, fd->del_dis_ts.nsecs / 1000000000, SECS);
-                 break;
-         case(TS_PREC_FIXED_DSEC):
-         case(TS_PREC_AUTO_DSEC):
-                 display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       (gint32) fd->del_dis_ts.secs, fd->del_dis_ts.nsecs / 100000000, DSECS);
-                 break;
-         case(TS_PREC_FIXED_CSEC):
-         case(TS_PREC_AUTO_CSEC):
-                 display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       (gint32) fd->del_dis_ts.secs, fd->del_dis_ts.nsecs / 10000000, CSECS);
-                 break;
-         case(TS_PREC_FIXED_MSEC):
-         case(TS_PREC_AUTO_MSEC):
-                 display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       (gint32) fd->del_dis_ts.secs, fd->del_dis_ts.nsecs / 1000000, MSECS);
-                 break;
-         case(TS_PREC_FIXED_USEC):
-         case(TS_PREC_AUTO_USEC):
-                 display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       (gint32) fd->del_dis_ts.secs, fd->del_dis_ts.nsecs / 1000, USECS);
-                 break;
-         case(TS_PREC_FIXED_NSEC):
-         case(TS_PREC_AUTO_NSEC):
-                 display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       (gint32) fd->del_dis_ts.secs, fd->del_dis_ts.nsecs, NSECS);
-                 break;
-         default:
-                 g_assert_not_reached();
+  frame_delta_abs_time(fd, fd->prev_cap, &del_cap_ts);
+
+  switch (timestamp_get_seconds_type()) {
+  case TS_SECONDS_DEFAULT:
+    set_time_seconds(&del_cap_ts, cinfo->col_buf[col]);
+    cinfo->col_expr.col_expr[col] = "frame.time_delta";
+    g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
+    break;
+  case TS_SECONDS_HOUR_MIN_SEC:
+    set_time_hour_min_sec(&del_cap_ts, cinfo->col_buf[col]);
+    cinfo->col_expr.col_expr[col] = "frame.time_delta";
+    set_time_seconds(&del_cap_ts, cinfo->col_expr.col_expr_val[col]);
+    break;
+  default:
+    g_assert_not_reached();
   }
+
   cinfo->col_data[col] = cinfo->col_buf[col];
-  g_strlcpy(cinfo->col_expr.col_expr[col],"frame.time_delta_displayed",
-           COL_MAX_LEN);
-  g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
 }
 
-/* To do: Add check_col checks to the col_add* routines */
+static void
+col_set_delta_time_dis(const frame_data *fd, column_info *cinfo, const int col)
+{
+  nstime_t del_dis_ts;
+
+  if (!fd->flags.has_ts) {
+    cinfo->col_buf[col][0] = '\0';
+    return;
+  }
+
+  frame_delta_abs_time(fd, fd->prev_dis, &del_dis_ts);
+
+  switch (timestamp_get_seconds_type()) {
+  case TS_SECONDS_DEFAULT:
+    set_time_seconds(&del_dis_ts, cinfo->col_buf[col]);
+    cinfo->col_expr.col_expr[col] = "frame.time_delta_displayed";
+    g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
+    break;
+  case TS_SECONDS_HOUR_MIN_SEC:
+    set_time_hour_min_sec(&del_dis_ts, cinfo->col_buf[col]);
+    cinfo->col_expr.col_expr[col] = "frame.time_delta_displayed";
+    set_time_seconds(&del_dis_ts, cinfo->col_expr.col_expr_val[col]);
+    break;
+  default:
+    g_assert_not_reached();
+  }
+
+  cinfo->col_data[col] = cinfo->col_buf[col];
+}
 
 static void
-col_set_abs_time(frame_data *fd, column_info *cinfo, int col)
+set_abs_time(const frame_data *fd, gchar *buf, gboolean local)
 {
   struct tm *tmp;
   time_t then;
 
-  COL_CHECK_REF_TIME(fd, cinfo, col);
-
-  then = fd->abs_ts.secs;
-  tmp = localtime(&then);
+  if (fd->flags.has_ts) {
+    then = fd->abs_ts.secs;
+    if (local)
+       tmp = localtime(&then);
+    else
+       tmp = gmtime(&then);
+  } else
+    tmp = NULL;
   if (tmp != NULL) {
-         switch(timestamp_get_precision()) {
-         case(TS_PREC_FIXED_SEC):
-         case(TS_PREC_AUTO_SEC):
-                 g_snprintf(cinfo->col_buf[col], COL_MAX_LEN,
-             "%02d:%02d:%02d",
+      switch(timestamp_get_precision()) {
+      case TS_PREC_FIXED_SEC:
+      case TS_PREC_AUTO_SEC:
+          g_snprintf(buf, COL_MAX_LEN,"%02d:%02d:%02d",
              tmp->tm_hour,
              tmp->tm_min,
              tmp->tm_sec);
-                 break;
-         case(TS_PREC_FIXED_DSEC):
-         case(TS_PREC_AUTO_DSEC):
-                 g_snprintf(cinfo->col_buf[col], COL_MAX_LEN,
-             "%02d:%02d:%02d.%01ld",
+          break;
+      case TS_PREC_FIXED_DSEC:
+      case TS_PREC_AUTO_DSEC:
+          g_snprintf(buf, COL_MAX_LEN,"%02d:%02d:%02d.%01ld",
              tmp->tm_hour,
              tmp->tm_min,
              tmp->tm_sec,
              (long)fd->abs_ts.nsecs / 100000000);
-                 break;
-         case(TS_PREC_FIXED_CSEC):
-         case(TS_PREC_AUTO_CSEC):
-                 g_snprintf(cinfo->col_buf[col], COL_MAX_LEN,
-             "%02d:%02d:%02d.%02ld",
+          break;
+      case TS_PREC_FIXED_CSEC:
+      case TS_PREC_AUTO_CSEC:
+          g_snprintf(buf, COL_MAX_LEN,"%02d:%02d:%02d.%02ld",
              tmp->tm_hour,
              tmp->tm_min,
              tmp->tm_sec,
              (long)fd->abs_ts.nsecs / 10000000);
-                 break;
-         case(TS_PREC_FIXED_MSEC):
-         case(TS_PREC_AUTO_MSEC):
-                 g_snprintf(cinfo->col_buf[col], COL_MAX_LEN,
-             "%02d:%02d:%02d.%03ld",
+          break;
+      case TS_PREC_FIXED_MSEC:
+      case TS_PREC_AUTO_MSEC:
+          g_snprintf(buf, COL_MAX_LEN,"%02d:%02d:%02d.%03ld",
              tmp->tm_hour,
              tmp->tm_min,
              tmp->tm_sec,
              (long)fd->abs_ts.nsecs / 1000000);
-                 break;
-         case(TS_PREC_FIXED_USEC):
-         case(TS_PREC_AUTO_USEC):
-                 g_snprintf(cinfo->col_buf[col], COL_MAX_LEN,
-             "%02d:%02d:%02d.%06ld",
+          break;
+      case TS_PREC_FIXED_USEC:
+      case TS_PREC_AUTO_USEC:
+          g_snprintf(buf, COL_MAX_LEN,"%02d:%02d:%02d.%06ld",
              tmp->tm_hour,
              tmp->tm_min,
              tmp->tm_sec,
              (long)fd->abs_ts.nsecs / 1000);
-                 break;
-         case(TS_PREC_FIXED_NSEC):
-         case(TS_PREC_AUTO_NSEC):
-                 g_snprintf(cinfo->col_buf[col], COL_MAX_LEN,
-             "%02d:%02d:%02d.%09ld",
+          break;
+      case TS_PREC_FIXED_NSEC:
+      case TS_PREC_AUTO_NSEC:
+          g_snprintf(buf, COL_MAX_LEN, "%02d:%02d:%02d.%09ld",
              tmp->tm_hour,
              tmp->tm_min,
              tmp->tm_sec,
              (long)fd->abs_ts.nsecs);
-                 break;
-         default:
-                 g_assert_not_reached();
-         }
+          break;
+      default:
+          g_assert_not_reached();
+      }
+
   } else {
-    cinfo->col_buf[col][0] = '\0';
+    *buf = '\0';
   }
-  cinfo->col_data[col] = cinfo->col_buf[col];
-  g_strlcpy(cinfo->col_expr.col_expr[col],"frame.time",COL_MAX_LEN);
+}
+
+static void
+col_set_abs_time(const frame_data *fd, column_info *cinfo, const int col)
+{
+  set_abs_time(fd, cinfo->col_buf[col], TRUE);
+  cinfo->col_expr.col_expr[col] = "frame.time";
   g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
+
+  cinfo->col_data[col] = cinfo->col_buf[col];
 }
 
 static void
-col_set_epoch_time(frame_data *fd, column_info *cinfo, int col)
+col_set_utc_time(const frame_data *fd, column_info *cinfo, const int col)
 {
+  set_abs_time(fd, cinfo->col_buf[col], FALSE);
+  cinfo->col_expr.col_expr[col] = "frame.time";
+  g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
 
-  COL_CHECK_REF_TIME(fd, cinfo, col);
+  cinfo->col_data[col] = cinfo->col_buf[col];
+}
 
+static gboolean
+set_epoch_time(const frame_data *fd, gchar *buf)
+{
+  if (!fd->flags.has_ts) {
+    buf[0] = '\0';
+    return FALSE;
+  }
   switch(timestamp_get_precision()) {
-         case(TS_PREC_FIXED_SEC):
-         case(TS_PREC_AUTO_SEC):
-                 display_epoch_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       fd->abs_ts.secs, fd->abs_ts.nsecs / 1000000000, SECS);
-                 break;
-         case(TS_PREC_FIXED_DSEC):
-         case(TS_PREC_AUTO_DSEC):
-                 display_epoch_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       fd->abs_ts.secs, fd->abs_ts.nsecs / 100000000, DSECS);
-                 break;
-         case(TS_PREC_FIXED_CSEC):
-         case(TS_PREC_AUTO_CSEC):
-                 display_epoch_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       fd->abs_ts.secs, fd->abs_ts.nsecs / 10000000, CSECS);
-                 break;
-         case(TS_PREC_FIXED_MSEC):
-         case(TS_PREC_AUTO_MSEC):
-                 display_epoch_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       fd->abs_ts.secs, fd->abs_ts.nsecs / 1000000, MSECS);
-                 break;
-         case(TS_PREC_FIXED_USEC):
-         case(TS_PREC_AUTO_USEC):
-                 display_epoch_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       fd->abs_ts.secs, fd->abs_ts.nsecs / 1000, USECS);
-                 break;
-         case(TS_PREC_FIXED_NSEC):
-         case(TS_PREC_AUTO_NSEC):
-                 display_epoch_time(cinfo->col_buf[col], COL_MAX_LEN,
-                       fd->abs_ts.secs, fd->abs_ts.nsecs, NSECS);
-                 break;
-         default:
-                 g_assert_not_reached();
+      case TS_PREC_FIXED_SEC:
+      case TS_PREC_AUTO_SEC:
+          display_epoch_time(buf, COL_MAX_LEN,
+            fd->abs_ts.secs, fd->abs_ts.nsecs / 1000000000, TO_STR_TIME_RES_T_SECS);
+          break;
+      case TS_PREC_FIXED_DSEC:
+      case TS_PREC_AUTO_DSEC:
+          display_epoch_time(buf, COL_MAX_LEN,
+            fd->abs_ts.secs, fd->abs_ts.nsecs / 100000000, TO_STR_TIME_RES_T_DSECS);
+          break;
+      case TS_PREC_FIXED_CSEC:
+      case TS_PREC_AUTO_CSEC:
+          display_epoch_time(buf, COL_MAX_LEN,
+            fd->abs_ts.secs, fd->abs_ts.nsecs / 10000000, TO_STR_TIME_RES_T_CSECS);
+          break;
+      case TS_PREC_FIXED_MSEC:
+      case TS_PREC_AUTO_MSEC:
+          display_epoch_time(buf, COL_MAX_LEN,
+            fd->abs_ts.secs, fd->abs_ts.nsecs / 1000000, TO_STR_TIME_RES_T_MSECS);
+          break;
+      case TS_PREC_FIXED_USEC:
+      case TS_PREC_AUTO_USEC:
+          display_epoch_time(buf, COL_MAX_LEN,
+            fd->abs_ts.secs, fd->abs_ts.nsecs / 1000, TO_STR_TIME_RES_T_USECS);
+          break;
+      case TS_PREC_FIXED_NSEC:
+      case TS_PREC_AUTO_NSEC:
+          display_epoch_time(buf, COL_MAX_LEN,
+            fd->abs_ts.secs, fd->abs_ts.nsecs, TO_STR_TIME_RES_T_NSECS);
+          break;
+      default:
+          g_assert_not_reached();
+  }
+  return TRUE;
+}
+
+static void
+col_set_epoch_time(const frame_data *fd, column_info *cinfo, const int col)
+{
+  if (set_epoch_time(fd, cinfo->col_buf[col])) {
+    cinfo->col_expr.col_expr[col] = "frame.time_delta";
+    g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
   }
   cinfo->col_data[col] = cinfo->col_buf[col];
-  g_strlcpy(cinfo->col_expr.col_expr[col],"frame.time_delta",COL_MAX_LEN);
-  g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
+}
+
+void
+set_fd_time(frame_data *fd, gchar *buf)
+{
+
+  switch (timestamp_get_type()) {
+    case TS_ABSOLUTE:
+      set_abs_time(fd, buf, TRUE);
+      break;
+
+    case TS_ABSOLUTE_WITH_DATE:
+      set_abs_date_time(fd, buf, TRUE);
+      break;
+
+    case TS_RELATIVE:
+      if (fd->flags.has_ts) {
+        switch (timestamp_get_seconds_type()) {
+        case TS_SECONDS_DEFAULT:
+          set_time_seconds(&fd->rel_ts, buf);
+          break;
+        case TS_SECONDS_HOUR_MIN_SEC:
+          set_time_seconds(&fd->rel_ts, buf);
+          break;
+        default:
+          g_assert_not_reached();
+        }
+      } else {
+        buf[0] = '\0';
+      }
+      break;
+
+    case TS_DELTA:
+      if (fd->flags.has_ts) {
+        nstime_t del_cap_ts;
+
+        frame_delta_abs_time(fd, fd->prev_cap, &del_cap_ts);
+
+        switch (timestamp_get_seconds_type()) {
+        case TS_SECONDS_DEFAULT:
+          set_time_seconds(&del_cap_ts, buf);
+          break;
+        case TS_SECONDS_HOUR_MIN_SEC:
+          set_time_hour_min_sec(&del_cap_ts, buf);
+          break;
+        default:
+          g_assert_not_reached();
+        }
+      } else {
+        buf[0] = '\0';
+      }
+      break;
+
+    case TS_DELTA_DIS:
+      if (fd->flags.has_ts) {
+        nstime_t del_dis_ts;
+
+        frame_delta_abs_time(fd, fd->prev_dis, &del_dis_ts);
+
+        switch (timestamp_get_seconds_type()) {
+        case TS_SECONDS_DEFAULT:
+          set_time_seconds(&del_dis_ts, buf);
+          break;
+        case TS_SECONDS_HOUR_MIN_SEC:
+          set_time_hour_min_sec(&del_dis_ts, buf);
+          break;
+        default:
+          g_assert_not_reached();
+        }
+      } else {
+        buf[0] = '\0';
+      }
+      break;
+
+    case TS_EPOCH:
+      set_epoch_time(fd, buf);
+      break;
+
+    case TS_UTC:
+      set_abs_time(fd, buf, FALSE);
+      break;
+
+    case TS_UTC_WITH_DATE:
+      set_abs_date_time(fd, buf, FALSE);
+      break;
+
+    case TS_NOT_SET:
+      /* code is missing for this case, but I don't know which [jmayer20051219] */
+      g_assert(FALSE);
+      break;
+  }
 }
 
 static void
-col_set_cls_time(frame_data *fd, column_info *cinfo, gint col)
+col_set_cls_time(const frame_data *fd, column_info *cinfo, const gint col)
 {
   switch (timestamp_get_type()) {
     case TS_ABSOLUTE:
@@ -989,26 +1261,30 @@ col_set_cls_time(frame_data *fd, column_info *cinfo, gint col)
       col_set_epoch_time(fd, cinfo, col);
       break;
 
+    case TS_UTC:
+      col_set_utc_time(fd, cinfo, col);
+      break;
+
+    case TS_UTC_WITH_DATE:
+      col_set_utc_date_time(fd, cinfo, col);
+      break;
+
     case TS_NOT_SET:
       /* code is missing for this case, but I don't know which [jmayer20051219] */
-      g_assert(FALSE);
+      g_assert_not_reached();
       break;
   }
 }
 
-/* Set the format of the variable time format.
-   XXX - this is called from "file.c" when the user changes the time
-   format they want for "command-line-specified" time; it's a bit ugly
-   that we have to export it, but if we go to a CList-like widget that
-   invokes callbacks to get the text for the columns rather than
-   requiring us to stuff the text into the widget from outside, we
-   might be able to clean this up. */
-void
-col_set_fmt_time(frame_data *fd, column_info *cinfo, gint fmt, gint col)
+/* Set the format of the variable time format. */
+static void
+col_set_fmt_time(const frame_data *fd, column_info *cinfo, const gint fmt, const gint col)
 {
+  COL_CHECK_REF_TIME(fd, cinfo->col_buf[col]);
+
   switch (fmt) {
     case COL_CLS_TIME:
-       col_set_cls_time(fd, cinfo, col);
+      col_set_cls_time(fd, cinfo, col);
       break;
 
     case COL_ABS_TIME:
@@ -1031,9 +1307,12 @@ col_set_fmt_time(frame_data *fd, column_info *cinfo, gint fmt, gint col)
       col_set_delta_time_dis(fd, cinfo, col);
       break;
 
-    case COL_REL_CONV_TIME:
-    case COL_DELTA_CONV_TIME:
-      /* Will be set by various dissectors */
+    case COL_UTC_TIME:
+      col_set_utc_time(fd, cinfo, col);
+      break;
+
+    case COL_UTC_DATE_TIME:
+      col_set_utc_date_time(fd, cinfo, col);
       break;
 
     default:
@@ -1042,127 +1321,152 @@ col_set_fmt_time(frame_data *fd, column_info *cinfo, gint fmt, gint col)
   }
 }
 
+/* --------------------------- */
+/* Set the given (relative) time to a column element.
+ *
+ * Used by multiple dissectors to set the time in the column
+ * COL_DELTA_CONV_TIME
+ *
+ * @param cinfo                the current packet row
+ * @param col          the column to use, e.g. COL_INFO
+ * @param ts           the time to set in the column
+ * @param fieldname    the fieldname to use for creating a filter (when
+ *                       applying/preparing/copying as filter)
+ */
 void
-col_set_time(column_info *cinfo, gint el, nstime_t *ts, char *fieldname)
+col_set_time(column_info *cinfo, const gint el, const nstime_t *ts, char *fieldname)
 {
-  int  col;
+  int col;
 
-  if (!check_col(cinfo, el))
+  if (!CHECK_COL(cinfo, el))
     return;
 
+  /** @todo TODO: We don't respect fd->flags.ref_time (no way to access 'fd')
+  COL_CHECK_REF_TIME(fd, buf);
+  */
+
   for (col = cinfo->col_first[el]; col <= cinfo->col_last[el]; col++) {
     if (cinfo->fmt_matx[col][el]) {
       switch(timestamp_get_precision()) {
-       case(TS_PREC_FIXED_SEC):
-       case(TS_PREC_AUTO_SEC):
-         display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-           (gint32) ts->secs, ts->nsecs / 1000000000, SECS);
-         break;
-       case(TS_PREC_FIXED_DSEC):
-       case(TS_PREC_AUTO_DSEC):
-         display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-           (gint32) ts->secs, ts->nsecs / 100000000, DSECS);
-         break;
-       case(TS_PREC_FIXED_CSEC):
-       case(TS_PREC_AUTO_CSEC):
-         display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-           (gint32) ts->secs, ts->nsecs / 10000000, CSECS);
-         break;
-       case(TS_PREC_FIXED_MSEC):
-       case(TS_PREC_AUTO_MSEC):
-         display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-           (gint32) ts->secs, ts->nsecs / 1000000, MSECS);
-         break;
-       case(TS_PREC_FIXED_USEC):
-       case(TS_PREC_AUTO_USEC):
-         display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-           (gint32) ts->secs, ts->nsecs / 1000, USECS);
-         break;
-       case(TS_PREC_FIXED_NSEC):
-       case(TS_PREC_AUTO_NSEC):
-         display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
-           (gint32) ts->secs, ts->nsecs, NSECS);
-         break;
-       default:
-         g_assert_not_reached();
+    case TS_PREC_FIXED_SEC:
+    case TS_PREC_AUTO_SEC:
+      display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
+        (gint32) ts->secs, ts->nsecs / 1000000000, TO_STR_TIME_RES_T_SECS);
+      break;
+    case TS_PREC_FIXED_DSEC:
+    case TS_PREC_AUTO_DSEC:
+      display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
+        (gint32) ts->secs, ts->nsecs / 100000000, TO_STR_TIME_RES_T_DSECS);
+      break;
+    case TS_PREC_FIXED_CSEC:
+    case TS_PREC_AUTO_CSEC:
+      display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
+        (gint32) ts->secs, ts->nsecs / 10000000, TO_STR_TIME_RES_T_CSECS);
+      break;
+    case TS_PREC_FIXED_MSEC:
+    case TS_PREC_AUTO_MSEC:
+      display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
+        (gint32) ts->secs, ts->nsecs / 1000000, TO_STR_TIME_RES_T_MSECS);
+      break;
+    case TS_PREC_FIXED_USEC:
+    case TS_PREC_AUTO_USEC:
+      display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
+        (gint32) ts->secs, ts->nsecs / 1000, TO_STR_TIME_RES_T_USECS);
+      break;
+    case TS_PREC_FIXED_NSEC:
+    case TS_PREC_AUTO_NSEC:
+      display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
+        (gint32) ts->secs, ts->nsecs, TO_STR_TIME_RES_T_NSECS);
+      break;
+    default:
+      g_assert_not_reached();
       }
       cinfo->col_data[col] = cinfo->col_buf[col];
-      g_strlcpy(cinfo->col_expr.col_expr[col],fieldname,COL_MAX_LEN);
-      g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],
-               COL_MAX_LEN);
+      cinfo->col_expr.col_expr[col] = fieldname;
+      g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
     }
   }
 }
 
 static void
-col_set_addr(packet_info *pinfo, int col, address *addr, gboolean is_res,
-            gboolean is_src)
+col_set_addr(packet_info *pinfo, const int col, const address *addr, const gboolean is_src, const gboolean fill_col_exprs)
 {
-  struct e_in6_addr ipv6_addr;
-
-  pinfo->cinfo->col_expr.col_expr[col][0] = '\0';
-  pinfo->cinfo->col_expr.col_expr_val[col][0] = '\0';
+  if (addr->type == AT_NONE) {
+    /* No address, nothing to do */
+    return;
+  }
 
-  if (addr->type == AT_NONE)
-    return;    /* no address, nothing to do */
+  pinfo->cinfo->col_data[col] = se_get_addr_name(addr);
 
-  if (is_res) {
-    get_addr_name_buf(addr, pinfo->cinfo->col_buf[col], COL_MAX_LEN);
-  } else {
-    address_to_str_buf(addr, pinfo->cinfo->col_buf[col], COL_MAX_LEN);
-  }
-  pinfo->cinfo->col_data[col] = pinfo->cinfo->col_buf[col];
+  if (!fill_col_exprs)
+    return;
 
   switch (addr->type) {
 
-  case AT_ETHER:
+  case AT_AX25:
     if (is_src)
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "eth.src",COL_MAX_LEN);
+      pinfo->cinfo->col_expr.col_expr[col] = "ax25.src";
     else
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "eth.dst",COL_MAX_LEN);
-    g_strlcpy(pinfo->cinfo->col_expr.col_expr_val[col], ether_to_str(addr->data), COL_MAX_LEN);
+      pinfo->cinfo->col_expr.col_expr[col] = "ax25.dst";
+    g_strlcpy(pinfo->cinfo->col_expr.col_expr_val[col], ax25_to_str(addr->data), COL_MAX_LEN);
+    break;
+
+  case AT_ETHER:
+    switch(addr->subtype) {
+    default:
+      if (is_src)
+        pinfo->cinfo->col_expr.col_expr[col] = "eth.src";
+      else
+        pinfo->cinfo->col_expr.col_expr[col] = "eth.dst";
+      address_to_str_buf(addr, pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN);
+      break;
+    case AT_SUB_IEEE80211:
+      if (is_src)
+        pinfo->cinfo->col_expr.col_expr[col] = "wlan.sa";
+      else
+        pinfo->cinfo->col_expr.col_expr[col] = "wlan.da";
+      address_to_str_buf(addr, pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN);
+      break;
+    }
     break;
 
   case AT_IPv4:
     if (is_src)
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "ip.src", COL_MAX_LEN);
+      pinfo->cinfo->col_expr.col_expr[col] = "ip.src";
     else
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "ip.dst",COL_MAX_LEN);
-    g_strlcpy(pinfo->cinfo->col_expr.col_expr_val[col], ip_to_str(addr->data), COL_MAX_LEN);
+      pinfo->cinfo->col_expr.col_expr[col] = "ip.dst";
+    ip_to_str_buf(addr->data, pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN);
     break;
 
   case AT_IPv6:
     if (is_src)
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "ipv6.src", COL_MAX_LEN);
+      pinfo->cinfo->col_expr.col_expr[col] = "ipv6.src";
     else
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "ipv6.dst", COL_MAX_LEN);
-    memcpy(&ipv6_addr.bytes, addr->data, sizeof ipv6_addr.bytes);
-    g_strlcpy(pinfo->cinfo->col_expr.col_expr_val[col], ip6_to_str(&ipv6_addr), COL_MAX_LEN);
+      pinfo->cinfo->col_expr.col_expr[col] = "ipv6.dst";
+    address_to_str_buf(addr, pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN);
     break;
 
   case AT_ATALK:
     if (is_src)
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "ddp.src", COL_MAX_LEN);
+      pinfo->cinfo->col_expr.col_expr[col] = "ddp.src";
     else
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "ddp.dst", COL_MAX_LEN);
+      pinfo->cinfo->col_expr.col_expr[col] = "ddp.dst";
     g_strlcpy(pinfo->cinfo->col_expr.col_expr_val[col], pinfo->cinfo->col_buf[col], COL_MAX_LEN);
     break;
 
   case AT_ARCNET:
     if (is_src)
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "arcnet.src",
-        COL_MAX_LEN);
+      pinfo->cinfo->col_expr.col_expr[col] = "arcnet.src";
     else
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "arcnet.dst", 
-       COL_MAX_LEN);
+      pinfo->cinfo->col_expr.col_expr[col] = "arcnet.dst";
     g_strlcpy(pinfo->cinfo->col_expr.col_expr_val[col], pinfo->cinfo->col_buf[col], COL_MAX_LEN);
     break;
 
   case AT_URI:
     if (is_src)
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "uri.src", COL_MAX_LEN);
+      pinfo->cinfo->col_expr.col_expr[col] = "uri.src";
     else
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "uri.dst", COL_MAX_LEN);
+      pinfo->cinfo->col_expr.col_expr[col] = "uri.dst";
     address_to_str_buf(addr, pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN);
     break;
 
@@ -1171,8 +1475,9 @@ col_set_addr(packet_info *pinfo, int col, address *addr, gboolean is_res,
   }
 }
 
+/* ------------------------ */
 static void
-col_set_port(packet_info *pinfo, int col, gboolean is_res, gboolean is_src)
+col_set_port(packet_info *pinfo, const int col, const gboolean is_res, const gboolean is_src, const gboolean fill_col_exprs _U_)
 {
   guint32 port;
 
@@ -1180,166 +1485,78 @@ col_set_port(packet_info *pinfo, int col, gboolean is_res, gboolean is_src)
     port = pinfo->srcport;
   else
     port = pinfo->destport;
-  pinfo->cinfo->col_expr.col_expr[col][0] = '\0';
-  pinfo->cinfo->col_expr.col_expr_val[col][0] = '\0';
-  switch (pinfo->ptype) {
 
+  /* TODO: Use fill_col_exprs */
+
+  switch (pinfo->ptype) {
   case PT_SCTP:
     if (is_res)
       g_strlcpy(pinfo->cinfo->col_buf[col], get_sctp_port(port), COL_MAX_LEN);
     else
-      g_snprintf(pinfo->cinfo->col_buf[col], COL_MAX_LEN, "%u", port);
+      guint32_to_str_buf(port, pinfo->cinfo->col_buf[col], COL_MAX_LEN);
     break;
 
   case PT_TCP:
+    guint32_to_str_buf(port, pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN);
     if (is_res)
       g_strlcpy(pinfo->cinfo->col_buf[col], get_tcp_port(port), COL_MAX_LEN);
     else
-      g_snprintf(pinfo->cinfo->col_buf[col], COL_MAX_LEN, "%u", port);
+      g_strlcpy(pinfo->cinfo->col_buf[col], pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN);
     if (is_src)
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "tcp.srcport",
-       COL_MAX_LEN);
+      pinfo->cinfo->col_expr.col_expr[col] = "tcp.srcport";
     else
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "tcp.dstport",
-       COL_MAX_LEN);
-    g_snprintf(pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN, "%u", port);
+      pinfo->cinfo->col_expr.col_expr[col] = "tcp.dstport";
     break;
 
   case PT_UDP:
+    guint32_to_str_buf(port, pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN);
     if (is_res)
       g_strlcpy(pinfo->cinfo->col_buf[col], get_udp_port(port), COL_MAX_LEN);
     else
-      g_snprintf(pinfo->cinfo->col_buf[col], COL_MAX_LEN, "%u", port);
+      g_strlcpy(pinfo->cinfo->col_buf[col], pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN);
     if (is_src)
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "udp.srcport",
-       COL_MAX_LEN);
+      pinfo->cinfo->col_expr.col_expr[col] = "udp.srcport";
     else
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "udp.dstport",
-       COL_MAX_LEN);
-    g_snprintf(pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN, "%u", port);
+      pinfo->cinfo->col_expr.col_expr[col] = "udp.dstport";
     break;
 
   case PT_DDP:
     if (is_src)
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "ddp.src_socket",
-       COL_MAX_LEN);
+      pinfo->cinfo->col_expr.col_expr[col] = "ddp.src_socket";
     else
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "ddp.dst_socket",
-       COL_MAX_LEN);
-    g_snprintf(pinfo->cinfo->col_buf[col], COL_MAX_LEN, "%u", port);
-    g_snprintf(pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN, "%u", port);
+      pinfo->cinfo->col_expr.col_expr[col] = "ddp.dst_socket";
+    guint32_to_str_buf(port, pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN);
+    g_strlcpy(pinfo->cinfo->col_buf[col], pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN);
     break;
 
   case PT_IPX:
     /* XXX - resolve IPX socket numbers */
     g_snprintf(pinfo->cinfo->col_buf[col], COL_MAX_LEN, "0x%04x", port);
+    g_strlcpy(pinfo->cinfo->col_expr.col_expr_val[col], pinfo->cinfo->col_buf[col],COL_MAX_LEN);
     if (is_src)
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "ipx.src.socket",
-       COL_MAX_LEN);
+      pinfo->cinfo->col_expr.col_expr[col] = "ipx.src.socket";
     else
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "ipx.dst.socket",
-       COL_MAX_LEN);
-    g_snprintf(pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN, "0x%04x", port);
+      pinfo->cinfo->col_expr.col_expr[col] = "ipx.dst.socket";
     break;
 
   case PT_IDP:
     /* XXX - resolve IDP socket numbers */
     g_snprintf(pinfo->cinfo->col_buf[col], COL_MAX_LEN, "0x%04x", port);
+    g_strlcpy(pinfo->cinfo->col_expr.col_expr_val[col], pinfo->cinfo->col_buf[col],COL_MAX_LEN);
     if (is_src)
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "idp.src.socket",
-       COL_MAX_LEN);
+      pinfo->cinfo->col_expr.col_expr[col] = "idp.src.socket";
     else
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "idp.dst.socket",
-       COL_MAX_LEN);
-    g_snprintf(pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN, "0x%04x", port);
+      pinfo->cinfo->col_expr.col_expr[col] = "idp.dst.socket";
     break;
 
   case PT_USB:
     /* XXX - resolve USB endpoint numbers */
     g_snprintf(pinfo->cinfo->col_buf[col], COL_MAX_LEN, "0x%08x", port);
+    g_strlcpy(pinfo->cinfo->col_expr.col_expr_val[col], pinfo->cinfo->col_buf[col],COL_MAX_LEN);
     if (is_src)
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "usb.src.endpoint",
-       COL_MAX_LEN);
+      pinfo->cinfo->col_expr.col_expr[col] = "usb.src.endpoint";
     else
-      g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "usb.dst.endpoint",
-       COL_MAX_LEN);
-    g_snprintf(pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN, "0x%08x", port);
-    break;
-
-  default:
-    break;
-  }
-  pinfo->cinfo->col_data[col] = pinfo->cinfo->col_buf[col];
-}
-
-/*
- * XXX - this should be in some common code in the epan directory, shared
- * by this code and packet-isdn.c.
- */
-static const value_string channel_vals[] = {
-       { 0,    "D" },
-       { 1,    "B1" },
-       { 2,    "B2" },
-       { 3,    "B3" },
-       { 4,    "B4" },
-       { 5,    "B5" },
-       { 6,    "B6" },
-       { 7,    "B7" },
-       { 8,    "B8" },
-       { 9,    "B9" },
-       { 10,   "B10" },
-       { 11,   "B11" },
-       { 12,   "B12" },
-       { 13,   "B13" },
-       { 14,   "B14" },
-       { 15,   "B15" },
-       { 16,   "B16" },
-       { 17,   "B17" },
-       { 18,   "B19" },
-       { 19,   "B19" },
-       { 20,   "B20" },
-       { 21,   "B21" },
-       { 22,   "B22" },
-       { 23,   "B23" },
-       { 24,   "B24" },
-       { 25,   "B25" },
-       { 26,   "B26" },
-       { 27,   "B27" },
-       { 28,   "B29" },
-       { 29,   "B29" },
-       { 30,   "B30" },
-       { 0,    NULL }
-};
-
-static void
-col_set_circuit_id(packet_info *pinfo, int col)
-{
-  pinfo->cinfo->col_expr.col_expr[col][0] = '\0';
-  pinfo->cinfo->col_expr.col_expr_val[col][0] = '\0';
-  switch (pinfo->ctype) {
-
-  case CT_DLCI:
-    g_snprintf(pinfo->cinfo->col_buf[col], COL_MAX_LEN, "%u", pinfo->circuit_id);
-    g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "fr.dlci", COL_MAX_LEN);
-    g_snprintf(pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN, "%u", pinfo->circuit_id);
-    break;
-
-  case CT_ISDN:
-    g_snprintf(pinfo->cinfo->col_buf[col], COL_MAX_LEN, "%s",
-            val_to_str(pinfo->circuit_id, channel_vals, "Unknown (%u)"));
-    g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "isdn.channel",
-       COL_MAX_LEN);
-    g_snprintf(pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN, "%u", pinfo->circuit_id);
-    break;
-
-  case CT_X25:
-    g_snprintf(pinfo->cinfo->col_buf[col], COL_MAX_LEN, "%u", pinfo->circuit_id);
-    break;
-
-  case CT_ISUP:
-    g_snprintf(pinfo->cinfo->col_buf[col], COL_MAX_LEN, "%u", pinfo->circuit_id);
-    g_strlcpy(pinfo->cinfo->col_expr.col_expr[col], "isup.cic", COL_MAX_LEN);
-    g_snprintf(pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN, "%u", pinfo->circuit_id);
+      pinfo->cinfo->col_expr.col_expr[col] = "usb.dst.endpoint";
     break;
 
   default:
@@ -1349,14 +1566,22 @@ col_set_circuit_id(packet_info *pinfo, int col)
 }
 
 gboolean
-col_based_on_frame_data(column_info *cinfo, gint col)
+col_based_on_frame_data(column_info *cinfo, const gint col)
 {
-    if (col_has_time_fmt(cinfo, col))
-        return TRUE;
+    g_assert(cinfo);
+    g_assert(col < cinfo->num_cols);
 
     switch (cinfo->col_fmt[col]) {
 
     case COL_NUMBER:
+    case COL_CLS_TIME:
+    case COL_ABS_TIME:
+    case COL_ABS_DATE_TIME:
+    case COL_UTC_TIME:
+    case COL_UTC_DATE_TIME:
+    case COL_REL_TIME:
+    case COL_DELTA_TIME:
+    case COL_DELTA_TIME_DIS:
     case COL_PACKET_LENGTH:
     case COL_CUMULATIVE_BYTES:
       return TRUE;
@@ -1367,45 +1592,77 @@ col_based_on_frame_data(column_info *cinfo, gint col)
 }
 
 void
-col_fill_in_frame_data(frame_data *fd, column_info *cinfo, gint col)
+col_fill_in_frame_data(const frame_data *fd, column_info *cinfo, const gint col, const gboolean fill_col_exprs)
 {
     switch (cinfo->col_fmt[col]) {
 
     case COL_NUMBER:
-      g_snprintf(cinfo->col_buf[col], COL_MAX_LEN, "%u", fd->num);
+      guint32_to_str_buf(fd->num, cinfo->col_buf[col], COL_MAX_LEN);
       cinfo->col_data[col] = cinfo->col_buf[col];
-      g_strlcpy(cinfo->col_expr.col_expr[col], "frame.number", COL_MAX_LEN);
-      g_strlcpy(cinfo->col_expr.col_expr_val[col], cinfo->col_buf[col], COL_MAX_LEN);
       break;
 
     case COL_CLS_TIME:
     case COL_ABS_TIME:
     case COL_ABS_DATE_TIME:
+    case COL_UTC_TIME:
+    case COL_UTC_DATE_TIME:
     case COL_REL_TIME:
     case COL_DELTA_TIME:
     case COL_DELTA_TIME_DIS:
+       /* TODO: Pass on fill_col_exprs */
       col_set_fmt_time(fd, cinfo, cinfo->col_fmt[col], col);
       break;
 
     case COL_PACKET_LENGTH:
-      g_snprintf(cinfo->col_buf[col], COL_MAX_LEN, "%u", fd->pkt_len);
+      guint32_to_str_buf(fd->pkt_len, cinfo->col_buf[col], COL_MAX_LEN);
       cinfo->col_data[col] = cinfo->col_buf[col];
-      g_strlcpy(cinfo->col_expr.col_expr[col], "frame.len", COL_MAX_LEN);
-      g_strlcpy(cinfo->col_expr.col_expr_val[col], cinfo->col_buf[col], COL_MAX_LEN);
       break;
 
     case COL_CUMULATIVE_BYTES:
-      g_snprintf(cinfo->col_buf[col], COL_MAX_LEN, "%u", fd->cum_bytes);
+      guint32_to_str_buf(fd->cum_bytes, cinfo->col_buf[col], COL_MAX_LEN);
       cinfo->col_data[col] = cinfo->col_buf[col];
       break;
 
     default:
       break;
     }
+
+    if (!fill_col_exprs)
+        return;
+
+    switch (cinfo->col_fmt[col]) {
+
+    case COL_NUMBER:
+      cinfo->col_expr.col_expr[col] = "frame.number";
+      g_strlcpy(cinfo->col_expr.col_expr_val[col], cinfo->col_buf[col], COL_MAX_LEN);
+      break;
+
+    case COL_CLS_TIME:
+    case COL_ABS_TIME:
+    case COL_ABS_DATE_TIME:
+    case COL_UTC_TIME:
+    case COL_UTC_DATE_TIME:
+    case COL_REL_TIME:
+    case COL_DELTA_TIME:
+    case COL_DELTA_TIME_DIS:
+      /* Already handled above */
+      break;
+
+    case COL_PACKET_LENGTH:
+      cinfo->col_expr.col_expr[col] = "frame.len";
+      g_strlcpy(cinfo->col_expr.col_expr_val[col], cinfo->col_buf[col], COL_MAX_LEN);
+      break;
+
+    case COL_CUMULATIVE_BYTES:
+      break;
+
+    default:
+      break;
+    }
 }
 
 void
-col_fill_in(packet_info *pinfo, gboolean fill_fd_colums)
+col_fill_in(packet_info *pinfo, const gboolean fill_col_exprs, const gboolean fill_fd_colums)
 {
   int i;
 
@@ -1416,174 +1673,439 @@ col_fill_in(packet_info *pinfo, gboolean fill_fd_colums)
     switch (pinfo->cinfo->col_fmt[i]) {
 
     case COL_NUMBER:
-      if (fill_fd_colums)
-        col_fill_in_frame_data(pinfo->fd, pinfo->cinfo, i);
-      break;
-
     case COL_CLS_TIME:
     case COL_ABS_TIME:
     case COL_ABS_DATE_TIME:
+    case COL_UTC_TIME:
+    case COL_UTC_DATE_TIME:
     case COL_REL_TIME:
     case COL_DELTA_TIME:
     case COL_DELTA_TIME_DIS:
+    case COL_PACKET_LENGTH:
+    case COL_CUMULATIVE_BYTES:
       if (fill_fd_colums)
-        col_fill_in_frame_data(pinfo->fd, pinfo->cinfo, i);
+        col_fill_in_frame_data(pinfo->fd, pinfo->cinfo, i, fill_col_exprs);
       break;
 
-    case COL_REL_CONV_TIME:
-    case COL_DELTA_CONV_TIME:
-      break;           /* Will be set by various dissectors */
-
     case COL_DEF_SRC:
-    case COL_RES_SRC:  /* COL_DEF_SRC is currently just like COL_RES_SRC */
-      col_set_addr(pinfo, i, &pinfo->src, TRUE, TRUE);
+    case COL_RES_SRC:   /* COL_DEF_SRC is currently just like COL_RES_SRC */
+      col_set_addr(pinfo, i, &pinfo->src, TRUE, fill_col_exprs);
       break;
 
     case COL_UNRES_SRC:
-      col_set_addr(pinfo, i, &pinfo->src, FALSE, TRUE);
+      col_set_addr(pinfo, i, &pinfo->src, TRUE, fill_col_exprs);
       break;
 
     case COL_DEF_DL_SRC:
     case COL_RES_DL_SRC:
-      col_set_addr(pinfo, i, &pinfo->dl_src, TRUE, TRUE);
+      col_set_addr(pinfo, i, &pinfo->dl_src, TRUE, fill_col_exprs);
       break;
 
     case COL_UNRES_DL_SRC:
-      col_set_addr(pinfo, i, &pinfo->dl_src, FALSE, TRUE);
+      col_set_addr(pinfo, i, &pinfo->dl_src, TRUE, fill_col_exprs);
       break;
 
     case COL_DEF_NET_SRC:
     case COL_RES_NET_SRC:
-      col_set_addr(pinfo, i, &pinfo->net_src, TRUE, TRUE);
+      col_set_addr(pinfo, i, &pinfo->net_src, TRUE, fill_col_exprs);
       break;
 
     case COL_UNRES_NET_SRC:
-      col_set_addr(pinfo, i, &pinfo->net_src, FALSE, TRUE);
+      col_set_addr(pinfo, i, &pinfo->net_src, TRUE, fill_col_exprs);
       break;
 
     case COL_DEF_DST:
-    case COL_RES_DST:  /* COL_DEF_DST is currently just like COL_RES_DST */
-      col_set_addr(pinfo, i, &pinfo->dst, TRUE, FALSE);
+    case COL_RES_DST:   /* COL_DEF_DST is currently just like COL_RES_DST */
+      col_set_addr(pinfo, i, &pinfo->dst, FALSE, fill_col_exprs);
       break;
 
     case COL_UNRES_DST:
-      col_set_addr(pinfo, i, &pinfo->dst, FALSE, FALSE);
+      col_set_addr(pinfo, i, &pinfo->dst, FALSE, fill_col_exprs);
       break;
 
     case COL_DEF_DL_DST:
     case COL_RES_DL_DST:
-      col_set_addr(pinfo, i, &pinfo->dl_dst, TRUE, FALSE);
+      col_set_addr(pinfo, i, &pinfo->dl_dst, FALSE, fill_col_exprs);
       break;
 
     case COL_UNRES_DL_DST:
-      col_set_addr(pinfo, i, &pinfo->dl_dst, FALSE, FALSE);
+      col_set_addr(pinfo, i, &pinfo->dl_dst, FALSE, fill_col_exprs);
       break;
 
     case COL_DEF_NET_DST:
     case COL_RES_NET_DST:
-      col_set_addr(pinfo, i, &pinfo->net_dst, TRUE, FALSE);
+      col_set_addr(pinfo, i, &pinfo->net_dst, FALSE, fill_col_exprs);
       break;
 
     case COL_UNRES_NET_DST:
-      col_set_addr(pinfo, i, &pinfo->net_dst, FALSE, FALSE);
+      col_set_addr(pinfo, i, &pinfo->net_dst, FALSE, fill_col_exprs);
       break;
 
     case COL_DEF_SRC_PORT:
-    case COL_RES_SRC_PORT:     /* COL_DEF_SRC_PORT is currently just like COL_RES_SRC_PORT */
-      col_set_port(pinfo, i, TRUE, TRUE);
+    case COL_RES_SRC_PORT:  /* COL_DEF_SRC_PORT is currently just like COL_RES_SRC_PORT */
+      col_set_port(pinfo, i, TRUE, TRUE, fill_col_exprs);
       break;
 
     case COL_UNRES_SRC_PORT:
-      col_set_port(pinfo, i, FALSE, TRUE);
+      col_set_port(pinfo, i, FALSE, TRUE, fill_col_exprs);
       break;
 
     case COL_DEF_DST_PORT:
-    case COL_RES_DST_PORT:     /* COL_DEF_DST_PORT is currently just like COL_RES_DST_PORT */
-      col_set_port(pinfo, i, TRUE, FALSE);
+    case COL_RES_DST_PORT:  /* COL_DEF_DST_PORT is currently just like COL_RES_DST_PORT */
+      col_set_port(pinfo, i, TRUE, FALSE, fill_col_exprs);
       break;
 
     case COL_UNRES_DST_PORT:
-      col_set_port(pinfo, i, FALSE, FALSE);
+      col_set_port(pinfo, i, FALSE, FALSE, fill_col_exprs);
       break;
 
-    case COL_PROTOCOL: /* currently done by dissectors */
-    case COL_INFO:     /* currently done by dissectors */
+    case COL_VSAN:
+      guint32_to_str_buf(pinfo->vsan, pinfo->cinfo->col_buf[i], COL_MAX_LEN);
+      pinfo->cinfo->col_data[i] = pinfo->cinfo->col_buf[i];
       break;
 
+    case NUM_COL_FMTS:  /* keep compiler happy - shouldn't get here */
+      g_assert_not_reached();
+      break;
+    default:
+      if (pinfo->cinfo->col_fmt[i] >= NUM_COL_FMTS) {
+        g_assert_not_reached();
+      }
+      /*
+       * Formatting handled by col_custom_set_edt() (COL_CUSTOM), expert.c
+       * (COL_EXPERT), or individual dissectors.
+       */
+      break;
+    }
+  }
+}
+
+/*
+ * Fill in columns if we got an error reading the packet.
+ * We set most columns to "???", and set the Info column to an error
+ * message.
+ */
+void
+col_fill_in_error(column_info *cinfo, frame_data *fdata, const gboolean fill_col_exprs, const gboolean fill_fd_colums)
+{
+  int i;
+
+  if (!cinfo)
+    return;
+
+  for (i = 0; i < cinfo->num_cols; i++) {
+    switch (cinfo->col_fmt[i]) {
+
+    case COL_NUMBER:
+    case COL_CLS_TIME:
+    case COL_ABS_TIME:
+    case COL_ABS_DATE_TIME:
+    case COL_UTC_TIME:
+    case COL_UTC_DATE_TIME:
+    case COL_REL_TIME:
+    case COL_DELTA_TIME:
+    case COL_DELTA_TIME_DIS:
     case COL_PACKET_LENGTH:
     case COL_CUMULATIVE_BYTES:
       if (fill_fd_colums)
-        col_fill_in_frame_data(pinfo->fd, pinfo->cinfo, i);
+        col_fill_in_frame_data(fdata, cinfo, i, fill_col_exprs);
       break;
 
-    case COL_OXID:
-      g_snprintf(pinfo->cinfo->col_buf[i], COL_MAX_LEN, "0x%x", pinfo->oxid);
-      pinfo->cinfo->col_data[i] = pinfo->cinfo->col_buf[i];
+    case COL_INFO:
+      /* XXX - say more than this */
+      cinfo->col_data[i] = "Read error";
       break;
 
-    case COL_RXID:
-      g_snprintf(pinfo->cinfo->col_buf[i], COL_MAX_LEN, "0x%x", pinfo->rxid);
-      pinfo->cinfo->col_data[i] = pinfo->cinfo->col_buf[i];
+    case NUM_COL_FMTS:  /* keep compiler happy - shouldn't get here */
+      g_assert_not_reached();
+      break;
+    default:
+      if (cinfo->col_fmt[i] >= NUM_COL_FMTS) {
+        g_assert_not_reached();
+      }
+      /*
+       * No dissection was done, and these columns are set as the
+       * result of the dissection, so....
+       */
+      cinfo->col_data[i] = "???";
       break;
+    }
+  }
+}
+
+#if 0
+XXX this needs more rework?
+/* --------------------------- */
+
+static  gchar *
+set_addr(address *addr, gboolean is_res)
+{
+  if (addr->type == AT_NONE)
+    return "";  /* no address, nothing to do */
+
+  if (is_res) {
+    return se_get_addr_name(addr /*, COL_MAX_LEN*/);
+  }
+  return se_address_to_str(addr);
+}
 
-    case COL_IF_DIR:   /* currently done by dissectors */
+/* Fills col_text in the frame data structure */
+void
+col_fill_fdata(packet_info *pinfo)
+{
+  int i;
+  frame_data *fdata;
+  gboolean res;
+
+  if (!pinfo->cinfo)
+    return;
+
+  fdata = pinfo->fd;
+
+  res =FALSE;
+
+  for (i = 0; i < pinfo->cinfo->num_cols; i++) {
+
+    switch (pinfo->cinfo->col_fmt[i]) {
+    case COL_NUMBER:           /* frame number */
+    case COL_PACKET_LENGTH:    /* fd->pkt_len */
+    case COL_CUMULATIVE_BYTES: /* fd->cum_bytes */
+    case COL_CLS_TIME:
+    case COL_ABS_TIME:
+    case COL_ABS_DATE_TIME:
+    case COL_UTC_TIME:
+    case COL_UTC_DATE_TIME:  /* from fd structures */
+    case COL_REL_TIME:
+    case COL_DELTA_TIME:
+    case COL_DELTA_TIME_DIS:
       break;
 
-    case COL_CIRCUIT_ID:
-      col_set_circuit_id(pinfo, i);
+    case COL_DEF_SRC:
+    case COL_RES_SRC:   /* COL_DEF_SRC is currently just like COL_RES_SRC */
+      res = TRUE;
+    case COL_UNRES_SRC:
+      fdata->col_text[i] = set_addr(&pinfo->src, res);
       break;
 
-    case COL_SRCIDX:
-      g_snprintf(pinfo->cinfo->col_buf[i], COL_MAX_LEN, "0x%x", pinfo->src_idx);
-      pinfo->cinfo->col_data[i] = pinfo->cinfo->col_buf[i];
+    case COL_DEF_DL_SRC:
+    case COL_RES_DL_SRC:
+      res = TRUE;
+    case COL_UNRES_DL_SRC:
+      fdata->col_text[i] = set_addr (&pinfo->dl_src, res);
       break;
 
-    case COL_DSTIDX:
-      g_snprintf(pinfo->cinfo->col_buf[i], COL_MAX_LEN, "0x%x", pinfo->dst_idx);
-      pinfo->cinfo->col_data[i] = pinfo->cinfo->col_buf[i];
+    case COL_DEF_NET_SRC:
+    case COL_RES_NET_SRC:
+      res = TRUE;
+    case COL_UNRES_NET_SRC:
+      fdata->col_text[i] = set_addr (&pinfo->net_src, res);
       break;
 
-    case COL_VSAN:
-      g_snprintf(pinfo->cinfo->col_buf[i], COL_MAX_LEN, "%u", pinfo->vsan);
-      pinfo->cinfo->col_data[i] = pinfo->cinfo->col_buf[i];
+    case COL_DEF_DST:
+    case COL_RES_DST:   /* COL_DEF_DST is currently just like COL_RES_DST */
+      res = TRUE;
+    case COL_UNRES_DST:
+      fdata->col_text[i] = set_addr (&pinfo->dst, res);
+      break;
+
+    case COL_DEF_DL_DST:
+    case COL_RES_DL_DST:
+      res = TRUE;
+    case COL_UNRES_DL_DST:
+      fdata->col_text[i] = set_addr (&pinfo->dl_dst, res);
       break;
 
-    case COL_HPUX_SUBSYS: /* done by nettl disector */
-    case COL_HPUX_DEVID:  /* done by nettl disector */
+    case COL_DEF_NET_DST:
+    case COL_RES_NET_DST:
+      res = TRUE;
+    case COL_UNRES_NET_DST:
+      fdata->col_text[i] = set_addr (&pinfo->net_dst, res);
       break;
 
-    case COL_DCE_CALL: /* done by dcerpc */
+    case COL_DEF_SRC_PORT:
+    case COL_RES_SRC_PORT:  /* COL_DEF_SRC_PORT is currently just like COL_RES_SRC_PORT */
+      fdata->col_text[i] = set_port(pinfo, TRUE, pinfo->srcport);
+      break;
+    case COL_UNRES_SRC_PORT:
+      fdata->col_text[i] = set_port(pinfo, FALSE, pinfo->srcport);
       break;
 
-    case COL_DCE_CTX:  /* done by dcerpc */
+    case COL_DEF_DST_PORT:
+    case COL_RES_DST_PORT:  /* COL_DEF_DST_PORT is currently just like COL_RES_DST_PORT */
+      fdata->col_text[i] = set_port(pinfo, TRUE, pinfo->destport);
+      break;
+
+    case COL_UNRES_DST_PORT:
+      fdata->col_text[i] = set_port(pinfo, FALSE, pinfo->destport);
       break;
 
+    case COL_IF_DIR:    /* currently done by dissectors */
+    case COL_PROTOCOL:
+    case COL_INFO:
+    case COL_HPUX_SUBSYS:
+    case COL_HPUX_DEVID:
+    case COL_DCE_CALL:
     case COL_8021Q_VLAN_ID:
-        break;
+    case COL_DSCP_VALUE:
+    case COL_COS_VALUE:
+    case COL_FR_DLCI:
+    case COL_BSSGP_TLLI:
+    case COL_EXPERT:
+    case COL_CUSTOM:
+    case COL_FREQ_CHAN:
+      if (pinfo->cinfo->col_data[i] != pinfo->cinfo->col_buf[i]) {
+         /* XXX assume it's a constant */
+         fdata->col_text[i] = (gchar *)pinfo->cinfo->col_data[i];
+      }
+      else {
+         /* copy */
+         fdata->col_text[i] = se_strdup(pinfo->cinfo->col_data[i]);
+      }
+      break;
+    case COL_OXID:
+      fdata->col_text[i] = (gchar *)(GUINT_TO_POINTER((guint)pinfo->oxid));
+      break;
+    case COL_RXID:
+      fdata->col_text[i] = (gchar *)(GUINT_TO_POINTER((guint)pinfo->rxid));
+      break;
+    case COL_CIRCUIT_ID:
+      set_circuit_id(pinfo);
+      break;
+    case COL_SRCIDX:
+      fdata->col_text[i] = (gchar *)(GUINT_TO_POINTER((guint)pinfo->src_idx));
+      break;
+    case COL_DSTIDX:
+      fdata->col_text[i] = (gchar *)(GUINT_TO_POINTER((guint)pinfo->dst_idx));
+      break;
+    case COL_VSAN:
+      fdata->col_text[i] = (gchar *)(GUINT_TO_POINTER((guint)pinfo->vsan));
+      break;
 
-    case COL_DSCP_VALUE:       /* done by packet-ip.c */
-       break;
+    case NUM_COL_FMTS:  /* keep compiler happy - shouldn't get here */
+      g_assert_not_reached();
+      break;
+    }
+  }
+}
 
-    case COL_COS_VALUE:                /* done by packet-vlan.c */
-       break;
+/* XXX Gets/creates the text from col_text in frame data */
+/* --------------------- */
+gchar *
+col_get_text(frame_data *fd, column_info *cinfo, gint col)
+{
+static gchar fmtbuf[3][COL_MAX_LEN];
+static int idx;
+gchar  *buf;
+gchar  *ptr;
 
-    case COL_FR_DLCI:  /* done by packet-fr.c */
-    case COL_BSSGP_TLLI: /* done by packet-bssgp.c */
-        break;
+    idx = (idx + 1) % 3;
+    buf = fmtbuf[idx];
+    *buf = 0;
+    ptr = buf;
 
-    case COL_EXPERT:    /* done by expert.c */
-        break;
+    switch (cinfo->col_fmt[col]) {
+    case COL_NUMBER: /* frame number */
+      guint32_to_str_buf(fd->num, buf, COL_MAX_LEN);
+      break;
 
-    case COL_FREQ_CHAN:    /* done by radio dissectors */
-        break;
+    case COL_CLS_TIME:
+      set_cls_time(fd, buf);
+      break;
+    case COL_ABS_TIME:
+      set_abs_time(fd, buf, TRUE);
+      break;
+    case COL_UTC_TIME:
+      set_abs_time(fd, buf, FALSE);
+      break;
+    case COL_ABS_DATE_TIME:
+      set_abs_date_time(fd, buf, TRUE);
+      break;
+    case COL_UTC_DATE_TIME:
+      set_abs_date_time(fd, buf, FALSE);
+      break;
+    case COL_REL_TIME:
+      set_rel_time(fd, buf);
+      break;
+    case COL_DELTA_TIME:
+      set_delta_time(fd, buf);
+      break;
+    case COL_DELTA_TIME_DIS:
+      set_delta_time_dis(fd, buf);
+      break;
+
+    case COL_PACKET_LENGTH: /* fd->pkt_len */
+      guint32_to_str_buf(fd->pkt_len, buf, COL_MAX_LEN);
+      break;
 
-    case COL_CUSTOM:     /* done by col_custom_set_fstr() called from proto.c */
-       break;
+    case COL_CUMULATIVE_BYTES: /* fd->cum_bytes */
+      guint32_to_str_buf(fd->cum_bytes, buf, COL_MAX_LEN);
+      break;
 
-    case NUM_COL_FMTS: /* keep compiler happy - shouldn't get here */
+    case COL_DEF_SRC:
+    case COL_RES_SRC:   /* network address */
+    case COL_UNRES_SRC:
+    case COL_DEF_DL_SRC:
+    case COL_RES_DL_SRC:
+    case COL_UNRES_DL_SRC:
+    case COL_DEF_NET_SRC:
+    case COL_RES_NET_SRC:
+    case COL_UNRES_NET_SRC:
+    case COL_DEF_DST:
+    case COL_RES_DST:
+    case COL_UNRES_DST:
+    case COL_DEF_DL_DST:
+    case COL_RES_DL_DST:
+    case COL_UNRES_DL_DST:
+    case COL_DEF_NET_DST:
+    case COL_RES_NET_DST:
+    case COL_UNRES_NET_DST:
+
+    case COL_IF_DIR:
+    case COL_CIRCUIT_ID:
+    case COL_PROTOCOL:
+    case COL_INFO:
+    case COL_HPUX_SUBSYS:
+    case COL_HPUX_DEVID:
+    case COL_DCE_CALL:
+    case COL_8021Q_VLAN_ID:
+    case COL_DSCP_VALUE:
+    case COL_COS_VALUE:
+    case COL_FR_DLCI:
+    case COL_BSSGP_TLLI:
+    case COL_EXPERT:
+    case COL_CUSTOM:
+    case COL_FREQ_CHAN:
+      ptr = fd->col_text[col];
+      break;
+
+    case COL_DEF_SRC_PORT:
+    case COL_RES_SRC_PORT:
+    case COL_UNRES_SRC_PORT:
+    case COL_DEF_DST_PORT:
+    case COL_RES_DST_PORT:
+    case COL_UNRES_DST_PORT:
+      /* hack */
+      if (GPOINTER_TO_UINT(fd->col_text[col]) <= 65536)
+          guint32_to_str_buf(GPOINTER_TO_UINT(fd->col_text[col], buf, COL_MAX_LEN));
+      else
+          ptr = fd->col_text[col];
+      break;
+
+    case COL_OXID:
+    case COL_RXID:
+    case COL_SRCIDX:
+    case COL_DSTIDX:
+      g_snprintf(buf, COL_MAX_LEN, "0x%x", GPOINTER_TO_UINT(fd->col_text[col]));
+      break;
+
+    case COL_VSAN:
+      guint32_to_str_buf(GPOINTER_TO_UINT(fd->col_text[col]), buf, COL_MAX_LEN);
+      break;
+
+    case NUM_COL_FMTS:  /* keep compiler happy - shouldn't get here */
       g_assert_not_reached();
       break;
     }
-  }
+    return ptr;
 }
-
+#endif