Avoid a buffer overflow in the cseq_method field, a fixed-length character array.
[obnox/wireshark/wip.git] / tethereal.c
index 2590be2025ba9196605e02289adea777206b1140..22495ff100d00a399bc3dc3d36dcde99f9b3f32a 100644 (file)
@@ -1,6 +1,6 @@
 /* tethereal.c
  *
- * $Id: tethereal.c,v 1.221 2004/01/18 04:13:44 guy Exp $
+ * $Id$
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -68,7 +68,7 @@
 #include "getopt.h"
 #endif
 
-#include "cvsversion.h"
+#include "svnversion.h"
 
 #include <glib.h>
 #include <epan/epan.h>
 #include <epan/packet.h>
 #include "file.h"
 #include "disabled_protos.h"
-#include "prefs.h"
-#include "column.h"
+#include <epan/prefs.h>
+#include <epan/column.h>
 #include "print.h"
-#include <epan/resolv.h>
+#include <epan/addr_resolv.h>
 #include "util.h"
+#include "clopts_common.h"
 #include "version_info.h"
-#ifdef HAVE_LIBPCAP
-#include "pcap-util.h"
-#endif
 #include <epan/conversation.h>
 #include <epan/plugins.h>
 #include "register.h"
 #include "conditions.h"
 #include "capture_stop_conditions.h"
 #include "ringbuffer.h"
+#include "capture_ui_utils.h"
 #include <epan/epan_dissect.h>
-#include "tap.h"
+#include <epan/tap.h>
+#include <epan/timestamp.h>
 
 #ifdef HAVE_LIBPCAP
+#include <pcap.h>
+#include "pcap-util.h"
 #include <wiretap/wtap-capture.h>
 #include <wiretap/libpcap.h>
-#endif
-
 #ifdef _WIN32
 #include "capture-wpcap.h"
 #endif
+#include "capture.h"
+#endif
+
 
 /*
  * This is the template for the decode as option; it is shared between the
  * various functions that output the usage for this parameter.
  */
 static const gchar decode_as_arg_template[] = "<layer_type>==<selector>,<decode_as_protocol>";
+
 static guint32 firstsec, firstusec;
 static guint32 prevsec, prevusec;
 static GString *comp_info_str, *runtime_info_str;
-static gboolean quiet;
-static gboolean decode;
+
+static gboolean print_packet_info;     /* TRUE if we're to print packet information */
+/*
+ * The way the packet decode is to be written.
+ */
+typedef enum {
+       WRITE_TEXT,     /* summary or detail text */
+       WRITE_XML       /* PDML or PSML */
+       /* Add CSV and the like here */
+} output_action_e;
+static output_action_e output_action;
+static gboolean do_dissection; /* TRUE if we have to dissect each packet */
 static gboolean verbose;
 static gboolean print_hex;
 static gboolean line_buffered;
-static guint32 cul_bytes = 0;
-static int print_format;
+static guint32 cum_bytes = 0;
+static print_format_e print_format = PR_FMT_TEXT;
+static print_stream_t *print_stream;
 
 #ifdef HAVE_LIBPCAP
+/*
+ * TRUE if we're to print packet counts to keep track of captured packets.
+ */
+static gboolean print_packet_counts;
+
 typedef struct _loop_data {
   gboolean       go;           /* TRUE as long as we're supposed to keep capturing */
   gint           linktype;
   gboolean       from_pipe;    /* TRUE if we are capturing data from a pipe */
   pcap_t        *pch;
+  char          *save_file;    /* Name of file to which we're writing */
   wtap_dumper   *pdh;
   jmp_buf        stopenv;
   gboolean       output_to_pipe;
@@ -140,14 +161,24 @@ typedef struct _loop_data {
          STATE_EXPECT_REC_HDR, STATE_READ_REC_HDR,
          STATE_EXPECT_DATA,     STATE_READ_DATA
        } pipe_state;
-
   enum { PIPOK, PIPEOF, PIPERR, PIPNEXIST } pipe_err;
 #endif
 } loop_data;
 
 static loop_data ld;
 
-static int capture(int);
+#ifdef HAVE_LIBPCAP
+static capture_options capture_opts;
+
+
+#ifdef SIGINFO
+static gboolean infodelay;     /* if TRUE, don't print capture info in SIGINFO handler */
+static gboolean infoprint;     /* if TRUE, print capture info after clearing infodelay */
+#endif /* SIGINFO */
+#endif /* HAVE_LIBPCAP */
+
+
+static int capture(char *, int);
 static void capture_pcap_cb(guchar *, const struct pcap_pkthdr *,
   const guchar *);
 static void report_counts(void);
@@ -161,17 +192,17 @@ static void report_counts_siginfo(int);
 #endif /* _WIN32 */
 #endif /* HAVE_LIBPCAP */
 
-typedef struct {
-  capture_file *cf;
-  wtap_dumper *pdh;
-} cb_args_t;
-
-static int load_cap_file(capture_file *, int);
-static void wtap_dispatch_cb_write(guchar *, const struct wtap_pkthdr *, long,
-    union wtap_pseudo_header *, const guchar *);
+static int load_cap_file(capture_file *, char *, int);
+static gboolean process_packet(capture_file *cf, wtap_dumper *pdh, long offset,
+    const struct wtap_pkthdr *whdr, union wtap_pseudo_header *pseudo_header,
+    const guchar *pd, int *err);
 static void show_capture_file_io_error(const char *, int, gboolean);
-static void wtap_dispatch_cb_print(guchar *, const struct wtap_pkthdr *, long,
-    union wtap_pseudo_header *, const guchar *);
+static void show_print_file_io_error(int err);
+static gboolean write_preamble(capture_file *cf);
+static gboolean print_packet(capture_file *cf, epan_dissect_t *edt);
+static gboolean write_finale(void);
+static char *cf_open_error_message(int err, gchar *err_info,
+    gboolean for_writing, int file_type);
 #ifdef HAVE_LIBPCAP
 #ifndef _WIN32
 static void adjust_header(loop_data *, struct pcap_hdr *, struct pcaprec_hdr *);
@@ -181,54 +212,13 @@ static int pipe_dispatch(int, loop_data *, struct pcap_hdr *, \
 #endif /* _WIN32 */
 #endif
 
-capture_file cfile;
-ts_type timestamp_type = RELATIVE;
-#ifdef HAVE_LIBPCAP
-typedef struct {
-       int snaplen;                    /* Maximum captured packet length */
-       int promisc_mode;               /* Capture in promiscuous mode */
-       int autostop_count;             /* Maximum packet count */
-       gboolean has_autostop_duration; /* TRUE if maximum capture duration
-                                          is specified */
-       gint32 autostop_duration;       /* Maximum capture duration */
-       gboolean has_autostop_filesize; /* TRUE if maximum capture file size
-                                          is specified */
-       gint32 autostop_filesize;       /* Maximum capture file size */
-       gboolean ringbuffer_on;         /* TRUE if ring buffer in use */
-       guint32 ringbuffer_num_files;   /* Number of ring buffer files */
-       gboolean has_ring_duration;     /* TRUE if ring duration specified */
-       gint32 ringbuffer_duration;     /* Switch file after n seconds */
-       int linktype;                   /* Data link type to use, or -1 for
-                                          "use default" */
-} capture_options;
-
-static capture_options capture_opts = {
-       WTAP_MAX_PACKET_SIZE,           /* snapshot length - default is
-                                          infinite, in effect */
-       TRUE,                           /* promiscuous mode is the default */
-       0,                              /* max packet count - default is 0,
-                                          meaning infinite */
-       FALSE,                          /* maximum capture duration not
-                                          specified by default */
-       0,                              /* maximum capture duration */
-       FALSE,                          /* maximum capture file size not
-                                          specified by default */
-       0,                              /* maximum capture file size */
-       FALSE,                          /* ring buffer off by default */
-       RINGBUFFER_MIN_NUM_FILES,       /* default number of ring buffer
-                                          files */
-       FALSE,                          /* Switch ring file after some */
-       0,                              /* specified time is off by default */
-       -1                              /* Default to not change link type */
-};
+static void open_failure_message(const char *filename, int err,
+    gboolean for_writing);
+static void failure_message(const char *msg_format, va_list ap);
+static void read_failure_message(const char *filename, int err);
 
-static gboolean list_link_layer_types;
+capture_file cfile;
 
-#ifdef SIGINFO
-static gboolean infodelay;     /* if TRUE, don't print capture info in SIGINFO handler */
-static gboolean infoprint;     /* if TRUE, print capture info after clearing infodelay */
-#endif /* SIGINFO */
-#endif /* HAVE_LIBPCAP */
 
 static void
 print_usage(gboolean print_ver)
@@ -239,10 +229,12 @@ print_usage(gboolean print_ver)
   if (print_ver) {
     output = stdout;
     fprintf(output, "This is GNU t" PACKAGE " " VERSION
-#ifdef CVSVERSION
-       " (cvs " CVSVERSION ")"
+#ifdef SVNVERSION
+       " (" SVNVERSION ")"
 #endif
+        "\n (C) 1998-2004 Gerald Combs <gerald@ethereal.com>"
        "\n%s\n%s\n",
+
        comp_info_str->str, runtime_info_str->str);
   } else {
     output = stderr;
@@ -255,14 +247,14 @@ print_usage(gboolean print_ver)
   fprintf(output, "\t[ -f <capture filter> ] [ -F <output file type> ] [ -i <interface> ]\n");
   fprintf(output, "\t[ -N <resolving> ] [ -o <preference setting> ] ... [ -r <infile> ]\n");
   fprintf(output, "\t[ -R <read filter> ] [ -s <snaplen> ] [ -t <time stamp format> ]\n");
-  fprintf(output, "\t[ -T pdml|ps|text ] [ -w <savefile> ] [ -y <link type> ]\n");
+  fprintf(output, "\t[ -T pdml|ps|psml|text ] [ -w <savefile> ] [ -y <link type> ]\n");
   fprintf(output, "\t[ -z <statistics string> ]\n");
 #else
   fprintf(output, "\nt%s [ -vh ] [ -lnVx ]\n", PACKAGE);
   fprintf(output, "\t[ -d %s ] ...\n", decode_as_arg_template);
   fprintf(output, "\t[ -F <output file type> ] [ -N <resolving> ]\n");
   fprintf(output, "\t[ -o <preference setting> ] ... [ -r <infile> ] [ -R <read filter> ]\n");
-  fprintf(output, "\t[ -t <time stamp format> ] [ -T pdml|ps|text ] [ -w <savefile> ]\n");
+  fprintf(output, "\t[ -t <time stamp format> ] [ -T pdml|ps|psml|text ] [ -w <savefile> ]\n");
   fprintf(output, "\t[ -z <statistics string> ]\n");
 #endif
   fprintf(output, "Valid file type arguments to the \"-F\" flag:\n");
@@ -274,167 +266,6 @@ print_usage(gboolean print_ver)
   fprintf(output, "\tdefault is libpcap\n");
 }
 
-#ifdef HAVE_LIBPCAP
-static int
-get_natural_int(const char *string, const char *name)
-{
-  long number;
-  char *p;
-
-  number = strtol(string, &p, 10);
-  if (p == string || *p != '\0') {
-    fprintf(stderr, "tethereal: The specified %s \"%s\" is not a decimal number\n",
-           name, string);
-    exit(1);
-  }
-  if (number < 0) {
-    fprintf(stderr, "tethereal: The specified %s is a negative number\n",
-           name);
-    exit(1);
-  }
-  if (number > INT_MAX) {
-    fprintf(stderr, "tethereal: The specified %s is too large (greater than %d)\n",
-           name, INT_MAX);
-    exit(1);
-  }
-  return number;
-}
-
-static int
-get_positive_int(const char *string, const char *name)
-{
-  long number;
-
-  number = get_natural_int(string, name);
-
-  if (number == 0) {
-    fprintf(stderr, "tethereal: The specified %s is zero\n",
-           name);
-    exit(1);
-  }
-
-  return number;
-}
-
-/*
- * Given a string of the form "<autostop criterion>:<value>", as might appear
- * as an argument to a "-a" option, parse it and set the criterion in
- * question.  Return an indication of whether it succeeded or failed
- * in some fashion.
- */
-static gboolean
-set_autostop_criterion(const char *autostoparg)
-{
-  guchar *p, *colonp;
-
-  colonp = strchr(autostoparg, ':');
-  if (colonp == NULL)
-    return FALSE;
-
-  p = colonp;
-  *p++ = '\0';
-
-  /*
-   * Skip over any white space (there probably won't be any, but
-   * as we allow it in the preferences file, we might as well
-   * allow it here).
-   */
-  while (isspace(*p))
-    p++;
-  if (*p == '\0') {
-    /*
-     * Put the colon back, so if our caller uses, in an
-     * error message, the string they passed us, the message
-     * looks correct.
-     */
-    *colonp = ':';
-    return FALSE;
-  }
-  if (strcmp(autostoparg,"duration") == 0) {
-    capture_opts.has_autostop_duration = TRUE;
-    capture_opts.autostop_duration = get_positive_int(p,"autostop duration");
-  } else if (strcmp(autostoparg,"filesize") == 0) {
-    capture_opts.has_autostop_filesize = TRUE;
-    capture_opts.autostop_filesize = get_positive_int(p,"autostop filesize");
-  } else {
-    return FALSE;
-  }
-  *colonp = ':';       /* put the colon back */
-  return TRUE;
-}
-
-/*
- * Given a string of the form "<ring buffer file>:<duration>", as might appear
- * as an argument to a "-b" option, parse it and set the arguments in
- * question.  Return an indication of whether it succeeded or failed
- * in some fashion.
- */
-static gboolean
-get_ring_arguments(const char *arg)
-{
-  guchar *p = NULL, *colonp;
-
-  colonp = strchr(arg, ':');
-
-  if (colonp != NULL) {
-    p = colonp;
-    *p++ = '\0';
-  }
-
-  capture_opts.ringbuffer_num_files = 
-    get_natural_int(arg, "number of ring buffer files");
-
-  if (colonp == NULL)
-    return TRUE;
-
-  /*
-   * Skip over any white space (there probably won't be any, but
-   * as we allow it in the preferences file, we might as well
-   * allow it here).
-   */
-  while (isspace(*p))
-    p++;
-  if (*p == '\0') {
-    /*
-     * Put the colon back, so if our caller uses, in an
-     * error message, the string they passed us, the message
-     * looks correct.
-     */
-    *colonp = ':';
-    return FALSE;
-  }
-
-  capture_opts.has_ring_duration = TRUE;
-  capture_opts.ringbuffer_duration = get_positive_int(p,
-                                                     "ring buffer duration");
-
-  *colonp = ':';       /* put the colon back */
-  return TRUE;
-}
-#endif
-
-/* structure to keep track of what tap listeners have been registered.
- */
-typedef struct _ethereal_tap_list {
-       struct _ethereal_tap_list *next;
-       char *cmd;
-       void (*func)(char *arg);
-} ethereal_tap_list;
-static ethereal_tap_list *tap_list=NULL;
-
-void
-register_ethereal_tap(char *cmd, void (*func)(char *arg))
-{
-       ethereal_tap_list *newtl;
-
-       newtl=malloc(sizeof(ethereal_tap_list));
-       newtl->next=tap_list;
-       tap_list=newtl;
-       newtl->cmd=cmd;
-       newtl->func=func;
-
-}
-
 /*
  * For a dissector table, print on the stream described by output,
  * its short name (which is what's used in the "-d" option) and its
@@ -806,12 +637,17 @@ main(int argc, char *argv[])
   long                 adapter_index;
   char                *p;
   gchar                err_str[PCAP_ERRBUF_SIZE];
+  gchar               *cant_get_if_list_errstr;
+  gboolean             list_link_layer_types = FALSE;
 #else
   gboolean             capture_option_specified = FALSE;
 #endif
+  gboolean             quiet = FALSE;
+  gchar               *save_file = NULL;
   int                  out_file_type = WTAP_FILE_PCAP;
   gchar               *cf_name = NULL, *rfilter = NULL;
 #ifdef HAVE_LIBPCAP
+  gboolean             start_capture = FALSE;
   gchar               *if_text;
   GList               *lt_list, *lt_entry;
   data_link_info_t    *data_link_info;
@@ -822,16 +658,27 @@ main(int argc, char *argv[])
   dfilter_t           *rfcode = NULL;
   e_prefs             *prefs;
   char                 badopt;
-  ethereal_tap_list *tli;
+  
+#ifdef HAVE_LIBPCAP
+  capture_opts_init(&capture_opts, NULL /* cfile */);
+#endif
+
+  set_timestamp_setting(TS_RELATIVE);
 
   /* Register all dissectors; we must do this before checking for the
      "-G" flag, as the "-G" flag dumps information registered by the
      dissectors, and we must do it before we read the preferences, in
      case any dissectors register preferences. */
-  epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs);
+  epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs,
+            failure_message,open_failure_message,read_failure_message);
 
   /* Register all tap listeners; we do this before we parse the arguments,
      as the "-z" argument can specify a registered tap. */
+  
+  /* we register the plugin taps before the other taps because
+         stats_tree taps plugins will be registered as tap listeners
+         by stats_tree_stat.c and need to registered before that */
+  register_all_plugin_tap_listeners();
   register_all_tap_listeners();
 
   /* Now register the preferences for any non-dissector modules.
@@ -845,22 +692,7 @@ main(int argc, char *argv[])
 
      We do this here to mirror what happens in the GTK+ version, although
      it's not necessary here. */
-  if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
-    if (argc == 2)
-      proto_registrar_dump_fields();
-    else {
-      if (strcmp(argv[2], "fields") == 0)
-        proto_registrar_dump_fields();
-      else if (strcmp(argv[2], "protocols") == 0)
-        proto_registrar_dump_protocols();
-      else {
-        fprintf(stderr, "tethereal: Invalid \"%s\" option for -G flag\n",
-                argv[2]);
-        exit(1);
-      }
-    }
-    exit(0);
-  }
+  handle_dashG_option(argc, argv, "tethereal");
 
   /* Set the C-language locale to the native environment. */
   setlocale(LC_ALL, "");
@@ -945,32 +777,14 @@ main(int argc, char *argv[])
   while ((opt = getopt(argc, argv, "a:b:c:d:Df:F:hi:lLnN:o:pqr:R:s:St:T:vw:Vxy:z:")) != -1) {
     switch (opt) {
       case 'a':        /* autostop criteria */
-#ifdef HAVE_LIBPCAP
-        if (set_autostop_criterion(optarg) == FALSE) {
-          fprintf(stderr, "tethereal: Invalid or unknown -a flag \"%s\"\n", optarg);
-          exit(1);
-        }
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
-        break;
       case 'b':        /* Ringbuffer option */
-#ifdef HAVE_LIBPCAP
-        capture_opts.ringbuffer_on = TRUE;
-       if (get_ring_arguments(optarg) == FALSE) {
-          fprintf(stderr, "tethereal: Invalid or unknown -b arg \"%s\"\n", optarg);
-          exit(1);
-       }
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
-        break;
       case 'c':        /* Capture xxx packets */
+      case 'f':        /* capture filter */
+      case 'p':        /* Don't capture in promiscuous mode */
+      case 's':        /* Set the snapshot (capture) length */
+      case 'y':        /* Set the pcap data link type */
 #ifdef HAVE_LIBPCAP
-        capture_opts.autostop_count =
-            get_positive_int(optarg, "packet count");
+        capture_opts_add_opt(&capture_opts, "tethereal", opt, optarg, &start_capture);
 #else
         capture_option_specified = TRUE;
         arg_error = TRUE;
@@ -987,8 +801,10 @@ main(int argc, char *argv[])
             switch (err) {
 
             case CANT_GET_INTERFACE_LIST:
-                fprintf(stderr, "tethereal: Can't get list of interfaces: %s\n",
-                       err_str);
+                cant_get_if_list_errstr =
+                    cant_get_if_list_error_message(err_str);
+                fprintf(stderr, "tethereal: %s\n", cant_get_if_list_errstr);
+                g_free(cant_get_if_list_errstr);
                 break;
 
             case NO_INTERFACES_FOUND:
@@ -1013,21 +829,10 @@ main(int argc, char *argv[])
         arg_error = TRUE;
 #endif
         break;
-      case 'f':
-#ifdef HAVE_LIBPCAP
-        capture_filter_specified = TRUE;
-       if (cfile.cfilter)
-               g_free(cfile.cfilter);
-       cfile.cfilter = g_strdup(optarg);
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
-       break;
       case 'F':
         out_file_type = wtap_short_string_to_file_type(optarg);
         if (out_file_type < 0) {
-          fprintf(stderr, "tethereal: \"%s\" is not a valid capture file type\n",
+          fprintf(stderr, "tethereal: \"%s\" isn't a valid capture file type\n",
                        optarg);
           exit(1);
         }
@@ -1068,8 +873,10 @@ main(int argc, char *argv[])
             switch (err) {
 
             case CANT_GET_INTERFACE_LIST:
-                fprintf(stderr, "tethereal: Can't get list of interfaces: %s\n",
-                        err_str);
+                cant_get_if_list_errstr =
+                    cant_get_if_list_error_message(err_str);
+                fprintf(stderr, "tethereal: %s\n", cant_get_if_list_errstr);
+                g_free(cant_get_if_list_errstr);
                 break;
 
             case NO_INTERFACES_FOUND:
@@ -1083,10 +890,10 @@ main(int argc, char *argv[])
             fprintf(stderr, "tethereal: there is no interface with that adapter index\n");
             exit(1);
           }
-          cfile.iface = g_strdup(if_info->name);
+          capture_opts.iface = g_strdup(if_info->name);
           free_interface_list(if_list);
         } else
-          cfile.iface = g_strdup(optarg);
+          capture_opts.iface = g_strdup(optarg);
 #else
         capture_option_specified = TRUE;
         arg_error = TRUE;
@@ -1100,12 +907,11 @@ main(int argc, char *argv[])
           is probably actually better for "-V", as it does fewer
           writes).
 
-          See the comment in "wtap_dispatch_cb_print()" for an
-          explanation of why we do that, and why we don't just
-          use "setvbuf()" to make the standard output line-buffered
-          (short version: in Windows, "line-buffered" is the same
-          as "fully-buffered", and the output buffer is only flushed
-          when it fills up). */
+          See the comment in "process_packet()" for an explanation of
+          why we do that, and why we don't just use "setvbuf()" to
+          make the standard output line-buffered (short version: in
+          Windows, "line-buffered" is the same as "fully-buffered",
+          and the output buffer is only flushed when it fills up). */
        line_buffered = TRUE;
        break;
       case 'L':        /* Print list of link-layer types and exit */
@@ -1146,14 +952,6 @@ main(int argc, char *argv[])
           break;
         }
         break;
-      case 'p':        /* Don't capture in promiscuous mode */
-#ifdef HAVE_LIBPCAP
-       capture_opts.promisc_mode = FALSE;
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
-       break;
       case 'q':        /* Quiet */
         quiet = TRUE;
         break;
@@ -1163,26 +961,18 @@ main(int argc, char *argv[])
       case 'R':        /* Read file filter */
         rfilter = optarg;
         break;
-      case 's':        /* Set the snapshot (capture) length */
-#ifdef HAVE_LIBPCAP
-        capture_opts.snaplen = get_positive_int(optarg, "snapshot length");
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
-        break;
       case 'S':        /* show packets in real time */
-        decode = TRUE;
+        print_packet_info = TRUE;
         break;
       case 't':        /* Time stamp type */
         if (strcmp(optarg, "r") == 0)
-          timestamp_type = RELATIVE;
+          set_timestamp_setting(TS_RELATIVE);
         else if (strcmp(optarg, "a") == 0)
-          timestamp_type = ABSOLUTE;
+          set_timestamp_setting(TS_ABSOLUTE);
         else if (strcmp(optarg, "ad") == 0)
-          timestamp_type = ABSOLUTE_WITH_DATE;
+          set_timestamp_setting(TS_ABSOLUTE_WITH_DATE);
         else if (strcmp(optarg, "d") == 0)
-          timestamp_type = DELTA;
+          set_timestamp_setting(TS_DELTA);
         else {
           fprintf(stderr, "tethereal: Invalid time stamp type \"%s\"\n",
             optarg);
@@ -1192,29 +982,35 @@ main(int argc, char *argv[])
         }
         break;
       case 'T':        /* printing Type */
-        if (strcmp(optarg, "text") == 0)
-               print_format = PR_FMT_TEXT;
-       else if (strcmp(optarg, "pdml") == 0)
-               print_format = PR_FMT_PDML;
-       else if (strcmp(optarg, "ps") == 0)
-               print_format = PR_FMT_PS;
-       else {
-               fprintf(stderr, "tethereal: Invalid -T parameter.\n");
-               fprintf(stderr, "It must be \"ps\", \"text\" or \"pdml\".\n");
-               exit(1);
+        if (strcmp(optarg, "text") == 0) {
+         output_action = WRITE_TEXT;
+         print_format = PR_FMT_TEXT;
+       } else if (strcmp(optarg, "ps") == 0) {
+         output_action = WRITE_TEXT;
+         print_format = PR_FMT_PS;
+       } else if (strcmp(optarg, "pdml") == 0) {
+         output_action = WRITE_XML;
+         verbose = TRUE;
+       } else if (strcmp(optarg, "psml") == 0) {
+         output_action = WRITE_XML;
+         verbose = FALSE;
+       } else {
+         fprintf(stderr, "tethereal: Invalid -T parameter.\n");
+         fprintf(stderr, "It must be \"ps\", \"text\", \"pdml\", or \"psml\".\n");
+         exit(1);
        }
        break;
       case 'v':        /* Show version and exit */
         printf("t" PACKAGE " " VERSION
-#ifdef CVSVERSION
-           " (cvs " CVSVERSION ")"
+#ifdef SVNVERSION
+           " (" SVNVERSION ")"
 #endif
            "\n%s\n%s\n",
            comp_info_str->str, runtime_info_str->str);
         exit(0);
         break;
       case 'w':        /* Write to capture file xxx */
-        cfile.save_file = g_strdup(optarg);
+        save_file = g_strdup(optarg);
        break;
       case 'V':        /* Verbose */
         verbose = TRUE;
@@ -1222,39 +1018,18 @@ main(int argc, char *argv[])
       case 'x':        /* Print packet data in hex (and ASCII) */
         print_hex = TRUE;
         break;
-      case 'y':        /* Set the pcap data link type */
-#ifdef HAVE_LIBPCAP
-#ifdef HAVE_PCAP_DATALINK_NAME_TO_VAL
-        capture_opts.linktype = pcap_datalink_name_to_val(optarg);
-        if (capture_opts.linktype == -1) {
-          fprintf(stderr, "tethereal: The specified data link type \"%s\" is not valid\n",
-                  optarg);
-          exit(1);
-        }
-#else /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
-        /* XXX - just treat it as a number */
-        capture_opts.linktype = get_natural_int(optarg, "data link type");
-#endif /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
-        break;
       case 'z':
-        for(tli=tap_list;tli;tli=tli->next){
-          if(!strncmp(tli->cmd,optarg,strlen(tli->cmd))){
-            (*tli->func)(optarg);
-            break;
-          }
-        }
-        if(!tli){
-          fprintf(stderr,"tethereal: invalid -z argument.\n");
-          fprintf(stderr,"  -z argument must be one of :\n");
-          for(tli=tap_list;tli;tli=tli->next){
-            fprintf(stderr,"     %s\n",tli->cmd);
-          }
-          exit(1);
-        }
+        /* We won't call the init function for the tap this soon
+           as it would disallow MATE's fields (which are registered
+           by the preferences set callback) from being used as
+           part of a tap filter.  Instead, we just add the argument
+           to a list of tap arguments. */
+        if (!process_tap_cmd_arg(optarg)) {
+         fprintf(stderr,"tethereal: invalid -z argument.\n");
+         fprintf(stderr,"  -z argument must be one of :\n");
+         list_tap_cmd_args();
+         exit(1);
+       }
         break;
       default:
       case '?':        /* Bad flag - print usage message */
@@ -1263,10 +1038,6 @@ main(int argc, char *argv[])
     }
   }
 
-  /* If printing PDML or PS, force -V */
-  if (print_format == PR_FMT_PDML || print_format == PR_FMT_PS)
-         verbose = TRUE;
-
   /* If no capture filter or read filter has been specified, and there are
      still command-line arguments, treat them as the tokens of a capture
      filter (if no "-r" flag was specified) or a read filter (if a "-r"
@@ -1286,7 +1057,7 @@ main(int argc, char *argv[])
 "tethereal: Capture filters were specified both with \"-f\" and with additional command-line arguments\n");
         exit(2);
       }
-      cfile.cfilter = get_args_as_string(argc, argv, optind);
+      capture_opts.cfilter = get_args_as_string(argc, argv, optind);
 #else
       capture_option_specified = TRUE;
 #endif
@@ -1297,18 +1068,23 @@ main(int argc, char *argv[])
 #ifdef HAVE_LIBPCAP
   ld.output_to_pipe = FALSE;
 #endif
-  if (cfile.save_file != NULL) {
-    if (strcmp(cfile.save_file, "-") == 0) {
-      /* stdout */
-      g_free(cfile.save_file);
-      cfile.save_file = g_strdup("");
+  if (save_file != NULL) {
+    /* We're writing to a capture file. */
+    if (strcmp(save_file, "-") == 0) {
+      /* Write to the standard output. */
+      g_free(save_file);
+      save_file = g_strdup("");
 #ifdef HAVE_LIBPCAP
+      /* XXX - should we check whether it's a pipe?  It's arguably
+         silly to do "-w - >output_file" rather than "-w output_file",
+         but by not checking we might be violating the Principle Of
+         Least Astonishment. */
       ld.output_to_pipe = TRUE;
 #endif
     }
 #ifdef HAVE_LIBPCAP
     else {
-      err = test_for_fifo(cfile.save_file);
+      err = test_for_fifo(save_file);
       switch (err) {
 
       case ENOENT:     /* it doesn't exist, so we'll be creating it,
@@ -1328,6 +1104,11 @@ main(int argc, char *argv[])
       }
     }
 #endif
+  } else {
+    /* We're not writing to a file, so we should print packet information
+       unless "-q" was specified. */
+    if (!quiet)
+      print_packet_info = TRUE;
   }
 
 #ifndef HAVE_LIBPCAP
@@ -1339,30 +1120,50 @@ main(int argc, char *argv[])
     exit(1);
   }
 
+  /* We don't support capture filters when reading from a capture file
+     (the BPF compiler doesn't support all link-layer types that we
+     support in capture files we read). */
+#ifdef HAVE_LIBPCAP
+  if (cf_name != NULL) {
+    if (capture_filter_specified) {
+      fprintf(stderr,
+"tethereal: Only read filters, not capture filters, can be specified when reading a capture file.\n");
+      exit(2);
+    }
+  }
+#endif
+
+  if (print_hex) {
+    if (output_action != WRITE_TEXT) {
+      fprintf(stderr, "tethereal: Raw packet hex data can only be printed as text or PostScript\n");
+      exit(1);
+    }
+  }
+
 #ifdef HAVE_LIBPCAP
   if (list_link_layer_types) {
     /* We're supposed to list the link-layer types for an interface;
        did the user also specify a capture file to be read? */
     if (cf_name) {
       /* Yes - that's bogus. */
-      fprintf(stderr, "tethereal: You cannot specify -L and a capture file to be read.\n");
+      fprintf(stderr, "tethereal: You can't specify -L and a capture file to be read.\n");
       exit(1);
     }
     /* No - did they specify a ring buffer option? */
-    if (capture_opts.ringbuffer_on) {
-      fprintf(stderr, "tethereal: Ring buffer requested, but a capture is not being done.\n");
+    if (capture_opts.multi_files_on) {
+      fprintf(stderr, "tethereal: Ring buffer requested, but a capture isn't being done.\n");
       exit(1);
     }
   } else {
     /* If they didn't specify a "-w" flag, but specified a maximum capture
        file size, tell them that this doesn't work, and exit. */
-    if (capture_opts.has_autostop_filesize && cfile.save_file == NULL) {
+    if (capture_opts.has_autostop_filesize && save_file == NULL) {
       fprintf(stderr, "tethereal: Maximum capture file size specified, but "
         "capture isn't being saved to a file.\n");
       exit(1);
     }
 
-    if (capture_opts.ringbuffer_on) {
+    if (capture_opts.multi_files_on) {
       /* Ring buffer works only under certain conditions:
         a) ring buffer does not work if you're not saving the capture to
            a file;
@@ -1370,7 +1171,7 @@ main(int argc, char *argv[])
         c) it makes no sense to enable the ring buffer if the maximum
            file size is set to "infinite";
         d) file must not be a pipe. */
-      if (cfile.save_file == NULL) {
+      if (save_file == NULL) {
        fprintf(stderr, "tethereal: Ring buffer requested, but "
          "capture isn't being saved to a file.\n");
        exit(1);
@@ -1404,6 +1205,11 @@ main(int argc, char *argv[])
      line that their preferences have changed. */
   prefs_apply_all();
 
+  /* At this point MATE will have registered its field array so we can
+     have a filter with one of MATE's late-registered fields as part
+     of the tap's filter.  We can now process all the "-z" arguments. */
+  start_requested_taps();
+  
   /* disabled protocols as per configuration file */
   if (gdp_path == NULL && dp_path == NULL) {
     set_disabled_protos_list();
@@ -1446,12 +1252,12 @@ main(int argc, char *argv[])
   else if (capture_opts.snaplen < MIN_PACKET_SIZE)
     capture_opts.snaplen = MIN_PACKET_SIZE;
 
-  /* Check the value range of the ringbuffer_num_files parameter */
-  if (capture_opts.ringbuffer_num_files > RINGBUFFER_MAX_NUM_FILES)
-    capture_opts.ringbuffer_num_files = RINGBUFFER_MAX_NUM_FILES;
+  /* Check the value range of the ring_num_files parameter */
+  if (capture_opts.ring_num_files > RINGBUFFER_MAX_NUM_FILES)
+    capture_opts.ring_num_files = RINGBUFFER_MAX_NUM_FILES;
 #if RINGBUFFER_MIN_NUM_FILES > 0
-  else if (capture_opts.ringbuffer_num_files < RINGBUFFER_MIN_NUM_FILES)
-    capture_opts.ringbuffer_num_files = RINGBUFFER_MIN_NUM_FILES;
+  else if (capture_opts.ring_num_files < RINGBUFFER_MIN_NUM_FILES)
+    capture_opts.ring_num_files = RINGBUFFER_MIN_NUM_FILES;
 #endif
 #endif
 
@@ -1461,16 +1267,16 @@ main(int argc, char *argv[])
       epan_cleanup();
 #ifdef HAVE_PCAP_OPEN_DEAD
       {
-        pcap_t *p;
+        pcap_t *pc;
 
-        p = pcap_open_dead(DLT_EN10MB, MIN_PACKET_SIZE);
-        if (p != NULL) {
-          if (pcap_compile(p, &fcode, rfilter, 0, 0) != -1) {
+        pc = pcap_open_dead(DLT_EN10MB, MIN_PACKET_SIZE);
+        if (pc != NULL) {
+          if (pcap_compile(pc, &fcode, rfilter, 0, 0) != -1) {
             fprintf(stderr,
               "  Note: That display filter code looks like a valid capture filter;\n"
               "        maybe you mixed them up?\n");
           }
-          pcap_close(p);
+          pcap_close(pc);
         }
       }
 #endif
@@ -1478,6 +1284,36 @@ main(int argc, char *argv[])
     }
   }
   cfile.rfcode = rfcode;
+
+  if (print_packet_info) {
+    /* If we're printing as text or PostScript, we have
+       to create a print stream. */
+    if (output_action == WRITE_TEXT) {
+      switch (print_format) {
+
+      case PR_FMT_TEXT:
+        print_stream = print_stream_text_stdio_new(stdout);
+        break;
+
+      case PR_FMT_PS:
+        print_stream = print_stream_ps_stdio_new(stdout);
+        break;
+
+      default:
+        g_assert_not_reached();
+      }
+    }
+  }
+
+  /* We have to dissect each packet if:
+
+       we're printing information about each packet;
+
+       we're using a read filter on the packets;
+
+       we're using any taps. */
+  do_dissection = print_packet_info || rfcode || have_tap_listeners();
+
   if (cf_name) {
     /*
      * We're reading a capture file.
@@ -1493,12 +1329,11 @@ main(int argc, char *argv[])
     setgid(getgid());
 #endif
 
-    err = cf_open(cf_name, FALSE, &cfile);
-    if (err != 0) {
+    if (cf_open(&cfile, cf_name, FALSE, &err) != CF_OK) {
       epan_cleanup();
       exit(2);
     }
-    err = load_cap_file(&cfile, out_file_type);
+    err = load_cap_file(&cfile, save_file, out_file_type);
     if (err != 0) {
       epan_cleanup();
       exit(2);
@@ -1518,15 +1353,15 @@ main(int argc, char *argv[])
 #endif
 
     /* Yes; did the user specify an interface to use? */
-    if (cfile.iface == NULL) {
+    if (capture_opts.iface == NULL) {
         /* No - is a default specified in the preferences file? */
         if (prefs->capture_device != NULL) {
             /* Yes - use it. */
            if_text = strrchr(prefs->capture_device, ' ');
            if (if_text == NULL) {
-               cfile.iface = g_strdup(prefs->capture_device);
+               capture_opts.iface = g_strdup(prefs->capture_device);
            } else {
-               cfile.iface = g_strdup(if_text + 1); /* Skip over space */
+               capture_opts.iface = g_strdup(if_text + 1); /* Skip over space */
            }
         } else {
             /* No - pick the first one from the list of interfaces. */
@@ -1535,8 +1370,10 @@ main(int argc, char *argv[])
                 switch (err) {
 
                 case CANT_GET_INTERFACE_LIST:
-                    fprintf(stderr, "tethereal: Can't get list of interfaces: %s\n",
-                           err_str);
+                    cant_get_if_list_errstr =
+                        cant_get_if_list_error_message(err_str);
+                    fprintf(stderr, "tethereal: %s\n", cant_get_if_list_errstr);
+                    g_free(cant_get_if_list_errstr);
                     break;
 
                 case NO_INTERFACES_FOUND:
@@ -1546,7 +1383,7 @@ main(int argc, char *argv[])
                 exit(2);
             }
            if_info = if_list->data;    /* first interface */
-           cfile.iface = g_strdup(if_info->name);
+           capture_opts.iface = g_strdup(if_info->name);
             free_interface_list(if_list);
         }
     }
@@ -1554,7 +1391,7 @@ main(int argc, char *argv[])
     if (list_link_layer_types) {
       /* We were asked to list the link-layer types for an interface.
          Get the list of link-layer types for the capture device. */
-      lt_list = get_pcap_linktype_list(cfile.iface, err_str);
+      lt_list = get_pcap_linktype_list(capture_opts.iface, err_str);
       if (lt_list == NULL) {
        if (err_str[0] != '\0') {
          fprintf(stderr, "tethereal: The list of data link types for the capture device could not be obtained (%s).\n"
@@ -1579,9 +1416,17 @@ main(int argc, char *argv[])
       exit(0);
     }
 
-    capture(out_file_type);
+    if (!quiet) {
+      /*
+       * The user didn't ask us not to print a count of packets as
+       * they arrive, so do so.
+       */
+      print_packet_counts = TRUE;
+    }
+
+    capture(save_file, out_file_type);
 
-    if (capture_opts.ringbuffer_on) {
+    if (capture_opts.multi_files_on) {
       ringbuf_free();
     }
 #else
@@ -1601,10 +1446,10 @@ main(int argc, char *argv[])
 /* Do the low-level work of a capture.
    Returns TRUE if it succeeds, FALSE otherwise. */
 
-static condition  *volatile cnd_ring_timeout = NULL; /* this must be visible in wtap_dispatch_cb_write */
+static condition  *volatile cnd_ring_timeout = NULL; /* this must be visible in process_packet */
 
 static int
-capture(int out_file_type)
+capture(char *save_file, int out_file_type)
 {
   int         pcap_encap;
   int         file_snaplen;
@@ -1620,6 +1465,7 @@ capture(int out_file_type)
   char        errmsg[1024+1];
   condition  *volatile cnd_stop_capturesize = NULL;
   condition  *volatile cnd_stop_timeout = NULL;
+  char       *descr;
 #ifndef _WIN32
   void        (*oldhandler)(int);
   static const char ppamsg[] = "can't find PPA for ";
@@ -1633,6 +1479,7 @@ capture(int out_file_type)
   gboolean    write_err;
   gboolean    dump_ok;
   dfilter_t   *rfcode = NULL;
+  int         save_file_fd;
 
   /* Initialize all data structures used for dissection. */
   init_dissection();
@@ -1645,13 +1492,13 @@ capture(int out_file_type)
      if they succeed; to tell if that's happened, we have to clear
      the error buffer, and check if it's still a null string.  */
   open_err_str[0] = '\0';
-  ld.pch = pcap_open_live(cfile.iface, capture_opts.snaplen,
+  ld.pch = pcap_open_live(capture_opts.iface, capture_opts.snaplen,
                          capture_opts.promisc_mode, 1000, open_err_str);
 
   if (ld.pch != NULL) {
     /* setting the data link type only works on real interfaces */
     if (capture_opts.linktype != -1) {
-      set_linktype_err_str = set_pcap_linktype(ld.pch, cfile.iface,
+      set_linktype_err_str = set_pcap_linktype(ld.pch, capture_opts.iface,
        capture_opts.linktype);
       if (set_linktype_err_str != NULL) {
        snprintf(errmsg, sizeof errmsg, "Unable to set data link type (%s).",
@@ -1680,7 +1527,8 @@ capture(int out_file_type)
     goto error;
 #else
     /* try to open cfile.iface as a pipe */
-    pipe_fd = pipe_open_live(cfile.iface, &hdr, &ld, errmsg, sizeof errmsg);
+    pipe_fd = pipe_open_live(capture_opts.iface, &hdr, &ld, errmsg,
+                             sizeof errmsg);
 
     if (pipe_fd == -1) {
 
@@ -1740,9 +1588,9 @@ capture(int out_file_type)
   setgid(getgid());
 #endif
 
-  if (cfile.cfilter && !ld.from_pipe) {
+  if (capture_opts.cfilter && !ld.from_pipe) {
     /* A capture filter was specified; set it up. */
-    if (pcap_lookupnet(cfile.iface, &netnum, &netmask, lookup_net_err_str) < 0) {
+    if (pcap_lookupnet(capture_opts.iface, &netnum, &netmask, lookup_net_err_str) < 0) {
       /*
        * Well, we can't get the netmask for this interface; it's used
        * only for filters that check for broadcast IP addresses, so
@@ -1752,8 +1600,8 @@ capture(int out_file_type)
         "Warning:  Couldn't obtain netmask info (%s).\n", lookup_net_err_str);
       netmask = 0;
     }
-    if (pcap_compile(ld.pch, &fcode, cfile.cfilter, 1, netmask) < 0) {
-      if (dfilter_compile(cfile.cfilter, &rfcode)) {
+    if (pcap_compile(ld.pch, &fcode, capture_opts.cfilter, 1, netmask) < 0) {
+      if (dfilter_compile(capture_opts.cfilter, &rfcode)) {
         snprintf(errmsg, sizeof errmsg,
          "Unable to parse capture filter string (%s).\n"
           "  Interestingly enough, this looks like a valid display filter\n"
@@ -1769,8 +1617,14 @@ capture(int out_file_type)
     if (pcap_setfilter(ld.pch, &fcode) < 0) {
       snprintf(errmsg, sizeof errmsg, "Can't install filter (%s).",
        pcap_geterr(ld.pch));
+#ifdef HAVE_PCAP_FREECODE
+      pcap_freecode(&fcode);
+#endif
       goto error;
     }
+#ifdef HAVE_PCAP_FREECODE
+    pcap_freecode(&fcode);
+#endif
   }
 
   /* Set up to write to the capture file. */
@@ -1781,36 +1635,37 @@ capture(int out_file_type)
   } else
 #endif
   {
-    pcap_encap = get_pcap_linktype(ld.pch, cfile.iface);
+    pcap_encap = get_pcap_linktype(ld.pch, capture_opts.iface);
     file_snaplen = pcap_snapshot(ld.pch);
   }
   ld.linktype = wtap_pcap_encap_to_wtap_encap(pcap_encap);
-  if (cfile.save_file != NULL) {
+  if (save_file != NULL) {
     /* Set up to write to the capture file. */
     if (ld.linktype == WTAP_ENCAP_UNKNOWN) {
       strcpy(errmsg, "The network you're capturing from is of a type"
                " that Tethereal doesn't support.");
       goto error;
     }
-    if (capture_opts.ringbuffer_on) {
-      cfile.save_file_fd = ringbuf_init(cfile.save_file,
-        capture_opts.ringbuffer_num_files);
-      if (cfile.save_file_fd != -1) {
+    ld.save_file = save_file;
+    if (capture_opts.multi_files_on) {
+      save_file_fd = ringbuf_init(save_file,
+        capture_opts.ring_num_files);
+      if (save_file_fd != -1) {
         ld.pdh = ringbuf_init_wtap_dump_fdopen(out_file_type, ld.linktype,
-          pcap_snapshot(ld.pch), &err);
+          file_snaplen, &err);
       } else {
        err = errno;    /* "ringbuf_init()" failed */
         ld.pdh = NULL;
       }
     } else {
-      ld.pdh = wtap_dump_open(cfile.save_file, out_file_type,
-                ld.linktype, pcap_snapshot(ld.pch), &err);
+      ld.pdh = wtap_dump_open(save_file, out_file_type,
+                ld.linktype, file_snaplen, &err);
     }
 
     if (ld.pdh == NULL) {
       snprintf(errmsg, sizeof errmsg,
-              file_open_error_message(err, TRUE, out_file_type),
-              *cfile.save_file == '\0' ? "stdout" : cfile.save_file);
+              cf_open_error_message(err, NULL, TRUE, out_file_type),
+              *save_file == '\0' ? "stdout" : save_file);
       goto error;
     }
   }
@@ -1841,7 +1696,9 @@ capture(int out_file_type)
 #endif /* _WIN32 */
 
   /* Let the user know what interface was chosen. */
-  fprintf(stderr, "Capturing on %s\n", cfile.iface);
+  descr = get_interface_descriptive_name(capture_opts.iface);
+  fprintf(stderr, "Capturing on %s\n", descr);
+  g_free(descr);
 
   /* initialize capture stop conditions */
   init_capture_stop_conditions();
@@ -1853,9 +1710,9 @@ capture(int out_file_type)
     cnd_stop_timeout = cnd_new((const char*)CND_CLASS_TIMEOUT,
                                (gint32)capture_opts.autostop_duration);
 
-  if (capture_opts.ringbuffer_on && capture_opts.has_ring_duration)
+  if (capture_opts.multi_files_on && capture_opts.has_file_duration)
     cnd_ring_timeout = cnd_new(CND_CLASS_TIMEOUT, 
-                              capture_opts.ringbuffer_duration);
+                              capture_opts.file_duration);
 
   if (!setjmp(ld.stopenv)) {
     ld.go = TRUE;
@@ -1906,15 +1763,15 @@ capture(int out_file_type)
          reading the FIFO sees the packets immediately and doesn't get
          any partial packet, forcing it to block in the middle of reading
          that packet. */
-      if (capture_opts.autostop_count == 0)
+      if (capture_opts.autostop_packets == 0)
         pcap_cnt = -1;
       else {
-        if (ld.packet_count >= capture_opts.autostop_count) {
+        if (ld.packet_count >= capture_opts.autostop_packets) {
           /* XXX do we need this test here? */
           /* It appears there's nothing more to capture. */
           break;
         }
-        pcap_cnt = capture_opts.autostop_count - ld.packet_count;
+        pcap_cnt = capture_opts.autostop_packets - ld.packet_count;
       }
     } else {
       /* We need to check the capture file size or the timeout after
@@ -1936,8 +1793,8 @@ capture(int out_file_type)
       /* The specified capture time has elapsed; stop the capture. */
       ld.go = FALSE;
     } else if (inpkts > 0) {
-      if (capture_opts.autostop_count != 0 &&
-                 ld.packet_count >= capture_opts.autostop_count) {
+      if (capture_opts.autostop_packets != 0 &&
+                 ld.packet_count >= capture_opts.autostop_packets) {
         /* The specified number of packets have been captured and have
            passed both any capture filter in effect and any read filter
            in effect. */
@@ -1947,9 +1804,9 @@ capture(int out_file_type)
                               (guint32)wtap_get_bytes_dumped(ld.pdh))) {
         /* We're saving the capture to a file, and the capture file reached
            its maximum size. */
-        if (capture_opts.ringbuffer_on) {
+        if (capture_opts.multi_files_on) {
           /* Switch to the next ringbuffer file */
-          if (ringbuf_switch_file(&cfile, &ld.pdh, &loop_err)) {
+          if (ringbuf_switch_file(&ld.pdh, &save_file, &save_file_fd, &loop_err)) {
             /* File switch succeeded: reset the condition */
             cnd_reset(cnd_stop_capturesize);
            if (cnd_ring_timeout) {
@@ -1985,9 +1842,8 @@ capture(int out_file_type)
   if (cnd_ring_timeout != NULL)
     cnd_delete(cnd_ring_timeout);
 
-  if ((cfile.save_file != NULL) && !quiet) {
-    /* We're saving to a file, which means we're printing packet counts
-       to stderr if we are not running silent and deep.
+  if (print_packet_counts) {
+    /* We're printing packet counts to stderr.
        Send a newline so that we move to the line after the packet count. */
     fprintf(stderr, "\n");
   }
@@ -2011,21 +1867,21 @@ capture(int out_file_type)
   if (volatile_err == 0)
     write_err = FALSE;
   else {
-    show_capture_file_io_error(cfile.save_file, volatile_err, FALSE);
+    show_capture_file_io_error(save_file, volatile_err, FALSE);
     write_err = TRUE;
   }
 
-  if (cfile.save_file != NULL) {
+  if (save_file != NULL) {
     /* We're saving to a file or files; close all files. */
-    if (capture_opts.ringbuffer_on) {
-      dump_ok = ringbuf_wtap_dump_close(&cfile, &err);
+    if (capture_opts.multi_files_on) {
+      dump_ok = ringbuf_wtap_dump_close(&save_file, &err);
     } else {
       dump_ok = wtap_dump_close(ld.pdh, &err);
     }
     /* If we've displayed a message about a write error, there's no point
        in displaying another message about an error on close. */
     if (!dump_ok && !write_err)
-      show_capture_file_io_error(cfile.save_file, err, TRUE);
+      show_capture_file_io_error(save_file, err, TRUE);
   }
 
 #ifndef _WIN32
@@ -2054,11 +1910,11 @@ capture(int out_file_type)
   return TRUE;
 
 error:
-  if (capture_opts.ringbuffer_on) {
+  if (capture_opts.multi_files_on) {
     ringbuf_error_cleanup();
   }
-  g_free(cfile.save_file);
-  cfile.save_file = NULL;
+  g_free(save_file);
+  save_file = NULL;
   fprintf(stderr, "tethereal: %s\n", errmsg);
 #ifndef _WIN32
   if (ld.from_pipe) {
@@ -2080,39 +1936,70 @@ capture_pcap_cb(guchar *user, const struct pcap_pkthdr *phdr,
 {
   struct wtap_pkthdr whdr;
   union wtap_pseudo_header pseudo_header;
-  loop_data *ld = (loop_data *) user;
-  cb_args_t args;
+  loop_data *ldat = (loop_data *) user;
+  int loop_err;
   int err;
+  int save_file_fd;
 
   /* Convert from libpcap to Wiretap format.
      If that fails, ignore the packet (wtap_process_pcap_packet has
      written an error message). */
-  pd = wtap_process_pcap_packet(ld->linktype, phdr, pd, &pseudo_header,
+  pd = wtap_process_pcap_packet(ldat->linktype, phdr, pd, &pseudo_header,
                                &whdr, &err);
-  if (pd == NULL) {
+  if (pd == NULL)
     return;
+
+#ifdef SIGINFO
+  /*
+   * Prevent a SIGINFO handler from writing to stdout while we're
+   * doing so; instead, have it just set a flag telling us to print
+   * that information when we're done.
+   */
+  infodelay = TRUE;
+#endif /* SIGINFO */
+
+  /* The current packet may have arrived after a very long silence,
+   * way past the time to switch files.  In order not to have
+   * the first packet of a new series of events as the last
+   * [or only] packet in the file, switch before writing!
+   */
+  if (cnd_ring_timeout != NULL && cnd_eval(cnd_ring_timeout)) {
+    /* time elapsed for this ring file, switch to the next */
+    if (ringbuf_switch_file(&ldat->pdh, &ldat->save_file, &save_file_fd, &loop_err)) {
+      /* File switch succeeded: reset the condition */
+      cnd_reset(cnd_ring_timeout);
+    } else {
+      /* File switch failed: stop here */
+      /* XXX - we should do something with "loop_err" */
+      ldat->go = FALSE;
+    }
   }
 
-  args.cf = &cfile;
-  args.pdh = ld->pdh;
-  if (ld->pdh) {
-    wtap_dispatch_cb_write((guchar *)&args, &whdr, 0, &pseudo_header, pd);
-    /* Report packet capture count if not quiet */
-    if (!quiet) {
-      if (!decode) {
-         if (ld->packet_count != 0) {
-           fprintf(stderr, "\r%u ", ld->packet_count);
-           /* stderr could be line buffered */
-           fflush(stderr);
-         }
-      } else {
-           wtap_dispatch_cb_print((guchar *)&args, &whdr, 0,
-                                  &pseudo_header, pd);
-      }
+  if (!process_packet(&cfile, ldat->pdh, 0, &whdr, &pseudo_header, pd, &err)) {
+    /* Error writing to a capture file */
+    if (print_packet_counts) {
+      /* We're printing counts of packets captured; move to the line after
+         the count. */
+      fprintf(stderr, "\n");
     }
-  } else {
-    wtap_dispatch_cb_print((guchar *)&args, &whdr, 0, &pseudo_header, pd);
+    show_capture_file_io_error(ldat->save_file, err, FALSE);
+    pcap_close(ldat->pch);
+    wtap_dump_close(ldat->pdh, &err);
+    exit(2);
   }
+
+#ifdef SIGINFO
+  /*
+   * Allow SIGINFO handlers to write.
+   */
+  infodelay = FALSE;
+
+  /*
+   * If a SIGINFO handler asked us to write out capture counts, do so.
+   */
+  if (infoprint)
+    report_counts();
+#endif /* SIGINFO */
 }
 
 #ifdef _WIN32
@@ -2166,10 +2053,9 @@ report_counts(void)
   signal(SIGINFO, report_counts_siginfo);
 #endif /* SIGINFO */
 
-  if (cfile.save_file != NULL && quiet) {
-    /* Report the count only if we're capturing to a file (rather
-       than printing captured packet information out) and aren't
-       updating a count as packets arrive. */
+  if (!print_packet_counts) {
+    /* Report the count only if we aren't printing a packet count
+       as packets arrive. */
     fprintf(stderr, "%u packets captured\n", ld.packet_count);
   }
 #ifdef SIGINFO
@@ -2195,24 +2081,24 @@ report_counts_siginfo(int signum _U_)
 #endif /* HAVE_LIBPCAP */
 
 static int
-load_cap_file(capture_file *cf, int out_file_type)
+load_cap_file(capture_file *cf, char *save_file, int out_file_type)
 {
   gint         linktype;
   int          snapshot_length;
   wtap_dumper *pdh;
   int          err;
-  int          success;
-  cb_args_t    args;
+  gchar        *err_info;
+  long         data_offset;
 
   linktype = wtap_file_encap(cf->wth);
-  if (cf->save_file != NULL) {
+  if (save_file != NULL) {
     /* Set up to write to the capture file. */
     snapshot_length = wtap_snapshot_length(cf->wth);
     if (snapshot_length == 0) {
       /* Snapshot length of input file not known. */
       snapshot_length = WTAP_MAX_PACKET_SIZE;
     }
-    pdh = wtap_dump_open(cf->save_file, out_file_type,
+    pdh = wtap_dump_open(save_file, out_file_type,
                linktype, snapshot_length, &err);
 
     if (pdh == NULL) {
@@ -2227,7 +2113,7 @@ load_cap_file(capture_file *cf, int out_file_type)
       case WTAP_ERR_UNSUPPORTED_ENCAP:
       case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
         fprintf(stderr,
-          "tethereal: The capture file being read cannot be written in "
+          "tethereal: The capture file being read can't be written in "
           "that format.\n");
         break;
 
@@ -2235,49 +2121,52 @@ load_cap_file(capture_file *cf, int out_file_type)
         fprintf(stderr,
           "tethereal: The file \"%s\" couldn't be created for some "
           "unknown reason.\n",
-            *cf->save_file == '\0' ? "stdout" : cf->save_file);
+            *save_file == '\0' ? "stdout" : save_file);
         break;
 
       case WTAP_ERR_SHORT_WRITE:
         fprintf(stderr,
           "tethereal: A full header couldn't be written to the file \"%s\".\n",
-               *cf->save_file == '\0' ? "stdout" : cf->save_file);
+               *save_file == '\0' ? "stdout" : save_file);
         break;
 
       default:
         fprintf(stderr,
           "tethereal: The file \"%s\" could not be created: %s\n.",
-               *cf->save_file == '\0' ? "stdout" : cf->save_file,
+               *save_file == '\0' ? "stdout" : save_file,
                wtap_strerror(err));
         break;
       }
       goto out;
     }
-    args.cf = cf;
-    args.pdh = pdh;
-    success = wtap_loop(cf->wth, 0, wtap_dispatch_cb_write, (guchar *) &args,
-                       &err);
-
-    /* Now close the capture file. */
-    if (!wtap_dump_close(pdh, &err))
-      show_capture_file_io_error(cfile.save_file, err, TRUE);
   } else {
-    args.cf = cf;
-    args.pdh = NULL;
-    print_preamble(stdout, print_format);
-    success = wtap_loop(cf->wth, 0, wtap_dispatch_cb_print, (guchar *) &args,
-                       &err);
-    print_finale(stdout, print_format);
-  }
-  if (!success) {
-    /* Print up a message box noting that the read failed somewhere along
-       the line. */
+    if (print_packet_info) {
+      if (!write_preamble(cf)) {
+        err = errno;
+        show_print_file_io_error(err);
+        goto out;
+      }
+    }
+    pdh = NULL;
+  }
+  while (wtap_read(cf->wth, &err, &err_info, &data_offset)) {
+    if (!process_packet(cf, pdh, data_offset, wtap_phdr(cf->wth),
+                        wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth),
+                        &err)) {
+      /* Error writing to a capture file */
+      show_capture_file_io_error(save_file, err, FALSE);
+      wtap_dump_close(pdh, &err);
+      exit(2);
+    }
+  }
+  if (err != 0) {
+    /* Print a message noting that the read failed somewhere along the line. */
     switch (err) {
 
     case WTAP_ERR_UNSUPPORTED_ENCAP:
       fprintf(stderr,
-"tethereal: \"%s\" is a capture file is for a network type that Tethereal doesn't support.\n",
-       cf->filename);
+"tethereal: \"%s\" has a packet with a network type that Tethereal doesn't support.\n(%s)\n",
+       cf->filename, err_info);
       break;
 
     case WTAP_ERR_CANT_READ:
@@ -2294,8 +2183,8 @@ load_cap_file(capture_file *cf, int out_file_type)
 
     case WTAP_ERR_BAD_RECORD:
       fprintf(stderr,
-"tethereal: \"%s\" appears to be damaged or corrupt.\n",
-       cf->filename);
+"tethereal: \"%s\" appears to be damaged or corrupt.\n(%s)\n",
+       cf->filename, err_info);
       break;
 
     default:
@@ -2304,10 +2193,28 @@ load_cap_file(capture_file *cf, int out_file_type)
        cf->filename, wtap_strerror(err));
       break;
     }
-  }
-
-out:
-  wtap_close(cf->wth);
+    if (save_file != NULL) {
+      /* Now close the capture file. */
+      if (!wtap_dump_close(pdh, &err))
+        show_capture_file_io_error(save_file, err, TRUE);
+    }
+  } else {
+    if (save_file != NULL) {
+      /* Now close the capture file. */
+      if (!wtap_dump_close(pdh, &err))
+        show_capture_file_io_error(save_file, err, TRUE);
+    } else {
+      if (print_packet_info) {
+        if (!write_finale()) {
+          err = errno;
+          show_print_file_io_error(err);
+        }
+      }
+    }
+  }
+
+out:
+  wtap_close(cf->wth);
   cf->wth = NULL;
 
   return err;
@@ -2322,8 +2229,8 @@ fill_in_fdata(frame_data *fdata, capture_file *cf,
   fdata->pfd = NULL;
   fdata->num = cf->count;
   fdata->pkt_len = phdr->len;
-  cul_bytes += phdr->len;
-  fdata->cul_bytes  = cul_bytes;
+  cum_bytes += phdr->len;
+  fdata->cum_bytes  = cum_bytes;
   fdata->cap_len = phdr->caplen;
   fdata->file_off = offset;
   fdata->lnk_t = phdr->pkt_encap;
@@ -2381,100 +2288,135 @@ clear_fdata(frame_data *fdata)
     g_slist_free(fdata->pfd);
 }
 
-static void
-wtap_dispatch_cb_write(guchar *user, const struct wtap_pkthdr *phdr,
-  long offset, union wtap_pseudo_header *pseudo_header, const guchar *buf)
+static gboolean
+process_packet(capture_file *cf, wtap_dumper *pdh, long offset,
+               const struct wtap_pkthdr *whdr,
+               union wtap_pseudo_header *pseudo_header, const guchar *pd,
+               int *err)
 {
-  cb_args_t    *args = (cb_args_t *) user;
-  capture_file *cf = args->cf;
-  wtap_dumper  *pdh = args->pdh;
-  frame_data    fdata;
-  int           err;
-  gboolean      passed;
+  frame_data fdata;
+  gboolean create_proto_tree;
   epan_dissect_t *edt;
+  gboolean passed;
 
-#ifdef HAVE_LIBPCAP
-#ifdef SIGINFO
-  /*
-   * Prevent a SIGINFO handler from writing to stdout while we're
-   * doing so; instead, have it just set a flag telling us to print
-   * that information when we're done.
-   */
-  infodelay = TRUE;
-#endif /* SIGINFO */
-#endif /* HAVE_LIBPCAP */
-
+  /* Count this packet. */
   cf->count++;
-  if (cf->rfcode) {
-    fill_in_fdata(&fdata, cf, phdr, offset);
-    edt = epan_dissect_new(TRUE, FALSE);
-    epan_dissect_prime_dfilter(edt, cf->rfcode);
-    epan_dissect_run(edt, pseudo_header, buf, &fdata, NULL);
-    passed = dfilter_apply_edt(cf->rfcode, edt);
-  } else {
+
+  /* If we're going to print packet information, or we're going to
+     run a read filter, or we're going to process taps, set up to
+     do a dissection and do so. */
+  if (do_dissection) {
+    fill_in_fdata(&fdata, cf, whdr, offset);
+
+    if (print_packet_info) {
+      /* Grab any resolved addresses */
+    
+      if (g_resolv_flags) {
+        host_name_lookup_process(NULL);
+      }
+    }
+
     passed = TRUE;
+    if (cf->rfcode || verbose || num_tap_filters!=0)
+      create_proto_tree = TRUE;
+    else
+      create_proto_tree = FALSE;
+    /* The protocol tree will be "visible", i.e., printed, only if we're
+       printing packet details, which is true if we're printing stuff
+       ("print_packet_info" is true) and we're in verbose mode ("verbose"
+       is true). */
+    edt = epan_dissect_new(create_proto_tree, print_packet_info && verbose);
+
+    /* If we're running a read filter, prime the epan_dissect_t with that
+       filter. */
+    if (cf->rfcode)
+      epan_dissect_prime_dfilter(edt, cf->rfcode);
+
+    tap_queue_init(edt);
+
+    /* We only need the columns if we're printing packet info but we're
+       *not* verbose; in verbose mode, we print the protocol tree, not
+       the protocol summary. */
+    epan_dissect_run(edt, pseudo_header, pd, &fdata,
+                     (print_packet_info && !verbose) ? &cf->cinfo : NULL);
+
+    tap_push_tapped_queue(edt);
+
+    /* Run the read filter if we have one. */
+    if (cf->rfcode)
+      passed = dfilter_apply_edt(cf->rfcode, edt);
+    else
+      passed = TRUE;
+  } else {
+    /* We're not running a display filter and we're not printing any
+       packet information, so we don't need to do a dissection, and all
+       packets are processed. */
     edt = NULL;
+    passed = TRUE;
   }
+
   if (passed) {
-    /* The packet passed the read filter. */
+    /* Count this packet. */
 #ifdef HAVE_LIBPCAP
-    int loop_err;
-
     ld.packet_count++;
-
-    /* The current packet may have arrived after a very long silence,
-     * way past the time to switch files.  In order not to have
-     * the first packet of a new series of events as the last
-     * [or only] packet in the file, switch before writing!
-     */
-    if (cnd_ring_timeout != NULL && cnd_eval(cnd_ring_timeout)) {
-      /* time elasped for this ring file, switch to the next */
-      if (ringbuf_switch_file(&cfile, &ld.pdh, &loop_err)) {
-       /* File switch succeeded: reset the condition */
-       cnd_reset(cnd_ring_timeout);
-      } else {
-       /* File switch failed: stop here */
-       /* XXX - we should do something with "loop_err" */
-       ld.go = FALSE;
-      }
-    }
 #endif
-    if (!wtap_dump(pdh, phdr, pseudo_header, buf, &err)) {
+
+    /* Process this packet. */
+    if (pdh != NULL) {
+      /* We're writing to a capture file; write this packet. */
+      if (!wtap_dump(pdh, whdr, pseudo_header, pd, err))
+        return FALSE;
 #ifdef HAVE_LIBPCAP
-      if (ld.pch != NULL && !quiet) {
-       /* We're capturing packets, so (if -q not specified) we're printing
-           a count of packets captured; move to the line after the count. */
-        fprintf(stderr, "\n");
+      if (print_packet_counts) {
+       /* We're printing packet counts. */
+        if (ld.packet_count != 0) {
+          fprintf(stderr, "\r%u ", ld.packet_count);
+          /* stderr could be line buffered */
+          fflush(stderr);
+        }
       }
 #endif
-      show_capture_file_io_error(cf->save_file, err, FALSE);
-#ifdef HAVE_LIBPCAP
-      if (ld.pch != NULL)
-        pcap_close(ld.pch);
-#endif
-      wtap_dump_close(pdh, &err);
-      exit(2);
+    }
+    if (print_packet_info) {
+      /* We're printing packet information; print the information for
+         this packet. */
+      print_packet(cf, edt);
+
+      /* The ANSI C standard does not appear to *require* that a line-buffered
+         stream be flushed to the host environment whenever a newline is
+         written, it just says that, on such a stream, characters "are
+         intended to be transmitted to or from the host environment as a
+         block when a new-line character is encountered".
+
+         The Visual C++ 6.0 C implementation doesn't do what is intended;
+         even if you set a stream to be line-buffered, it still doesn't
+         flush the buffer at the end of every line.
+
+         So, if the "-l" flag was specified, we flush the standard output
+         at the end of a packet.  This will do the right thing if we're
+         printing packet summary lines, and, as we print the entire protocol
+         tree for a single packet without waiting for anything to happen,
+         it should be as good as line-buffered mode if we're printing
+         protocol trees.  (The whole reason for the "-l" flag in either
+         tcpdump or Tethereal is to allow the output of a live capture to
+         be piped to a program or script and to have that script see the
+         information for the packet as soon as it's printed, rather than
+         having to wait until a standard I/O buffer fills up. */
+      if (line_buffered)
+        fflush(stdout);
+
+      if (ferror(stdout)) {
+        show_print_file_io_error(errno);
+        exit(2);
+      }
     }
   }
-  if (edt != NULL)
+
+  if (do_dissection) {
     epan_dissect_free(edt);
-  if (cf->rfcode)
     clear_fdata(&fdata);
-
-#ifdef HAVE_LIBPCAP
-#ifdef SIGINFO
-  /*
-   * Allow SIGINFO handlers to write.
-   */
-  infodelay = FALSE;
-
-  /*
-   * If a SIGINFO handler asked us to write out capture counts, do so.
-   */
-  if (infoprint)
-    report_counts();
-#endif /* SIGINFO */
-#endif /* HAVE_LIBPCAP */
+  }
+  return TRUE;
 }
 
 static void
@@ -2527,387 +2469,507 @@ show_capture_file_io_error(const char *fname, int err, gboolean is_close)
   }
 }
 
-static void
-wtap_dispatch_cb_print(guchar *user, const struct wtap_pkthdr *phdr,
-  long offset, union wtap_pseudo_header *pseudo_header, const guchar *buf)
+static gboolean
+write_preamble(capture_file *cf)
 {
-  cb_args_t    *args = (cb_args_t *) user;
-  capture_file *cf = args->cf;
-  frame_data    fdata;
-  gboolean      passed;
-  print_args_t  print_args;
-  epan_dissect_t *edt;
-  gboolean      create_proto_tree;
-  int           i;
+  switch (output_action) {
 
-  cf->count++;
+  case WRITE_TEXT:
+    return print_preamble(print_stream, cf->filename);
+    break;
 
-  fill_in_fdata(&fdata, cf, phdr, offset);
+  case WRITE_XML:
+    if (verbose)
+      write_pdml_preamble(stdout);
+    else
+      write_psml_preamble(stdout);
+    return !ferror(stdout);
 
-  /* Grab any resolved addresses */
-  if (g_resolv_flags) {
-    host_name_lookup_process(NULL);
+  default:
+    g_assert_not_reached();
+    return FALSE;
   }
+}
 
-  passed = TRUE;
-  if (cf->rfcode || verbose || num_tap_filters!=0)
-    create_proto_tree = TRUE;
-  else
-    create_proto_tree = FALSE;
-  /* The protocol tree will be "visible", i.e., printed, only if we're
-     not printing a summary.
-
-     We only need the columns if we're *not* verbose; in verbose mode,
-     we print the protocol tree, not the protocol summary. */
-
-  edt = epan_dissect_new(create_proto_tree, verbose);
-  if (cf->rfcode) {
-    epan_dissect_prime_dfilter(edt, cf->rfcode);
+static char *
+get_line_buf(size_t len)
+{
+  static char *line_bufp = NULL;
+  static size_t line_buf_len = 256;
+  size_t new_line_buf_len;
+
+  for (new_line_buf_len = line_buf_len; len > new_line_buf_len;
+       new_line_buf_len *= 2)
+    ;
+  if (line_bufp == NULL) {
+    line_buf_len = new_line_buf_len;
+    line_bufp = g_malloc(line_buf_len + 1);
+  } else {
+    if (new_line_buf_len > line_buf_len) {
+      line_buf_len = new_line_buf_len;
+      line_bufp = g_realloc(line_bufp, line_buf_len + 1);
+    }
   }
+  return line_bufp;
+}
 
-  tap_queue_init(edt);
-  epan_dissect_run(edt, pseudo_header, buf, &fdata, verbose ? NULL : &cf->cinfo);
-  tap_push_tapped_queue(edt);
-
-  if (cf->rfcode) {
-    passed = dfilter_apply_edt(cf->rfcode, edt);
-  }
-  if (passed) {
-    /* The packet passed the read filter. */
+static gboolean
+print_columns(capture_file *cf)
+{
+  char *line_bufp;
+  int i;
+  size_t buf_offset;
+  size_t column_len;
+
+  line_bufp = get_line_buf(256);
+  buf_offset = 0;
+  *line_bufp = '\0';
+  for (i = 0; i < cf->cinfo.num_cols; i++) {
+    switch (cf->cinfo.col_fmt[i]) {
+    case COL_NUMBER:
 #ifdef HAVE_LIBPCAP
-    ld.packet_count++;
+      /*
+       * Don't print this if we're doing a live capture from a network
+       * interface - if we're doing a live capture, you won't be
+       * able to look at the capture in the future (it's not being
+       * saved anywhere), so the frame numbers are unlikely to be
+       * useful.
+       *
+       * (XXX - it might be nice to be able to save and print at
+       * the same time, sort of like an "Update list of packets
+       * in real time" capture in Ethereal.)
+       */
+      if (capture_opts.iface != NULL)
+        continue;
 #endif
-    print_args.to_file = TRUE;
-    print_args.format = print_format;
-    print_args.print_summary = !verbose;
-    print_args.print_hex = print_hex;
-    print_args.print_dissections = print_dissections_expanded;
-
-    /* init the packet range */
-    packet_range_init(&print_args.range);
-
-    if (verbose) {
-      /* Print the information in the protocol tree. */
-      proto_tree_print(&print_args, edt, stdout);
-      if (!print_hex) {
-        /* "print_hex_data()" will put out a leading blank line, as well
-          as a trailing one; print one here, to separate the packets,
-          only if "print_hex_data()" won't be called. */
-        printf("\n");
-      }
-    } else {
-      /* Just fill in the columns. */
-      epan_dissect_fill_in_columns(edt);
-
-      /* Now print them. */
-      for (i = 0; i < cf->cinfo.num_cols; i++) {
-        switch (cf->cinfo.col_fmt[i]) {
-       case COL_NUMBER:
-         /*
-          * Don't print this if we're doing a live capture from a network
-          * interface - if we're doing a live capture, you won't be
-          * able to look at the capture in the future (it's not being
-          * saved anywhere), so the frame numbers are unlikely to be
-          * useful.
-          *
-          * (XXX - it might be nice to be able to save and print at
-          * the same time, sort of like an "Update list of packets
-          * in real time" capture in Ethereal.)
-          */
-          if (cf->iface != NULL)
-            continue;
-          printf("%3s", cf->cinfo.col_data[i]);
+      column_len = strlen(cf->cinfo.col_data[i]);
+      if (column_len < 3)
+        column_len = 3;
+      line_bufp = get_line_buf(buf_offset + column_len);
+      sprintf(line_bufp + buf_offset, "%3s", cf->cinfo.col_data[i]);
+      break;
+
+    case COL_CLS_TIME:
+    case COL_REL_TIME:
+    case COL_ABS_TIME:
+    case COL_ABS_DATE_TIME:    /* XXX - wider */
+      column_len = strlen(cf->cinfo.col_data[i]);
+      if (column_len < 10)
+        column_len = 10;
+      line_bufp = get_line_buf(buf_offset + column_len);
+      sprintf(line_bufp + buf_offset, "%10s", cf->cinfo.col_data[i]);
+      break;
+
+    case COL_DEF_SRC:
+    case COL_RES_SRC:
+    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:
+      column_len = strlen(cf->cinfo.col_data[i]);
+      if (column_len < 12)
+        column_len = 12;
+      line_bufp = get_line_buf(buf_offset + column_len);
+      sprintf(line_bufp + buf_offset, "%12s", cf->cinfo.col_data[i]);
+      break;
+
+    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:
+      column_len = strlen(cf->cinfo.col_data[i]);
+      if (column_len < 12)
+        column_len = 12;
+      line_bufp = get_line_buf(buf_offset + column_len);
+      sprintf(line_bufp + buf_offset, "%-12s", cf->cinfo.col_data[i]);
+      break;
+
+    default:
+      column_len = strlen(cf->cinfo.col_data[i]);
+      line_bufp = get_line_buf(buf_offset + column_len);
+      strcat(line_bufp + buf_offset, cf->cinfo.col_data[i]);
+      break;
+    }
+    buf_offset += column_len;
+    if (i != cf->cinfo.num_cols - 1) {
+      /*
+       * This isn't the last column, so we need to print a
+       * separator between this column and the next.
+       *
+       * If we printed a network source and are printing a
+       * network destination of the same type next, separate
+       * them with "->"; if we printed a network destination
+       * and are printing a network source of the same type
+       * next, separate them with "<-"; otherwise separate them
+       * with a space.
+       *
+       * We add enough space to the buffer for " <- " or " -> ",
+       * even if we're only adding " ".
+       */
+      line_bufp = get_line_buf(buf_offset + 4);
+      switch (cf->cinfo.col_fmt[i]) {
+
+      case COL_DEF_SRC:
+      case COL_RES_SRC:
+      case COL_UNRES_SRC:
+        switch (cf->cinfo.col_fmt[i + 1]) {
+
+        case COL_DEF_DST:
+        case COL_RES_DST:
+        case COL_UNRES_DST:
+          strcat(line_bufp + buf_offset, " -> ");
+          buf_offset += 4;
           break;
 
-        case COL_CLS_TIME:
-        case COL_REL_TIME:
-        case COL_ABS_TIME:
-        case COL_ABS_DATE_TIME:        /* XXX - wider */
-          printf("%10s", cf->cinfo.col_data[i]);
+        default:
+          strcat(line_bufp + buf_offset, " ");
+          buf_offset += 1;
           break;
+        }
+        break;
+
+      case COL_DEF_DL_SRC:
+      case COL_RES_DL_SRC:
+      case COL_UNRES_DL_SRC:
+        switch (cf->cinfo.col_fmt[i + 1]) {
+
+        case COL_DEF_DL_DST:
+        case COL_RES_DL_DST:
+        case COL_UNRES_DL_DST:
+          strcat(line_bufp + buf_offset, " -> ");
+          buf_offset += 4;
+          break;
+
+        default:
+          strcat(line_bufp + buf_offset, " ");
+          buf_offset += 1;
+          break;
+        }
+        break;
+
+      case COL_DEF_NET_SRC:
+      case COL_RES_NET_SRC:
+      case COL_UNRES_NET_SRC:
+        switch (cf->cinfo.col_fmt[i + 1]) {
+
+        case COL_DEF_NET_DST:
+        case COL_RES_NET_DST:
+        case COL_UNRES_NET_DST:
+          strcat(line_bufp + buf_offset, " -> ");
+          buf_offset += 4;
+          break;
+
+        default:
+          strcat(line_bufp + buf_offset, " ");
+          buf_offset += 1;
+          break;
+        }
+        break;
+
+      case COL_DEF_DST:
+      case COL_RES_DST:
+      case COL_UNRES_DST:
+        switch (cf->cinfo.col_fmt[i + 1]) {
 
         case COL_DEF_SRC:
         case COL_RES_SRC:
         case COL_UNRES_SRC:
+          strcat(line_bufp + buf_offset, " <- ");
+          buf_offset += 4;
+          break;
+
+        default:
+          strcat(line_bufp + buf_offset, " ");
+          buf_offset += 1;
+          break;
+        }
+        break;
+
+      case COL_DEF_DL_DST:
+      case COL_RES_DL_DST:
+      case COL_UNRES_DL_DST:
+        switch (cf->cinfo.col_fmt[i + 1]) {
+
         case COL_DEF_DL_SRC:
         case COL_RES_DL_SRC:
         case COL_UNRES_DL_SRC:
+          strcat(line_bufp + buf_offset, " <- ");
+          buf_offset += 4;
+          break;
+
+        default:
+          strcat(line_bufp + buf_offset, " ");
+          buf_offset += 1;
+          break;
+        }
+        break;
+
+      case COL_DEF_NET_DST:
+      case COL_RES_NET_DST:
+      case COL_UNRES_NET_DST:
+        switch (cf->cinfo.col_fmt[i + 1]) {
+
         case COL_DEF_NET_SRC:
         case COL_RES_NET_SRC:
         case COL_UNRES_NET_SRC:
-          printf("%12s", cf->cinfo.col_data[i]);
-          break;
-
-        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:
-          printf("%-12s", cf->cinfo.col_data[i]);
+          strcat(line_bufp + buf_offset, " <- ");
+          buf_offset += 4;
           break;
 
         default:
-          printf("%s", cf->cinfo.col_data[i]);
+          strcat(line_bufp + buf_offset, " ");
+          buf_offset += 1;
           break;
         }
-        if (i != cf->cinfo.num_cols - 1) {
-          /*
-          * This isn't the last column, so we need to print a
-          * separator between this column and the next.
-          *
-          * If we printed a network source and are printing a
-          * network destination of the same type next, separate
-          * them with "->"; if we printed a network destination
-          * and are printing a network source of the same type
-          * next, separate them with "<-"; otherwise separate them
-          * with a space.
-          */
-         switch (cf->cinfo.col_fmt[i]) {
-
-         case COL_DEF_SRC:
-         case COL_RES_SRC:
-         case COL_UNRES_SRC:
-           switch (cf->cinfo.col_fmt[i + 1]) {
-
-           case COL_DEF_DST:
-           case COL_RES_DST:
-           case COL_UNRES_DST:
-             printf(" -> ");
-             break;
-
-           default:
-             putchar(' ');
-             break;
-           }
-           break;
-
-         case COL_DEF_DL_SRC:
-         case COL_RES_DL_SRC:
-         case COL_UNRES_DL_SRC:
-           switch (cf->cinfo.col_fmt[i + 1]) {
-
-           case COL_DEF_DL_DST:
-           case COL_RES_DL_DST:
-           case COL_UNRES_DL_DST:
-             printf(" -> ");
-             break;
-
-           default:
-             putchar(' ');
-             break;
-           }
-           break;
-
-         case COL_DEF_NET_SRC:
-         case COL_RES_NET_SRC:
-         case COL_UNRES_NET_SRC:
-           switch (cf->cinfo.col_fmt[i + 1]) {
-
-           case COL_DEF_NET_DST:
-           case COL_RES_NET_DST:
-           case COL_UNRES_NET_DST:
-             printf(" -> ");
-             break;
-
-           default:
-             putchar(' ');
-             break;
-           }
-           break;
-
-         case COL_DEF_DST:
-         case COL_RES_DST:
-         case COL_UNRES_DST:
-           switch (cf->cinfo.col_fmt[i + 1]) {
-
-           case COL_DEF_SRC:
-           case COL_RES_SRC:
-           case COL_UNRES_SRC:
-             printf(" <- ");
-             break;
-
-           default:
-             putchar(' ');
-             break;
-           }
-           break;
-
-         case COL_DEF_DL_DST:
-         case COL_RES_DL_DST:
-         case COL_UNRES_DL_DST:
-           switch (cf->cinfo.col_fmt[i + 1]) {
-
-           case COL_DEF_DL_SRC:
-           case COL_RES_DL_SRC:
-           case COL_UNRES_DL_SRC:
-             printf(" <- ");
-             break;
-
-           default:
-             putchar(' ');
-             break;
-           }
-           break;
-
-         case COL_DEF_NET_DST:
-         case COL_RES_NET_DST:
-         case COL_UNRES_NET_DST:
-           switch (cf->cinfo.col_fmt[i + 1]) {
-
-           case COL_DEF_NET_SRC:
-           case COL_RES_NET_SRC:
-           case COL_UNRES_NET_SRC:
-             printf(" <- ");
-             break;
-
-           default:
-             putchar(' ');
-             break;
-           }
-           break;
+        break;
 
-         default:
-           putchar(' ');
-           break;
-         }
-       }
+      default:
+        strcat(line_bufp + buf_offset, " ");
+        buf_offset += 1;
+        break;
       }
-      putchar('\n');
-    }
-    if (print_hex) {
-      print_hex_data(stdout, print_args.format, edt);
-      putchar('\n');
     }
   }
+  return print_line(print_stream, 0, line_bufp);
+}
+
+static gboolean
+print_packet(capture_file *cf, epan_dissect_t *edt)
+{
+  print_args_t  print_args;
+
+  if (verbose) {
+    /* Print the information in the protocol tree. */
+    switch (output_action) {
+
+    case WRITE_TEXT:
+      print_args.to_file = TRUE;
+      print_args.format = print_format;
+      print_args.print_summary = !verbose;
+      print_args.print_hex = verbose && print_hex;
+      print_args.print_formfeed = FALSE;
+      print_args.print_dissections = verbose ? print_dissections_expanded : print_dissections_none;
 
-  /* The ANSI C standard does not appear to *require* that a line-buffered
-     stream be flushed to the host environment whenever a newline is
-     written, it just says that, on such a stream, characters "are
-     intended to be transmitted to or from the host environment as a
-     block when a new-line character is encountered".
+      /* init the packet range */
+      packet_range_init(&print_args.range);
 
-     The Visual C++ 6.0 C implementation doesn't do what is intended;
-     even if you set a stream to be line-buffered, it still doesn't
-     flush the buffer at the end of every line.
+      if (!proto_tree_print(&print_args, edt, print_stream))
+        return FALSE;
+      if (!print_hex) {
+        /* "print_hex_data()" will put out a leading blank line, as well
+         as a trailing one; print one here, to separate the packets,
+         only if "print_hex_data()" won't be called. */
+        if (!print_line(print_stream, 0, ""))
+          return FALSE;
+      }
+      break;
 
-     So, if the "-l" flag was specified, we flush the standard output
-     at the end of a packet.  This will do the right thing if we're
-     printing packet summary lines, and, as we print the entire protocol
-     tree for a single packet without waiting for anything to happen,
-     it should be as good as line-buffered mode if we're printing
-     protocol trees.  (The whole reason for the "-l" flag in either
-     tcpdump or Tethereal is to allow the output of a live capture to
-     be piped to a program or script and to have that script see the
-     information for the packet as soon as it's printed, rather than
-     having to wait until a standard I/O buffer fills up. */
-  if (line_buffered)
-    fflush(stdout);
+    case WRITE_XML:
+      proto_tree_write_pdml(edt, stdout);
+      printf("\n");
+      return !ferror(stdout);
+    }
+  } else {
+    /* Just fill in the columns. */
+    epan_dissect_fill_in_columns(edt);
 
-  epan_dissect_free(edt);
+    /* Now print them. */
+    switch (output_action) {
 
-  clear_fdata(&fdata);
+    case WRITE_TEXT:
+        if (!print_columns(cf))
+          return FALSE;
+        break;
+
+    case WRITE_XML:
+        proto_tree_write_psml(edt, stdout);
+        return !ferror(stdout);
+    }
+  }
+  if (print_hex) {
+    if (!print_hex_data(print_stream, edt))
+      return FALSE;
+    if (!print_line(print_stream, 0, ""))
+      return FALSE;
+  }
+  return TRUE;
 }
 
-char *
-file_open_error_message(int err, gboolean for_writing, int file_type)
+static gboolean
+write_finale(void)
 {
-  char *errmsg;
-  static char errmsg_errno[1024+1];
+  switch (output_action) {
+
+  case WRITE_TEXT:
+    return print_finale(print_stream);
+    break;
+
+  case WRITE_XML:
+    if (verbose)
+      write_pdml_finale(stdout);
+    else
+      write_psml_finale(stdout);
+    return !ferror(stdout);
+
+  default:
+    g_assert_not_reached();
+    return FALSE;
+  }
+}
 
+static void
+show_print_file_io_error(int err)
+{
   switch (err) {
 
-  case WTAP_ERR_NOT_REGULAR_FILE:
-    errmsg = "The file \"%s\" is a \"special file\" or socket or other non-regular file.";
+  case ENOSPC:
+    fprintf(stderr,
+"tethereal: Not all the packets could be printed because there is "
+"no space left on the file system.\n");
     break;
 
-  case WTAP_ERR_FILE_UNKNOWN_FORMAT:
-  case WTAP_ERR_UNSUPPORTED:
-    /* Seen only when opening a capture file for reading. */
-    errmsg = "The file \"%s\" is not a capture file in a format Tethereal understands.";
-    break;
+#ifdef EDQUOT
+  case EDQUOT:
+    fprintf(stderr,
+"tethereal: Not all the packets could be printed because you are "
+"too close to, or over your disk quota.\n");
+  break;
+#endif
 
-  case WTAP_ERR_CANT_WRITE_TO_PIPE:
-    /* Seen only when opening a capture file for writing. */
-    snprintf(errmsg_errno, sizeof(errmsg_errno),
-            "The file \"%%s\" is a pipe, and %s capture files cannot be "
-            "written to a pipe.", wtap_file_type_string(file_type));
-    errmsg = errmsg_errno;
+  default:
+    fprintf(stderr,
+"tethereal: An error occurred while printing packets: %s.\n",
+      strerror(err));
     break;
+  }
+}
 
-  case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
-    /* Seen only when opening a capture file for writing. */
-    errmsg = "Tethereal does not support writing capture files in that format.";
-    break;
+static char *
+cf_open_error_message(int err, gchar *err_info, gboolean for_writing,
+                      int file_type)
+{
+  char *errmsg;
+  static char errmsg_errno[1024+1];
 
-  case WTAP_ERR_UNSUPPORTED_ENCAP:
-  case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
-    if (for_writing)
-      errmsg = "Tethereal cannot save this capture in that format.";
-    else
-      errmsg = "The file \"%s\" is a capture for a network type that Tethereal doesn't support.";
-    break;
+  if (err < 0) {
+    /* Wiretap error. */
+    switch (err) {
 
-  case WTAP_ERR_BAD_RECORD:
-    errmsg = "The file \"%s\" appears to be damaged or corrupt.";
-    break;
+    case WTAP_ERR_NOT_REGULAR_FILE:
+      errmsg = "The file \"%s\" is a \"special file\" or socket or other non-regular file.";
+      break;
 
-  case WTAP_ERR_CANT_OPEN:
-    if (for_writing)
-      errmsg = "The file \"%s\" could not be created for some unknown reason.";
-    else
-      errmsg = "The file \"%s\" could not be opened for some unknown reason.";
-    break;
+    case WTAP_ERR_FILE_UNKNOWN_FORMAT:
+      /* Seen only when opening a capture file for reading. */
+      errmsg = "The file \"%s\" isn't a capture file in a format Tethereal understands.";
+      break;
 
-  case WTAP_ERR_SHORT_READ:
-    errmsg = "The file \"%s\" appears to have been cut short"
-             " in the middle of a packet or other data.";
-    break;
+    case WTAP_ERR_UNSUPPORTED:
+      /* Seen only when opening a capture file for reading. */
+      snprintf(errmsg_errno, sizeof(errmsg_errno),
+               "The file \"%%s\" isn't a capture file in a format Tethereal understands.\n"
+               "(%s)", err_info);
+      g_free(err_info);
+      errmsg = errmsg_errno;
+      break;
 
-  case WTAP_ERR_SHORT_WRITE:
-    errmsg = "A full header couldn't be written to the file \"%s\".";
-    break;
+    case WTAP_ERR_CANT_WRITE_TO_PIPE:
+      /* Seen only when opening a capture file for writing. */
+      snprintf(errmsg_errno, sizeof(errmsg_errno),
+              "The file \"%%s\" is a pipe, and %s capture files can't be "
+              "written to a pipe.", wtap_file_type_string(file_type));
+      errmsg = errmsg_errno;
+      break;
 
-  case ENOENT:
-    if (for_writing)
-      errmsg = "The path to the file \"%s\" does not exist.";
-    else
-      errmsg = "The file \"%s\" does not exist.";
-    break;
+    case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
+      /* Seen only when opening a capture file for writing. */
+      errmsg = "Tethereal doesn't support writing capture files in that format.";
+      break;
 
-  case EACCES:
-    if (for_writing)
-      errmsg = "You do not have permission to create or write to the file \"%s\".";
-    else
-      errmsg = "You do not have permission to read the file \"%s\".";
-    break;
+    case WTAP_ERR_UNSUPPORTED_ENCAP:
+      if (for_writing)
+        errmsg = "Tethereal can't save this capture in that format.";
+      else {
+        snprintf(errmsg_errno, sizeof(errmsg_errno),
+                 "The file \"%%s\" is a capture for a network type that Tethereal doesn't support.\n"
+                 "(%s)", err_info);
+        g_free(err_info);
+        errmsg = errmsg_errno;
+      }
+      break;
 
-  case EISDIR:
-    errmsg = "\"%s\" is a directory (folder), not a file.";
-    break;
+    case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
+      if (for_writing)
+        errmsg = "Tethereal can't save this capture in that format.";
+      else
+        errmsg = "The file \"%s\" is a capture for a network type that Tethereal doesn't support.";
+      break;
 
-  default:
-    snprintf(errmsg_errno, sizeof(errmsg_errno),
-            "The file \"%%s\" could not be %s: %s.",
-            for_writing ? "created" : "opened",
-            wtap_strerror(err));
-    errmsg = errmsg_errno;
-    break;
-  }
+    case WTAP_ERR_BAD_RECORD:
+      /* Seen only when opening a capture file for reading. */
+      snprintf(errmsg_errno, sizeof(errmsg_errno),
+               "The file \"%%s\" appears to be damaged or corrupt.\n"
+               "(%s)", err_info);
+      g_free(err_info);
+      errmsg = errmsg_errno;
+      break;
+
+    case WTAP_ERR_CANT_OPEN:
+      if (for_writing)
+        errmsg = "The file \"%s\" could not be created for some unknown reason.";
+      else
+        errmsg = "The file \"%s\" could not be opened for some unknown reason.";
+      break;
+
+    case WTAP_ERR_SHORT_READ:
+      errmsg = "The file \"%s\" appears to have been cut short"
+               " in the middle of a packet or other data.";
+      break;
+
+    case WTAP_ERR_SHORT_WRITE:
+      errmsg = "A full header couldn't be written to the file \"%s\".";
+      break;
+
+    default:
+      snprintf(errmsg_errno, sizeof(errmsg_errno),
+              "The file \"%%s\" could not be %s: %s.",
+              for_writing ? "created" : "opened",
+              wtap_strerror(err));
+      errmsg = errmsg_errno;
+      break;
+    }
+  } else
+    errmsg = file_open_error_message(err, for_writing);
   return errmsg;
 }
 
-int
-cf_open(char *fname, gboolean is_tempfile, capture_file *cf)
+/*
+ * Open/create errors are reported with an console message in Tethereal.
+ */
+static void
+open_failure_message(const char *filename, int err, gboolean for_writing)
+{
+  fprintf(stderr, "tethereal: ");
+  fprintf(stderr, file_open_error_message(err, for_writing), filename);
+  fprintf(stderr, "\n");
+}
+
+cf_status_t
+cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
 {
   wtap       *wth;
-  int         err;
+  gchar       *err_info;
   char        err_msg[2048+1];
 
-  wth = wtap_open_offline(fname, &err, FALSE);
+  wth = wtap_open_offline(fname, err, &err_info, FALSE);
   if (wth == NULL)
     goto fail;
 
@@ -2947,13 +3009,13 @@ cf_open(char *fname, gboolean is_tempfile, capture_file *cf)
   firstsec = 0, firstusec = 0;
   prevsec = 0, prevusec = 0;
 
-  return (0);
+  return CF_OK;
 
 fail:
-  snprintf(err_msg, sizeof err_msg, file_open_error_message(err, FALSE, 0),
-          fname);
+  snprintf(err_msg, sizeof err_msg,
+           cf_open_error_message(*err, err_info, FALSE, 0), fname);
   fprintf(stderr, "tethereal: %s\n", err_msg);
-  return (err);
+  return CF_ERROR;
 }
 
 #ifdef HAVE_LIBPCAP
@@ -2961,9 +3023,9 @@ fail:
 /* Take care of byte order in the libpcap headers read from pipes.
  * (function taken from wiretap/libpcap.c) */
 static void
-adjust_header(loop_data *ld, struct pcap_hdr *hdr, struct pcaprec_hdr *rechdr)
+adjust_header(loop_data *ldat, struct pcap_hdr *hdr, struct pcaprec_hdr *rechdr)
 {
-  if (ld->byte_swapped) {
+  if (ldat->byte_swapped) {
     /* Byte-swap the record header fields. */
     rechdr->ts_sec = BSWAP32(rechdr->ts_sec);
     rechdr->ts_usec = BSWAP32(rechdr->ts_usec);
@@ -2995,7 +3057,7 @@ adjust_header(loop_data *ld, struct pcap_hdr *hdr, struct pcaprec_hdr *rechdr)
  * N.B. : we can't read the libpcap formats used in RedHat 6.1 or SuSE 6.3
  * because we can't seek on pipes (see wiretap/libpcap.c for details) */
 static int
-pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
+pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ldat,
                  char *errmsg, int errmsgl)
 {
   struct stat pipe_stat;
@@ -3012,12 +3074,12 @@ pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
   else {
     if (stat(pipename, &pipe_stat) < 0) {
       if (errno == ENOENT || errno == ENOTDIR)
-        ld->pipe_err = PIPNEXIST;
+        ldat->pipe_err = PIPNEXIST;
       else {
         snprintf(errmsg, errmsgl,
           "The capture session could not be initiated "
           "due to error on pipe: %s", strerror(errno));
-        ld->pipe_err = PIPERR;
+        ldat->pipe_err = PIPERR;
       }
       return -1;
     }
@@ -3027,12 +3089,12 @@ pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
          * Assume the user specified an interface on a system where
          * interfaces are in /dev.  Pretend we haven't seen it.
          */
-         ld->pipe_err = PIPNEXIST;
+         ldat->pipe_err = PIPNEXIST;
       } else {
         snprintf(errmsg, errmsgl,
             "The capture session could not be initiated because\n"
             "\"%s\" is neither an interface nor a pipe", pipename);
-        ld->pipe_err = PIPERR;
+        ldat->pipe_err = PIPERR;
       }
       return -1;
     }
@@ -3041,12 +3103,12 @@ pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
       snprintf(errmsg, errmsgl,
           "The capture session could not be initiated "
           "due to error on pipe open: %s", strerror(errno));
-      ld->pipe_err = PIPERR;
+      ldat->pipe_err = PIPERR;
       return -1;
     }
   }
 
-  ld->from_pipe = TRUE;
+  ldat->from_pipe = TRUE;
 
   /* read the pcap header */
   bytes_read = 0;
@@ -3067,28 +3129,28 @@ pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
   case PCAP_MAGIC:
     /* Host that wrote it has our byte order, and was running
        a program using either standard or ss990417 libpcap. */
-    ld->byte_swapped = FALSE;
-    ld->modified = FALSE;
+    ldat->byte_swapped = FALSE;
+    ldat->modified = FALSE;
     break;
   case PCAP_MODIFIED_MAGIC:
     /* Host that wrote it has our byte order, but was running
        a program using either ss990915 or ss991029 libpcap. */
-    ld->byte_swapped = FALSE;
-    ld->modified = TRUE;
+    ldat->byte_swapped = FALSE;
+    ldat->modified = TRUE;
     break;
   case PCAP_SWAPPED_MAGIC:
     /* Host that wrote it has a byte order opposite to ours,
        and was running a program using either standard or
        ss990417 libpcap. */
-    ld->byte_swapped = TRUE;
-    ld->modified = FALSE;
+    ldat->byte_swapped = TRUE;
+    ldat->modified = FALSE;
     break;
   case PCAP_SWAPPED_MODIFIED_MAGIC:
     /* Host that wrote it out has a byte order opposite to
        ours, and was running a program using either ss990915
        or ss991029 libpcap. */
-    ld->byte_swapped = TRUE;
-    ld->modified = TRUE;
+    ldat->byte_swapped = TRUE;
+    ldat->modified = TRUE;
     break;
   default:
     /* Not a "libpcap" type we know about. */
@@ -3112,7 +3174,7 @@ pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
     bytes_read += b;
   }
 
-  if (ld->byte_swapped) {
+  if (ldat->byte_swapped) {
     /* Byte-swap the header fields about which we care. */
     hdr->version_major = BSWAP16(hdr->version_major);
     hdr->version_minor = BSWAP16(hdr->version_minor);
@@ -3125,12 +3187,12 @@ pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
     goto error;
   }
 
-  ld->pipe_state = STATE_EXPECT_REC_HDR;
-  ld->pipe_err = PIPOK;
+  ldat->pipe_state = STATE_EXPECT_REC_HDR;
+  ldat->pipe_err = PIPOK;
   return fd;
 
 error:
-  ld->pipe_err = PIPERR;
+  ldat->pipe_err = PIPERR;
   close(fd);
   return -1;
 
@@ -3139,7 +3201,7 @@ error:
  * header, write the record in the capture file, and update capture statistics. */
 
 static int
-pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr,
+pipe_dispatch(int fd, loop_data *ldat, struct pcap_hdr *hdr,
                 struct pcaprec_modified_hdr *rechdr, guchar *data,
                 char *errmsg, int errmsgl)
 {
@@ -3148,18 +3210,18 @@ pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr,
   enum { PD_REC_HDR_READ, PD_DATA_READ, PD_PIPE_EOF, PD_PIPE_ERR,
           PD_ERR } result;
 
-  switch (ld->pipe_state) {
+  switch (ldat->pipe_state) {
 
   case STATE_EXPECT_REC_HDR:
-    ld->bytes_to_read = ld->modified ?
+    ldat->bytes_to_read = ldat->modified ?
       sizeof(struct pcaprec_modified_hdr) : sizeof(struct pcaprec_hdr);
-    ld->bytes_read = 0;
-    ld->pipe_state = STATE_READ_REC_HDR;
+    ldat->bytes_read = 0;
+    ldat->pipe_state = STATE_READ_REC_HDR;
     /* Fall through */
 
   case STATE_READ_REC_HDR:
-    b = read(fd, ((char *)rechdr)+ld->bytes_read,
-      ld->bytes_to_read - ld->bytes_read);
+    b = read(fd, ((char *)rechdr)+ldat->bytes_read,
+      ldat->bytes_to_read - ldat->bytes_read);
     if (b <= 0) {
       if (b == 0)
         result = PD_PIPE_EOF;
@@ -3167,18 +3229,18 @@ pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr,
         result = PD_PIPE_ERR;
       break;
     }
-    if ((ld->bytes_read += b) < ld->bytes_to_read)
+    if ((ldat->bytes_read += b) < ldat->bytes_to_read)
         return 0;
     result = PD_REC_HDR_READ;
     break;
 
   case STATE_EXPECT_DATA:
-    ld->bytes_read = 0;
-    ld->pipe_state = STATE_READ_DATA;
+    ldat->bytes_read = 0;
+    ldat->pipe_state = STATE_READ_DATA;
     /* Fall through */
 
   case STATE_READ_DATA:
-    b = read(fd, data+ld->bytes_read, rechdr->hdr.incl_len - ld->bytes_read);
+    b = read(fd, data+ldat->bytes_read, rechdr->hdr.incl_len - ldat->bytes_read);
     if (b <= 0) {
       if (b == 0)
         result = PD_PIPE_EOF;
@@ -3186,7 +3248,7 @@ pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr,
         result = PD_PIPE_ERR;
       break;
     }
-    if ((ld->bytes_read += b) < rechdr->hdr.incl_len)
+    if ((ldat->bytes_read += b) < rechdr->hdr.incl_len)
       return 0;
     result = PD_DATA_READ;
     break;
@@ -3195,7 +3257,7 @@ pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr,
     snprintf(errmsg, errmsgl, "pipe_dispatch: invalid state");
     result = PD_ERR;
 
-  } /* switch (ld->pipe_state) */
+  } /* switch (ldat->pipe_state) */
 
   /*
    * We've now read as much data as we were expecting, so process it.
@@ -3204,13 +3266,13 @@ pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr,
 
   case PD_REC_HDR_READ:
     /* We've read the header. Take care of byte order. */
-    adjust_header(ld, hdr, &rechdr->hdr);
+    adjust_header(ldat, hdr, &rechdr->hdr);
     if (rechdr->hdr.incl_len > WTAP_MAX_PACKET_SIZE) {
       snprintf(errmsg, errmsgl, "Frame %u too long (%d bytes)",
-        ld->packet_count+1, rechdr->hdr.incl_len);
+        ldat->packet_count+1, rechdr->hdr.incl_len);
       break;
     }
-    ld->pipe_state = STATE_EXPECT_DATA;
+    ldat->pipe_state = STATE_EXPECT_DATA;
     return 0;
 
   case PD_DATA_READ:
@@ -3220,13 +3282,13 @@ pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr,
     phdr.caplen = rechdr->hdr.incl_len;
     phdr.len = rechdr->hdr.orig_len;
 
-    capture_pcap_cb((guchar *)ld, &phdr, data);
+    capture_pcap_cb((guchar *)ldat, &phdr, data);
 
-    ld->pipe_state = STATE_EXPECT_REC_HDR;
+    ldat->pipe_state = STATE_EXPECT_REC_HDR;
     return 1;
 
   case PD_PIPE_EOF:
-    ld->pipe_err = PIPEOF;
+    ldat->pipe_err = PIPEOF;
     return -1;
 
   case PD_PIPE_ERR:
@@ -3237,9 +3299,30 @@ pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr,
     break;
   }
 
-  ld->pipe_err = PIPERR;
+  ldat->pipe_err = PIPERR;
   /* Return here rather than inside the switch to prevent GCC warning */
   return -1;
 }
 #endif /* _WIN32 */
 #endif /* HAVE_LIBPCAP */
+
+/*
+ * General errors are reported with an console message in Tethereal.
+ */
+static void
+failure_message(const char *msg_format, va_list ap)
+{
+  fprintf(stderr, "tethereal: ");
+  vfprintf(stderr, msg_format, ap);
+  fprintf(stderr, "\n");
+}
+
+/*
+ * Read errors are reported with an console message in Tethereal.
+ */
+static void
+read_failure_message(const char *filename, int err)
+{
+  fprintf(stderr, "tethereal: An error occurred while reading from the file \"%s\": %s.\n",
+          filename, strerror(err));
+}