Put the low-level sync routines into a common file so they can be shared
[metze/wireshark/wip.git] / tethereal.c
index 133dbb1e3aa34818415ae34d9c0b490122840025..b2fb7a091303681be6dd3d35a01fc438b3c58bd9 100644 (file)
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
-/* With MSVC and a libethereal.dll this file needs to import some variables 
-   in a special way. Therefore _NEED_VAR_IMPORT_ is defined. */
-#define _NEED_VAR_IMPORT_
-
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
 
 #include <signal.h>
 
-#ifdef HAVE_LIBPCAP
-#include <pcap.h>
-#include <setjmp.h>
-#endif
-
 #ifdef HAVE_SYS_STAT_H
 # include <sys/stat.h>
 #endif
 
-#ifdef NEED_SNPRINTF_H
-# include "snprintf.h"
-#endif
-
 #ifdef NEED_STRERROR_H
 #include "strerror.h"
 #endif
 #include "getopt.h"
 #endif
 
-#include "svnversion.h"
-
 #include <glib.h>
 #include <epan/epan.h>
 #include <epan/filesystem.h>
+#include <epan/privileges.h>
+#include <wiretap/file_util.h>
 
 #include "globals.h"
 #include <epan/timestamp.h>
 #include <epan/addr_resolv.h>
 #include "util.h"
 #include "clopts_common.h"
+#include "cmdarg_err.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 "capture_ui_utils.h"
 #include <epan/epan_dissect.h>
 #include <epan/tap.h>
+#include <epan/stat_cmd_args.h>
 #include <epan/timestamp.h>
+#include <epan/ex-opt.h>
 
 #ifdef HAVE_LIBPCAP
+#include <pcap.h>
+#include <setjmp.h>
+#include "capture-pcap-util.h"
+#include "pcapio.h"
 #include <wiretap/wtap-capture.h>
-#include <wiretap/libpcap.h>
-#endif
-
 #ifdef _WIN32
 #include "capture-wpcap.h"
-#endif
+#include "capture_errs.h"
+#endif /* _WIN32 */
+#include "capture.h"
+#include "capture_loop.h"
+#include "capture_sync.h"
+#endif /* HAVE_LIBPCAP */
+#include "epan/emem.h"
+#include "log.h"
+#include <epan/funnel.h>
 
 /*
  * This is the template for the decode as option; it is shared between the
  */
 static const gchar decode_as_arg_template[] = "<layer_type>==<selector>,<decode_as_protocol>";
 
-static guint32 firstsec, firstusec;
-static guint32 prevsec, prevusec;
+static nstime_t first_ts;
+static nstime_t prev_ts;
 static GString *comp_info_str, *runtime_info_str;
-static gboolean quiet;
 
 static gboolean print_packet_info;     /* TRUE if we're to print packet information */
 /*
@@ -142,74 +137,24 @@ static guint32 cum_bytes = 0;
 static print_format_e print_format = PR_FMT_TEXT;
 static print_stream_t *print_stream;
 
+/*
+ * Standard secondary message for unexpected errors.
+ */
+static const char please_report[] =
+    "Please report this to the Ethereal developers";
+
 #ifdef HAVE_LIBPCAP
-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;
-  int            packet_count;
-#ifndef _WIN32
-  gboolean       modified;     /* TRUE if data in the pipe uses modified pcap headers */
-  gboolean       byte_swapped; /* TRUE if data in the pipe is byte swapped */
-  unsigned int   bytes_to_read, bytes_read; /* Used by pipe_dispatch */
-  enum {
-         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;
+/*
+ * TRUE if we're to print packet counts to keep track of captured packets.
+ */
+static gboolean print_packet_counts;
+
 
 static loop_data ld;
 
 #ifdef HAVE_LIBPCAP
-typedef struct {
-    gchar    *cfilter;              /* Capture filter string */
-    gchar    *iface;                /* the network interface to capture from */
-    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 = {
-    "",                             /* No capture filter string specified */
-    NULL,                           /* Default is "pick the first interface" */
-    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 capture_options capture_opts;
 
-static gboolean list_link_layer_types;
 
 #ifdef SIGINFO
 static gboolean infodelay;     /* if TRUE, don't print capture info in SIGINFO handler */
@@ -218,9 +163,9 @@ static gboolean infoprint;  /* if TRUE, print capture info after clearing infodel
 #endif /* HAVE_LIBPCAP */
 
 
-static int capture(char *, int);
-static void capture_pcap_cb(guchar *, const struct pcap_pkthdr *,
-  const guchar *);
+static int capture(void);
+static void capture_pcap_cb(u_char *, const struct pcap_pkthdr *,
+  const u_char *);
 static void report_counts(void);
 #ifdef _WIN32
 static BOOL WINAPI capture_cleanup(DWORD);
@@ -233,24 +178,16 @@ static void report_counts_siginfo(int);
 #endif /* HAVE_LIBPCAP */
 
 static int load_cap_file(capture_file *, char *, int);
-static gboolean process_packet(capture_file *cf, wtap_dumper *pdh, long offset,
+static gboolean process_packet(capture_file *cf, long offset,
     const struct wtap_pkthdr *whdr, union wtap_pseudo_header *pseudo_header,
-    const guchar *pd, int *err);
+    const guchar *pd);
 static void show_capture_file_io_error(const char *, int, gboolean);
 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,
+static const 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 *);
-static int pipe_open_live(char *, struct pcap_hdr *, loop_data *, char *, int);
-static int pipe_dispatch(int, loop_data *, struct pcap_hdr *, \
-                struct pcaprec_modified_hdr *, guchar *, char *, int);
-#endif /* _WIN32 */
-#endif
 
 static void open_failure_message(const char *filename, int err,
     gboolean for_writing);
@@ -260,211 +197,95 @@ static void read_failure_message(const char *filename, int err);
 capture_file cfile;
 
 
+static void list_capture_types(void) {
+    int i;
+
+    fprintf(stderr, "editcap: The available capture file types for \"F\":\n");
+    for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
+      if (wtap_dump_can_open(i))
+        fprintf(stderr, "    %s - %s\n",
+          wtap_file_type_short_string(i), wtap_file_type_string(i));
+    }
+}
+
 static void
 print_usage(gboolean print_ver)
 {
-  int i;
   FILE *output;
 
   if (print_ver) {
     output = stdout;
-    fprintf(output, "This is GNU t" PACKAGE " " VERSION
-#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);
+    fprintf(output, 
+        "Tethereal " VERSION "%s\n"
+        "Dump and analyze network traffic.\n"
+        "See http://www.ethereal.com for more information.\n"
+        "\n"
+        "%s",
+       svnversion, get_copyright_info());
   } else {
     output = stderr;
   }
-#ifdef HAVE_LIBPCAP
-  fprintf(output, "\nt%s [ -vh ] [ -DlLnpqSVx ] [ -a <capture autostop condition> ] ...\n",
-         PACKAGE);
-  fprintf(output, "\t[ -b <number of ring buffer files>[:<duration>] ] [ -c <count> ]\n");
-  fprintf(output, "\t[ -d %s ] ...\n", decode_as_arg_template);
-  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|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|psml|text ] [ -w <savefile> ]\n");
-  fprintf(output, "\t[ -z <statistics string> ]\n");
-#endif
-  fprintf(output, "Valid file type arguments to the \"-F\" flag:\n");
-  for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
-    if (wtap_dump_can_open(i))
-      fprintf(output, "\t%s - %s\n",
-        wtap_file_type_short_string(i), wtap_file_type_string(i));
-  }
-  fprintf(output, "\tdefault is libpcap\n");
-}
+  fprintf(output, "\n");
+  fprintf(output, "Usage: tethereal [options] ...\n");
+  fprintf(output, "\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\" isn't 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;
-}
+  fprintf(output, "Capture interface:\n");
+  fprintf(output, "  -i <interface>           name or idx of interface (def: first none loopback)\n");
+  fprintf(output, "  -f <capture filter>      packet filter in libpcap filter syntax\n");
+  fprintf(output, "  -s <snaplen>             packet snapshot length (def: 65535)\n");
+  fprintf(output, "  -p                       don't capture in promiscuous mode\n");
+#ifdef _WIN32
+  fprintf(output, "  -B <buffer size>         size of kernel buffer (def: 1MB)\n");
 #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;
-
+  fprintf(output, "  -y <link type>           link layer type (def: first appropriate)\n");
+  fprintf(output, "  -D                       print list of interfaces and exit\n");
+  fprintf(output, "  -L                       print list of link-layer types of iface and exit\n");
+  fprintf(output, "\n");
+  fprintf(output, "Capture stop conditions:\n");
+  fprintf(output, "  -c <packet count>        stop after n packets (def: infinite)\n");
+  fprintf(output, "  -a <autostop cond.> ...  duration:NUM - stop after NUM seconds\n");
+  fprintf(output, "                           filesize:NUM - stop this file after NUM KB\n");
+  fprintf(output, "                              files:NUM - stop after NUM files\n");
+  /*fprintf(output, "\n");*/
+  fprintf(output, "Capture output:\n");
+  fprintf(output, "  -b <ringbuffer opt.> ... duration:NUM - switch to next file after NUM secs\n");
+  fprintf(output, "                           filesize:NUM - switch to next file after NUM KB\n");
+  fprintf(output, "                              files:NUM - ringbuffer: replace after NUM files\n");
+#endif  /* HAVE_LIBPCAP */
+
+  /*fprintf(output, "\n");*/
+  fprintf(output, "Input file:\n");
+  fprintf(output, "  -r <infile>              set the filename to read from (no pipes or stdin!)\n");
+
+  fprintf(output, "\n");
+  fprintf(output, "Processing:\n");
+  fprintf(output, "  -R <read filter>         packet filter in Ethereal display filter syntax\n");
+  fprintf(output, "  -n                       disable all name resolutions (def: all enabled)\n");
+  fprintf(output, "  -N <name resolve flags>  enable specific name resolution(s): \"mntC\"\n");
+  fprintf(output, "  -d %s ...\n", decode_as_arg_template);
+  fprintf(output, "                           \"Decode As\", see the man page for details\n");
+  fprintf(output, "                           Example: tcp.port==8888,http\n");
+
+  /*fprintf(output, "\n");*/
+  fprintf(output, "Output:\n");
+  fprintf(stderr, "  -w <outfile|->           set the output filename (or '-' for stdout)\n");
+  fprintf(stderr, "  -F <output file type>    set the output file type, default is libpcap\n");
+  fprintf(stderr, "                           an empty \"-F\" option will list the file types\n");
+  fprintf(output, "  -V                       add output of packet tree        (Packet Details)\n");
+  fprintf(output, "  -x                       add output of hex and ASCII dump (Packet Bytes)\n");
+  fprintf(output, "  -T pdml|ps|psml|text     output format of text output (def: text)\n");
+  fprintf(output, "  -t ad|a|r|d              output format of time stamps (def: r: rel. to first)\n");
+  fprintf(output, "  -l                       flush output after each packet\n");
+  fprintf(output, "  -q                       be more quiet on stdout (e.g. when using statistics)\n");
+  fprintf(output, "  -X <key>:<value>         eXtension options, see the man page for details\n");
+  fprintf(output, "  -z <statistics>          various statistics, see the man page for details\n");
+
+  fprintf(output, "\n");
+  fprintf(stderr, "Miscellaneous:\n");
+  fprintf(stderr, "  -h                       display this help and exit\n");
+  fprintf(stderr, "  -v                       display version info and exit\n");
+  fprintf(output, "  -o <name>:<value> ...   override preference setting\n");
 }
 
 /*
@@ -473,7 +294,8 @@ register_ethereal_tap(char *cmd, void (*func)(char *arg))
  * descriptive name.
  */
 static void
-display_dissector_table_names(char *table_name, char *ui_name, gpointer output)
+display_dissector_table_names(char *table_name, const char *ui_name,
+                              gpointer output)
 {
   fprintf((FILE *)output, "\t%s (%s)\n", table_name, ui_name);
 }
@@ -484,7 +306,7 @@ display_dissector_table_names(char *table_name, char *ui_name, gpointer output)
  * name for the protocol that corresponds to this handle.
  */
 static void
-display_dissector_names(gchar *table _U_, gpointer handle, gpointer output)
+display_dissector_names(const gchar *table _U_, gpointer handle, gpointer output)
 {
   int                proto_id;
   const gchar*       proto_filter_name;
@@ -525,7 +347,7 @@ typedef struct protocol_name_search *protocol_name_search_t;
  * whole list of dissectors.
  */
 static void
-find_protocol_name_func(gchar *table _U_, gpointer handle, gpointer user_data)
+find_protocol_name_func(const gchar *table _U_, gpointer handle, gpointer user_data)
 
 {
   int                         proto_id;
@@ -618,7 +440,7 @@ add_decode_as(const gchar *cl_param)
 
   remaining_param = strchr(table_name, '=');
   if (remaining_param == NULL) {
-    fprintf(stderr, "tethereal: Parameter \"%s\" doesn't follow the template \"%s\"\n", cl_param, decode_as_arg_template);
+    cmdarg_err("Parameter \"%s\" doesn't follow the template \"%s\"", cl_param, decode_as_arg_template);
     /* If the argument does not follow the template, carry on anyway to check
        if the table name is at least correct.  If remaining_param is NULL,
        we'll exit anyway further down */
@@ -638,19 +460,19 @@ add_decode_as(const gchar *cl_param)
 
 /* Look for the requested table */
   if ( !(*(table_name)) ) { /* Is the table name empty, if so, don't even search for anything, display a message */
-    fprintf(stderr, "tethereal: No layer type specified\n"); /* Note, we don't exit here, but table_matching will remain NULL, so we exit below */
+    cmdarg_err("No layer type specified"); /* Note, we don't exit here, but table_matching will remain NULL, so we exit below */
   }
   else {
     table_matching = find_dissector_table(table_name);
     if (!table_matching) {
-      fprintf(stderr, "tethereal: Unknown layer type -- %s\n", table_name); /* Note, we don't exit here, but table_matching will remain NULL, so we exit below */
+      cmdarg_err("Unknown layer type -- %s", table_name); /* Note, we don't exit here, but table_matching will remain NULL, so we exit below */
     }
   }
 
   if (!table_matching) {
     /* Display a list of supported layer types to help the user, if the 
        specified layer type was not found */
-    fprintf(stderr, "tethereal: Valid layer types are:\n");
+    cmdarg_err("Valid layer types are:");
     fprint_all_layer_types(stderr);
   }
   if (remaining_param == NULL || !table_matching) {
@@ -661,7 +483,7 @@ add_decode_as(const gchar *cl_param)
   }
   
   if (*(remaining_param + 1) != '=') { /* Check for "==" and not only '=' */
-    fprintf(stderr, "tethereal: WARNING: -d requires \"==\" instead of \"=\". Option will be treated as \"%s==%s\"\n", table_name, remaining_param + 1);
+    cmdarg_err("WARNING: -d requires \"==\" instead of \"=\". Option will be treated as \"%s==%s\"", table_name, remaining_param + 1);
   }
   else {
     remaining_param++; /* Move to the second '=' */
@@ -675,7 +497,7 @@ add_decode_as(const gchar *cl_param)
 
   remaining_param = strchr(selector_str, ',');
   if (remaining_param == NULL) {
-    fprintf(stderr, "tethereal: Parameter \"%s\" doesn't follow the template \"%s\"\n", cl_param, decode_as_arg_template);
+    cmdarg_err("Parameter \"%s\" doesn't follow the template \"%s\"", cl_param, decode_as_arg_template);
     /* If the argument does not follow the template, carry on anyway to check
        if the selector value is at least correct.  If remaining_param is NULL,
        we'll exit anyway further down */
@@ -696,7 +518,7 @@ add_decode_as(const gchar *cl_param)
        There's no need to remove leading and trailing spaces from the
        selector number string, because sscanf will do that for us. */
     if ( sscanf(selector_str, "%u", &selector) != 1 ) {
-      fprintf(stderr, "tethereal: Invalid selector number \"%s\"\n", selector_str);
+      cmdarg_err("Invalid selector number \"%s\"", selector_str);
       g_free(decoded_param);
       return FALSE;
     }
@@ -715,7 +537,7 @@ add_decode_as(const gchar *cl_param)
 
   if (remaining_param == NULL) {
     /* Exit if no ',' separator was found (see above) */
-    fprintf(stderr, "tethereal: Valid protocols for layer type \"%s\" are:\n", table_name);
+    cmdarg_err("Valid protocols for layer type \"%s\" are:", table_name);
     fprint_all_protocols_for_layer_types(stderr, table_name);
     g_free(decoded_param); 
     return FALSE;
@@ -737,7 +559,7 @@ add_decode_as(const gchar *cl_param)
   
   /* We now have a pointer to the handle for the requested table inside the variable table_matching */
   if ( ! (*dissector_str) ) { /* Is the dissector name empty, if so, don't even search for a matching dissector and display all dissectors found for the selected table */
-    fprintf(stderr, "tethereal: No protocol name specified\n"); /* Note, we don't exit here, but dissector_matching will remain NULL, so we exit below */
+    cmdarg_err("No protocol name specified"); /* Note, we don't exit here, but dissector_matching will remain NULL, so we exit below */
   }
   else {
     user_protocol_name.nb_match = 0;
@@ -749,7 +571,7 @@ add_decode_as(const gchar *cl_param)
     if (user_protocol_name.nb_match != 0) {
       dissector_matching = user_protocol_name.matched_handle;
       if (user_protocol_name.nb_match > 1) {
-        fprintf(stderr, "tethereal: WARNING: Protocol \"%s\" matched %u dissectors, first one will be used\n", dissector_str, user_protocol_name.nb_match);
+        cmdarg_err("WARNING: Protocol \"%s\" matched %u dissectors, first one will be used", dissector_str, user_protocol_name.nb_match);
       }
     }
     else {
@@ -760,16 +582,16 @@ add_decode_as(const gchar *cl_param)
          so we exit below */
       if (proto_get_id_by_filter_name(dissector_str) == -1) {
         /* No such protocol */
-        fprintf(stderr, "tethereal: Unknown protocol -- \"%s\"\n", dissector_str);
+        cmdarg_err("Unknown protocol -- \"%s\"", dissector_str);
       } else {
-        fprintf(stderr, "tethereal: Protocol \"%s\" isn't valid for layer type \"%s\"\n",
+        cmdarg_err("Protocol \"%s\" isn't valid for layer type \"%s\"",
                dissector_str, table_name);
       }
     }
   }
 
   if (!dissector_matching) {
-    fprintf(stderr, "tethereal: Valid protocols for layer type \"%s\" are:\n", table_name);
+    cmdarg_err("Valid protocols for layer type \"%s\" are:", table_name);
     fprint_all_protocols_for_layer_types(stderr, table_name);
     g_free(decoded_param); 
     return FALSE;
@@ -813,6 +635,28 @@ add_decode_as(const gchar *cl_param)
   return TRUE;
 }
 
+static void
+log_func_ignore (const gchar *log_domain _U_, GLogLevelFlags log_level _U_,
+    const gchar *message _U_, gpointer user_data _U_)
+{
+}
+
+static char *
+output_file_description(const char *fname)
+{
+  char *save_file_string;
+
+  /* Get a string that describes what we're writing to */
+  if (strcmp(fname, "-") == 0) {
+    /* We're writing to the standard output */
+    save_file_string = g_strdup("standard output");
+  } else {
+    /* We're writing to a file with the name in save_file */
+    save_file_string = g_strdup_printf("file \"%s\"", fname);
+  }
+  return save_file_string;
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -833,36 +677,70 @@ main(int argc, char *argv[])
   int                  err;
 #ifdef HAVE_LIBPCAP
   gboolean             capture_filter_specified = FALSE;
-  GList               *if_list, *if_entry;
-  if_info_t           *if_info;
-  long                 adapter_index;
-  char                *p;
-  gchar                err_str[PCAP_ERRBUF_SIZE];
-  gchar               *cant_get_if_list_errstr;
+  gboolean             list_link_layer_types = FALSE;
+  gboolean             start_capture = FALSE;
 #else
   gboolean             capture_option_specified = FALSE;
 #endif
-  gchar               *save_file = NULL;
+  gboolean             quiet = FALSE;
   int                  out_file_type = WTAP_FILE_PCAP;
   gchar               *cf_name = NULL, *rfilter = NULL;
-#ifdef HAVE_LIBPCAP
-  gchar               *if_text;
-  GList               *lt_list, *lt_entry;
-  data_link_info_t    *data_link_info;
-#endif
 #ifdef HAVE_PCAP_OPEN_DEAD
   struct bpf_program   fcode;
 #endif
   dfilter_t           *rfcode = NULL;
   e_prefs             *prefs;
   char                 badopt;
-  ethereal_tap_list *tli;
+  GLogLevelFlags       log_flags;
+  int                  status;
 
+#define OPTSTRING_INIT "a:b:c:d:Df:F:hi:lLnN:o:pqr:R:s:St:T:vVw:xX:y:z:"
+#ifdef HAVE_LIBPCAP
+#ifdef _WIN32
+#define OPTSTRING_WIN32 "B:"
+#else
+#define OPTSTRING_WIN32 ""
+#endif  /* _WIN32 */
+#else
+#define OPTSTRING_WIN32 ""
+#endif  /* HAVE_LIBPCAP */
 
-  /* XXX - better use capture_opts_init instead */
-  capture_opts.cfilter = g_strdup("");
+  static const char    optstring[] = OPTSTRING_INIT OPTSTRING_WIN32;
 
-  set_timestamp_setting(TS_RELATIVE);
+  /*
+   * Get credential information for later use.
+   */
+  get_credential_info();
+
+  /* nothing more than the standard GLib handler, but without a warning */
+  log_flags = 
+                   G_LOG_LEVEL_ERROR|
+                   G_LOG_LEVEL_CRITICAL|
+                   G_LOG_LEVEL_WARNING|
+                   G_LOG_LEVEL_MESSAGE|
+                   G_LOG_LEVEL_INFO|
+                   G_LOG_LEVEL_DEBUG|
+                   G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION;
+
+  g_log_set_handler(NULL,
+                   log_flags,
+                   log_func_ignore, NULL /* user_data */);
+  g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
+                   log_flags,
+                   log_func_ignore, NULL /* user_data */);
+
+  /* initialize memory allocation subsystem */
+  ep_init_chunk();
+  se_init_chunk();
+  
+  initialize_funnel_ops();
+  
+#ifdef HAVE_LIBPCAP
+  capture_opts_init(&capture_opts, NULL /* cfile */);
+#endif
+
+  timestamp_set_type(TS_RELATIVE);
+  timestamp_set_precision(TS_PREC_AUTO);
 
   /* Register all dissectors; we must do this before checking for the
      "-G" flag, as the "-G" flag dumps information registered by the
@@ -873,6 +751,13 @@ main(int argc, char *argv[])
 
   /* 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 */
+#ifdef HAVE_PLUGINS
+  register_all_plugin_tap_listeners();
+#endif
   register_all_tap_listeners();
 
   /* Now register the preferences for any non-dissector modules.
@@ -884,9 +769,38 @@ main(int argc, char *argv[])
      for backwards compatibility we dump out a glossary of display
      filter symbols.
 
-     We do this here to mirror what happens in the GTK+ version, although
-     it's not necessary here. */
-  handle_dashG_option(argc, argv, "tethereal");
+     XXX - we do this here, for now, to support "-G" with no arguments.
+     If none of our build or other processes uses "-G" with no arguments,
+     we can just process it with the other arguments. */
+  if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
+    if (argc == 2)
+      proto_registrar_dump_fields(1);
+    else {
+      if (strcmp(argv[2], "fields") == 0)
+        proto_registrar_dump_fields(1);
+      else if (strcmp(argv[2], "fields2") == 0)
+        proto_registrar_dump_fields(2);
+      else if (strcmp(argv[2], "fields3") == 0)
+        proto_registrar_dump_fields(3);
+      else if (strcmp(argv[2], "protocols") == 0)
+        proto_registrar_dump_protocols();
+      else if (strcmp(argv[2], "values") == 0)
+        proto_registrar_dump_values();
+      else if (strcmp(argv[2], "decodes") == 0)
+        dissector_dump_decodes();
+      else if (strcmp(argv[2], "defaultprefs") == 0)
+        write_prefs(NULL);
+      else if (strcmp(argv[2], "currentprefs") == 0) {
+        read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
+            &pf_open_errno, &pf_read_errno, &pf_path);
+        write_prefs(NULL);
+      } else {
+        cmdarg_err("Invalid \"%s\" option for -G flag", argv[2]);
+        exit(1);
+      }
+    }
+    exit(0);
+  }
 
   /* Set the C-language locale to the native environment. */
   setlocale(LC_ALL, "");
@@ -895,21 +809,21 @@ main(int argc, char *argv[])
                      &pf_open_errno, &pf_read_errno, &pf_path);
   if (gpf_path != NULL) {
     if (gpf_open_errno != 0) {
-      fprintf(stderr, "Can't open global preferences file \"%s\": %s.\n",
+      cmdarg_err("Can't open global preferences file \"%s\": %s.",
               pf_path, strerror(gpf_open_errno));
     }
     if (gpf_read_errno != 0) {
-      fprintf(stderr, "I/O error reading global preferences file \"%s\": %s.\n",
+      cmdarg_err("I/O error reading global preferences file \"%s\": %s.",
               pf_path, strerror(gpf_read_errno));
     }
   }
   if (pf_path != NULL) {
     if (pf_open_errno != 0) {
-      fprintf(stderr, "Can't open your preferences file \"%s\": %s.\n", pf_path,
+      cmdarg_err("Can't open your preferences file \"%s\": %s.", pf_path,
               strerror(pf_open_errno));
     }
     if (pf_read_errno != 0) {
-      fprintf(stderr, "I/O error reading your preferences file \"%s\": %s.\n",
+      cmdarg_err("I/O error reading your preferences file \"%s\": %s.",
               pf_path, strerror(pf_read_errno));
     }
     g_free(pf_path);
@@ -921,29 +835,27 @@ main(int argc, char *argv[])
 
   /* Read the disabled protocols file. */
   read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno,
-                           &dp_path, &dp_open_errno, &dp_read_errno);
+                            &dp_path, &dp_open_errno, &dp_read_errno);
   if (gdp_path != NULL) {
     if (gdp_open_errno != 0) {
-      fprintf(stderr,
-        "Could not open global disabled protocols file\n\"%s\": %s.\n",
-       gdp_path, strerror(gdp_open_errno));
+      cmdarg_err("Could not open global disabled protocols file\n\"%s\": %s.",
+                 gdp_path, strerror(gdp_open_errno));
     }
     if (gdp_read_errno != 0) {
-      fprintf(stderr,
-        "I/O error reading global disabled protocols file\n\"%s\": %s.\n",
-       gdp_path, strerror(gdp_read_errno));
+      cmdarg_err("I/O error reading global disabled protocols file\n\"%s\": %s.",
+                 gdp_path, strerror(gdp_read_errno));
     }
     g_free(gdp_path);
   }
   if (dp_path != NULL) {
     if (dp_open_errno != 0) {
-      fprintf(stderr,
-        "Could not open your disabled protocols file\n\"%s\": %s.\n", dp_path,
+      cmdarg_err(
+        "Could not open your disabled protocols file\n\"%s\": %s.", dp_path,
         strerror(dp_open_errno));
     }
     if (dp_read_errno != 0) {
-      fprintf(stderr,
-        "I/O error reading your disabled protocols file\n\"%s\": %s.\n", dp_path,
+      cmdarg_err(
+        "I/O error reading your disabled protocols file\n\"%s\": %s.", dp_path,
         strerror(dp_read_errno));
     }
     g_free(dp_path);
@@ -968,35 +880,25 @@ main(int argc, char *argv[])
   print_format = PR_FMT_TEXT;
 
   /* Now get our args */
-  while ((opt = getopt(argc, argv, "a:b:c:d:Df:F:hi:lLnN:o:pqr:R:s:St:T:vw:Vxy:z:")) != -1) {
+  while ((opt = getopt(argc, argv, optstring)) != -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 'i':        /* Use interface xxx */
+      case 'p':        /* Don't capture in promiscuous mode */
+      case 's':        /* Set the snapshot (capture) length */
+      case 'w':        /* Write to capture file xxx */
+      case 'y':        /* Set the pcap data link type */
+#ifdef _WIN32
+      case 'B':        /* Buffer size */
+#endif /* _WIN32 */
 #ifdef HAVE_LIBPCAP
-        capture_opts.autostop_count =
-            get_positive_int(optarg, "packet count");
+        status = capture_opts_add_opt(&capture_opts, opt, optarg, &start_capture);
+        if(status != 0) {
+            exit(status);
+        }
 #else
         capture_option_specified = TRUE;
         arg_error = TRUE;
@@ -1005,138 +907,43 @@ main(int argc, char *argv[])
       case 'd':        /* Decode as rule */
         if (!add_decode_as(optarg))
           exit(1);
-       break;
-      case 'D':        /* Print a list of capture devices */
-#ifdef HAVE_LIBPCAP
-        if_list = get_interface_list(&err, err_str);
-        if (if_list == NULL) {
-            switch (err) {
-
-            case CANT_GET_INTERFACE_LIST:
-                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:
-                fprintf(stderr, "tethereal: There are no interfaces on which a capture can be done\n");
-                break;
-            }
-            exit(2);
-        }
-        i = 1;  /* Interface id number */
-        for (if_entry = g_list_first(if_list); if_entry != NULL;
-               if_entry = g_list_next(if_entry)) {
-         if_info = if_entry->data;
-          printf("%d. %s", i++, if_info->name);
-          if (if_info->description != NULL)
-            printf(" (%s)", if_info->description);
-          printf("\n");
-        }
-        free_interface_list(if_list);
-        exit(0);
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
         break;
-      case 'f':
+      case 'D':        /* Print a list of capture devices and exit */
 #ifdef HAVE_LIBPCAP
-        capture_filter_specified = TRUE;
-       if (capture_opts.cfilter)
-               g_free(capture_opts.cfilter);
-       capture_opts.cfilter = g_strdup(optarg);
+        status = capture_opts_list_interfaces();
+        exit(status);
 #else
         capture_option_specified = TRUE;
         arg_error = TRUE;
 #endif
-       break;
+        break;
       case 'F':
         out_file_type = wtap_short_string_to_file_type(optarg);
         if (out_file_type < 0) {
-          fprintf(stderr, "tethereal: \"%s\" isn't a valid capture file type\n",
-                       optarg);
+          cmdarg_err("\"%s\" isn't a valid capture file type", optarg);
+          list_capture_types();
           exit(1);
         }
         break;
       case 'h':        /* Print help and exit */
-       print_usage(TRUE);
-       exit(0);
-        break;
-      case 'i':        /* Use interface xxx */
-#ifdef HAVE_LIBPCAP
-        /*
-         * If the argument is a number, treat it as an index into the list
-         * of adapters, as printed by "tethereal -D".
-         *
-         * This should be OK on UNIX systems, as interfaces shouldn't have
-         * names that begin with digits.  It can be useful on Windows, where
-         * more than one interface can have the same name.
-         */
-        adapter_index = strtol(optarg, &p, 10);
-        if (p != NULL && *p == '\0') {
-          if (adapter_index < 0) {
-            fprintf(stderr,
-                "tethereal: The specified adapter index is a negative number\n");
-           exit(1);
-          }
-          if (adapter_index > INT_MAX) {
-            fprintf(stderr,
-                "tethereal: The specified adapter index is too large (greater than %d)\n",
-                INT_MAX);
-            exit(1);
-          }
-          if (adapter_index == 0) {
-            fprintf(stderr, "tethereal: there is no interface with that adapter index\n");
-            exit(1);
-          }
-          if_list = get_interface_list(&err, err_str);
-          if (if_list == NULL) {
-            switch (err) {
-
-            case CANT_GET_INTERFACE_LIST:
-                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:
-                fprintf(stderr, "tethereal: There are no interfaces on which a capture can be done\n");
-                break;
-            }
-            exit(2);
-          }
-          if_info = g_list_nth_data(if_list, adapter_index - 1);
-          if (if_info == NULL) {
-            fprintf(stderr, "tethereal: there is no interface with that adapter index\n");
-            exit(1);
-          }
-          capture_opts.iface = g_strdup(if_info->name);
-          free_interface_list(if_list);
-        } else
-          capture_opts.iface = g_strdup(optarg);
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
+        print_usage(TRUE);
+        exit(0);
         break;
       case 'l':        /* "Line-buffer" standard output */
-       /* This isn't line-buffering, strictly speaking, it's just
-          flushing the standard output after the information for
-          each packet is printed; however, that should be good
-          enough for all the purposes to which "-l" is put (and
-          is probably actually better for "-V", as it does fewer
-          writes).
-
-          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;
+        /* This isn't line-buffering, strictly speaking, it's just
+           flushing the standard output after the information for
+           each packet is printed; however, that should be good
+           enough for all the purposes to which "-l" is put (and
+           is probably actually better for "-V", as it does fewer
+           writes).
+
+           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 */
 #ifdef HAVE_LIBPCAP
         list_link_layer_types = TRUE;
@@ -1154,147 +961,118 @@ main(int argc, char *argv[])
           g_resolv_flags = RESOLV_NONE;
         badopt = string_to_name_resolve(optarg, &g_resolv_flags);
         if (badopt != '\0') {
-          fprintf(stderr, "tethereal: -N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'\n",
-                       badopt);
+          cmdarg_err("-N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'",
+                     badopt);
           exit(1);
         }
         break;
       case 'o':        /* Override preference from command line */
         switch (prefs_set_pref(optarg)) {
 
-       case PREFS_SET_SYNTAX_ERR:
-          fprintf(stderr, "tethereal: Invalid -o flag \"%s\"\n", optarg);
+        case PREFS_SET_SYNTAX_ERR:
+          cmdarg_err("Invalid -o flag \"%s\"", optarg);
           exit(1);
           break;
 
         case PREFS_SET_NO_SUCH_PREF:
         case PREFS_SET_OBSOLETE:
-          fprintf(stderr, "tethereal: -o flag \"%s\" specifies unknown preference\n",
-                       optarg);
+          cmdarg_err("-o flag \"%s\" specifies unknown preference", optarg);
           exit(1);
           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;
       case 'r':        /* Read capture file xxx */
         cf_name = g_strdup(optarg);
-        quiet = TRUE;  /* We're not capturing, so don't print packet counts */
         break;
       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 */
         print_packet_info = TRUE;
         break;
       case 't':        /* Time stamp type */
         if (strcmp(optarg, "r") == 0)
-          set_timestamp_setting(TS_RELATIVE);
+          timestamp_set_type(TS_RELATIVE);
         else if (strcmp(optarg, "a") == 0)
-          set_timestamp_setting(TS_ABSOLUTE);
+          timestamp_set_type(TS_ABSOLUTE);
         else if (strcmp(optarg, "ad") == 0)
-          set_timestamp_setting(TS_ABSOLUTE_WITH_DATE);
+          timestamp_set_type(TS_ABSOLUTE_WITH_DATE);
         else if (strcmp(optarg, "d") == 0)
-          set_timestamp_setting(TS_DELTA);
+          timestamp_set_type(TS_DELTA);
         else {
-          fprintf(stderr, "tethereal: Invalid time stamp type \"%s\"\n",
+          cmdarg_err("Invalid time stamp type \"%s\"",
             optarg);
-          fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
-          fprintf(stderr, "\"ad\" for absolute with date, or \"d\" for delta.\n");
+          cmdarg_err_cont("It must be \"r\" for relative, \"a\" for absolute,");
+          cmdarg_err_cont("\"ad\" for absolute with date, or \"d\" for delta.");
           exit(1);
         }
         break;
       case 'T':        /* printing Type */
         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;
+          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 {
+          cmdarg_err("Invalid -T parameter.");
+          cmdarg_err_cont("It must be \"ps\", \"text\", \"pdml\", or \"psml\".");
+          exit(1);
+        }
+        break;
       case 'v':        /* Show version and exit */
-        printf("t" PACKAGE " " VERSION
-#ifdef SVNVERSION
-           " (" SVNVERSION ")"
-#endif
-           "\n%s\n%s\n",
-           comp_info_str->str, runtime_info_str->str);
+        printf("Tethereal " VERSION "%s\n"
+               "\n"
+               "%s"
+               "\n"
+               "%s"
+               "\n"
+               "%s",
+               svnversion, get_copyright_info(), comp_info_str->str,
+               runtime_info_str->str);
         exit(0);
         break;
-      case 'w':        /* Write to capture file xxx */
-        save_file = g_strdup(optarg);
-       break;
       case 'V':        /* Verbose */
         verbose = TRUE;
         break;
       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\" isn't 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;
+          print_hex = TRUE;
+          break;
+      case 'X':
+          ex_opt_add(optarg);
+          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);
-          }
+        /* We won't call the init function for the stat 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 stat arguments. */
+        if (!process_stat_cmd_arg(optarg)) {
+          cmdarg_err("invalid -z argument.");
+          cmdarg_err_cont("  -z argument must be one of :");
+          list_stat_cmd_args();
           exit(1);
         }
         break;
       default:
       case '?':        /* Bad flag - print usage message */
-        arg_error = TRUE;
+        switch(optopt) {
+        case'F':
+          list_capture_types();
+          break;
+        default:
+          print_usage(TRUE);
+        }
+        exit(1);
         break;
     }
   }
@@ -1306,17 +1084,17 @@ main(int argc, char *argv[])
   if (optind < argc) {
     if (cf_name != NULL) {
       if (rfilter != NULL) {
-        fprintf(stderr,
-"tethereal: Read filters were specified both with \"-R\" and with additional command-line arguments\n");
-        exit(2);
+        cmdarg_err("Read filters were specified both with \"-R\" "
+            "and with additional command-line arguments");
+        exit(1);
       }
       rfilter = get_args_as_string(argc, argv, optind);
     } else {
 #ifdef HAVE_LIBPCAP
       if (capture_filter_specified) {
-        fprintf(stderr,
-"tethereal: Capture filters were specified both with \"-f\" and with additional command-line arguments\n");
-        exit(2);
+        cmdarg_err("Capture filters were specified both with \"-f\""
+            " and with additional command-line arguments");
+        exit(1);
       }
       capture_opts.cfilter = get_args_as_string(argc, argv, optind);
 #else
@@ -1325,56 +1103,27 @@ main(int argc, char *argv[])
     }
   }
 
-  /* See if we're writing a capture file and the file is a pipe */
-#ifdef HAVE_LIBPCAP
-  ld.output_to_pipe = FALSE;
-#endif
-  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(save_file);
-      switch (err) {
-
-      case ENOENT:     /* it doesn't exist, so we'll be creating it,
-                          and it won't be a FIFO */
-      case 0:          /* found it, but it's not a FIFO */
-        break;
-
-      case ESPIPE:     /* it is a FIFO */
-        ld.output_to_pipe = TRUE;
-        break;
-
-      default:         /* couldn't stat it */
-        fprintf(stderr,
-                "tethereal: Error testing whether capture file is a pipe: %s\n",
-                strerror(errno));
-        exit(2);
-      }
-    }
-#endif
-  } else {
-    /* We're not writing to a file, so we should print packet information
-       unless "-q" was specified. */
+  if (!capture_opts.saving_to_file) {
+    /* We're not saving the capture to a file; if "-q" wasn't specified,
+       we should print packet information */
     if (!quiet)
       print_packet_info = TRUE;
+  } else {
+    /* We're saving to a file; if we're writing to the standard output.
+       and we'll also be writing dissected packets to the standard
+       output, reject the request.  At best, we could redirect that
+       to the standard error; we *can't* write both to the standard
+       output and have either of them be useful. */
+    if (strcmp(capture_opts.save_file, "-") == 0 && print_packet_info) {
+      cmdarg_err("You can't write both raw packet data and dissected packets"
+          " to the standard output.");
+      exit(1);
+    }
   }
 
 #ifndef HAVE_LIBPCAP
   if (capture_option_specified)
-    fprintf(stderr, "This version of Tethereal was not built with support for capturing packets.\n");
+    cmdarg_err("This version of Tethereal was not built with support for capturing packets.");
 #endif
   if (arg_error) {
     print_usage(FALSE);
@@ -1387,16 +1136,16 @@ main(int argc, char *argv[])
 #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);
+      cmdarg_err("Only read filters, not capture filters, "
+          "can be specified when reading a capture file.");
+      exit(1);
     }
   }
 #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");
+      cmdarg_err("Raw packet hex data can only be printed as text or PostScript");
       exit(1);
     }
   }
@@ -1407,50 +1156,113 @@ main(int argc, char *argv[])
        did the user also specify a capture file to be read? */
     if (cf_name) {
       /* Yes - that's bogus. */
-      fprintf(stderr, "tethereal: You can't specify -L and a capture file to be read.\n");
+      cmdarg_err("You can't specify -L and a capture file to be read.");
       exit(1);
     }
     /* No - did they specify a ring buffer option? */
-    if (capture_opts.ringbuffer_on) {
-      fprintf(stderr, "tethereal: Ring buffer requested, but a capture isn't being done.\n");
+    if (capture_opts.multi_files_on) {
+      cmdarg_err("Ring buffer requested, but a capture isn't being done.");
       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 && save_file == NULL) {
-      fprintf(stderr, "tethereal: Maximum capture file size specified, but "
-        "capture isn't being saved to a file.\n");
+    if (capture_opts.has_autostop_filesize && capture_opts.save_file == NULL) {
+      cmdarg_err("Maximum capture file size specified, but "
+        "capture isn't being saved to a file.");
       exit(1);
     }
 
-    if (capture_opts.ringbuffer_on) {
-      /* Ring buffer works only under certain conditions:
-        a) ring buffer does not work if you're not saving the capture to
-           a file;
-        b) ring buffer only works if you're saving in libpcap format;
-        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 (save_file == NULL) {
-       fprintf(stderr, "tethereal: Ring buffer requested, but "
-         "capture isn't being saved to a file.\n");
-       exit(1);
+    if (cf_name) {
+      /*
+       * "-r" was specified, so we're reading a capture file.
+       * Capture options don't apply here.
+       */
+      if (capture_opts.multi_files_on) {
+        cmdarg_err("Multiple capture files requested, but "
+                   "a capture isn't being done.");
+        exit(1);
       }
-      if (out_file_type != WTAP_FILE_PCAP) {
-       fprintf(stderr, "tethereal: Ring buffer requested, but "
-         "capture isn't being saved in libpcap format.\n");
-       exit(2);
+      if (capture_opts.has_file_duration) {
+        cmdarg_err("Switching capture files after a time interval was specified, but "
+                   "a capture isn't being done.");
+        exit(1);
       }
-      if (!capture_opts.has_autostop_filesize) {
-       fprintf(stderr, "tethereal: Ring buffer requested, but "
-         "no maximum capture file size was specified.\n");
-       exit(2);
+      if (capture_opts.has_ring_num_files) {
+        cmdarg_err("A ring buffer of capture files was specified, but "
+          "a capture isn't being done.");
+        exit(1);
       }
-      if (ld.output_to_pipe) {
-       fprintf(stderr, "tethereal: Ring buffer requested, but "
-         "capture file is a pipe.\n");
-       exit(2);
+      if (capture_opts.has_autostop_files) {
+        cmdarg_err("A maximum number of capture files was specified, but "
+          "a capture isn't being done.");
+        exit(1);
+      }
+      if (capture_opts.has_autostop_packets) {
+        cmdarg_err("A maximum number of captured packets was specified, but "
+          "a capture isn't being done.");
+        exit(1);
+      }
+      if (capture_opts.has_autostop_filesize) {
+        cmdarg_err("A maximum capture file size was specified, but "
+          "a capture isn't being done.");
+        exit(1);
+      }
+      if (capture_opts.has_autostop_duration) {
+        cmdarg_err("A maximum capture time was specified, but "
+          "a capture isn't being done.");
+        exit(1);
+      }
+    } else {
+      /*
+       * "-r" wasn't specified, so we're doing a live capture.
+       */
+      if (capture_opts.saving_to_file) {
+        /* They specified a "-w" flag, so we'll be saving to a capture file. */
+  
+        /* When capturing, we only support writing libpcap format. */
+        if (out_file_type != WTAP_FILE_PCAP) {
+          cmdarg_err("Live captures can only be saved in libpcap format.");
+          exit(1);
+        }
+        if (capture_opts.multi_files_on) {
+          /* Multiple-file mode works only under certain conditions:
+             a) it doesn't work if you're writing to the standard output;
+             b) it doesn't work if you're writing to a pipe;
+             c) it makes no sense if the maximum file size is set to "infinite"
+                (XXX - shouldn't that be "if there is no stop criterion",
+                as you might want to switch files based on a packet count
+                or a time). */
+          if (strcmp(capture_opts.save_file, "-") == 0) {
+            cmdarg_err("Multiple capture files requested, but "
+              "the capture is being written to the standard output.");
+            exit(1);
+          }
+          if (capture_opts.output_to_pipe) {
+            cmdarg_err("Multiple capture files requested, but "
+              "the capture file is a pipe.");
+            exit(1);
+          }
+          if (!capture_opts.has_autostop_filesize) {
+            cmdarg_err("Multiple capture files requested, but "
+              "no maximum capture file size was specified.");
+            exit(1);
+          }
+        }
+      } else {
+        /* They didn't specify a "-w" flag, so we won't be saving to a
+           capture file.  Check for options that only make sense if
+           we're saving to a file. */
+        if (capture_opts.has_autostop_filesize) {
+          cmdarg_err("Maximum capture file size specified, but "
+           "capture isn't being saved to a file.");
+          exit(1);
+        }
+        if (capture_opts.multi_files_on) {
+          cmdarg_err("Multiple capture files requested, but "
+            "the capture isn't being saved to a file.");
+          exit(1);
+        }
       }
     }
   }
@@ -1459,13 +1271,18 @@ main(int argc, char *argv[])
 #ifdef _WIN32
   /* Start windows sockets */
   WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
-#endif /* _WIN32 */
+#endif /* _WIN32 */
 
   /* Notify all registered modules that have had any of their preferences
      changed either from one of the preferences file or from the command
      line that their preferences have changed. */
   prefs_apply_all();
 
+  /* At this point MATE will have registered its field array so we can
+     have a tap filter with one of MATE's late-registered fields as part
+     of the filter.  We can now process all the "-z" arguments. */
+  start_requested_stats();
+  
   /* disabled protocols as per configuration file */
   if (gdp_path == NULL && dp_path == NULL) {
     set_disabled_protos_list();
@@ -1503,23 +1320,13 @@ main(int argc, char *argv[])
   }
 
 #ifdef HAVE_LIBPCAP
-  if (capture_opts.snaplen < 1)
-    capture_opts.snaplen = WTAP_MAX_PACKET_SIZE;
-  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;
-#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;
-#endif
+  capture_opts_trim_snaplen(&capture_opts, MIN_PACKET_SIZE);
+  capture_opts_trim_ring_num_files(&capture_opts);
 #endif
 
   if (rfilter != NULL) {
     if (!dfilter_compile(rfilter, &rfcode)) {
-      fprintf(stderr, "tethereal: %s\n", dfilter_error_msg);
+      cmdarg_err("%s", dfilter_error_msg);
       epan_cleanup();
 #ifdef HAVE_PCAP_OPEN_DEAD
       {
@@ -1528,9 +1335,10 @@ main(int argc, char *argv[])
         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");
+            cmdarg_err_cont(
+              "  Note: That display filter code looks like a valid capture filter;");
+            cmdarg_err_cont(
+              "        maybe you mixed them up?");
           }
           pcap_close(pc);
         }
@@ -1563,11 +1371,11 @@ main(int argc, char *argv[])
 
   /* We have to dissect each packet if:
 
-       we're printing information about each packet;
+        we're printing information about each packet;
 
-       we're using a read filter on the packets;
+        we're using a read filter on the packets;
 
-       we're using any taps. */
+        we're using any taps. */
   do_dissection = print_packet_info || rfcode || have_tap_listeners();
 
   if (cf_name) {
@@ -1575,21 +1383,45 @@ main(int argc, char *argv[])
      * We're reading a capture file.
      */
 
-#ifndef _WIN32
     /*
-     * Immediately relinquish any set-UID or set-GID privileges we have;
-     * we must not be allowed to read any capture files the user running
-     * Tethereal can't open.
+     * Immediately relinquish any special privileges we have; we must not
+     * be allowed to read any capture files the user running Tethereal
+     * can't open.
      */
-    setuid(getuid());
-    setgid(getgid());
-#endif
+    relinquish_special_privs_perm();
 
     if (cf_open(&cfile, cf_name, FALSE, &err) != CF_OK) {
       epan_cleanup();
       exit(2);
     }
-    err = load_cap_file(&cfile, save_file, out_file_type);
+
+    /* Set timestamp precision; there should arguably be a command-line
+       option to let the user set this. */
+    switch(wtap_file_tsprecision(cfile.wth)) {
+    case(WTAP_FILE_TSPREC_SEC):
+      timestamp_set_precision(TS_PREC_AUTO_SEC);
+      break;
+    case(WTAP_FILE_TSPREC_DSEC):
+      timestamp_set_precision(TS_PREC_AUTO_DSEC);
+      break;
+    case(WTAP_FILE_TSPREC_CSEC):
+      timestamp_set_precision(TS_PREC_AUTO_CSEC);
+      break;
+    case(WTAP_FILE_TSPREC_MSEC):
+      timestamp_set_precision(TS_PREC_AUTO_MSEC);
+      break;
+    case(WTAP_FILE_TSPREC_USEC):
+      timestamp_set_precision(TS_PREC_AUTO_USEC);
+      break;
+    case(WTAP_FILE_TSPREC_NSEC):
+      timestamp_set_precision(TS_PREC_AUTO_NSEC);
+      break;
+    default:
+      g_assert_not_reached();
+    }
+
+    /* Process the packets in the file */
+    err = load_cap_file(&cfile, capture_opts.save_file, out_file_type);
     if (err != 0) {
       epan_cleanup();
       exit(2);
@@ -1603,88 +1435,59 @@ main(int argc, char *argv[])
 
 #ifdef _WIN32
     if (!has_wpcap) {
-       fprintf(stderr, "tethereal: Could not load wpcap.dll.\n");
-       exit(2);
+      char *detailed_err;
+
+      cmdarg_err("WinPcap couldn't be found.");
+      detailed_err = cant_load_winpcap_err("Tethereal");
+      cmdarg_err_cont("%s", detailed_err);
+      g_free(detailed_err);
+      exit(2);
     }
 #endif
 
-    /* Yes; did the user specify an interface to use? */
-    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) {
-               capture_opts.iface = g_strdup(prefs->capture_device);
-           } else {
-               capture_opts.iface = g_strdup(if_text + 1); /* Skip over space */
-           }
-        } else {
-            /* No - pick the first one from the list of interfaces. */
-            if_list = get_interface_list(&err, err_str);
-            if (if_list == NULL) {
-                switch (err) {
-
-                case CANT_GET_INTERFACE_LIST:
-                    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:
-                    fprintf(stderr, "tethereal: There are no interfaces on which a capture can be done\n");
-                    break;
-                }
-                exit(2);
-            }
-           if_info = if_list->data;    /* first interface */
-           capture_opts.iface = g_strdup(if_info->name);
-            free_interface_list(if_list);
-        }
+    /* trim the interface name and exit if that failed */
+    if (!capture_opts_trim_iface(&capture_opts, 
+        (prefs->capture_device) ? get_if_name(prefs->capture_device) : NULL)) {
+        exit(2);
     }
 
+    /* if requested, list the link layer types and exit */
     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(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"
-           "Please check to make sure you have sufficient permissions, and that\n"
-           "you have the proper interface or pipe specified.\n", err_str);
-       } else
-         fprintf(stderr, "tethereal: The capture device has no data link types.\n");
-       exit(2);
-      }
-      fprintf(stderr, "Data link types (use option -y to set):\n");
-      for (lt_entry = lt_list; lt_entry != NULL;
-          lt_entry = g_list_next(lt_entry)) {
-       data_link_info = lt_entry->data;
-       fprintf(stderr, "  %s", data_link_info->name);
-       if (data_link_info->description != NULL)
-         fprintf(stderr, " (%s)", data_link_info->description);
-       else
-         fprintf(stderr, " (not supported)");
-       putchar('\n');
-      }
-      free_pcap_linktype_list(lt_list);
-      exit(0);
+        status = capture_opts_list_link_layer_types(&capture_opts);
+        exit(status);
+    }
+
+    if (!print_packet_info && !quiet) {
+      /*
+       * We're not printing information for each packet, and the user
+       * didn't ask us not to print a count of packets as they arrive,
+       * so print that count so the user knows that packets are arriving.
+       *
+       * XXX - what if the user wants to do a live capture, doesn't want
+       * to save it to a file, doesn't want information printed for each
+       * packet, does want some "-z" statistic, and wants packet counts
+       * so they know whether they're seeing any packets?
+       */
+      print_packet_counts = TRUE;
     }
 
-    capture(save_file, out_file_type);
+    /* For now, assume libpcap gives microsecond precision. */
+    timestamp_set_precision(TS_PREC_AUTO_USEC);
+
+    capture();
 
-    if (capture_opts.ringbuffer_on) {
+    if (capture_opts.multi_files_on) {
       ringbuf_free();
     }
 #else
     /* No - complain. */
-    fprintf(stderr, "This version of Tethereal was not built with support for capturing packets.\n");
+    cmdarg_err("This version of Tethereal was not built with support for capturing packets.");
     exit(2);
 #endif
   }
 
   draw_tap_listeners(TRUE);
+  funnel_dump_all_text_windows();
   epan_cleanup();
 
   return 0;
@@ -1694,228 +1497,95 @@ 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 process_packet */
+static condition  *volatile cnd_file_duration = NULL; /* this must be visible in process_packet */
 
 static int
-capture(char *save_file, int out_file_type)
+capture(void)
 {
-  int         pcap_encap;
-  int         file_snaplen;
-  gchar       open_err_str[PCAP_ERRBUF_SIZE];
-  gchar       lookup_net_err_str[PCAP_ERRBUF_SIZE];
-  bpf_u_int32 netnum, netmask;
-  struct bpf_program fcode;
-  const char *set_linktype_err_str;
   int         err = 0;
   int         volatile volatile_err = 0;
   int         volatile inpkts = 0;
   int         pcap_cnt;
-  char        errmsg[1024+1];
-  condition  *volatile cnd_stop_capturesize = NULL;
-  condition  *volatile cnd_stop_timeout = NULL;
+  condition  *volatile cnd_autostop_size = NULL;
+  condition  *volatile cnd_autostop_duration = NULL;
   char       *descr;
 #ifndef _WIN32
   void        (*oldhandler)(int);
-  static const char ppamsg[] = "can't find PPA for ";
-  char       *libpcap_warn;
-  volatile int pipe_fd = -1;
-  struct pcap_hdr hdr;
-  struct pcaprec_modified_hdr rechdr;
   guchar pcap_data[WTAP_MAX_PACKET_SIZE];
 #endif
   struct pcap_stat stats;
-  gboolean    write_err;
-  gboolean    dump_ok;
-  dfilter_t   *rfcode = NULL;
+  gboolean    write_ok;
+  gboolean    close_ok;
+  gboolean    cfilter_error = FALSE;
+  char        errmsg[1024+1];
+  char        secondary_errmsg[4096+1];
   int         save_file_fd;
 
   /* Initialize all data structures used for dissection. */
   init_dissection();
 
-  ld.linktype       = WTAP_ENCAP_UNKNOWN;
+  ld.wtap_linktype  = WTAP_ENCAP_UNKNOWN;
   ld.pdh            = NULL;
+  ld.packet_cb      = capture_pcap_cb;
 
-  /* Open the network interface to capture from it.
-     Some versions of libpcap may put warnings into the error buffer
-     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(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, capture_opts.iface,
-       capture_opts.linktype);
-      if (set_linktype_err_str != NULL) {
-       snprintf(errmsg, sizeof errmsg, "Unable to set data link type (%s).",
-         set_linktype_err_str);
-       goto error;
-      }
-    }
-  } else {
-    /* We couldn't open "cfile.iface" as a network device. */
-#ifdef _WIN32
-    /* On Windows, we don't support capturing on pipes, so we give up. */
-
-    /* On Win32 OSes, the capture devices are probably available to all
-       users; don't warn about permissions problems.
-
-       Do, however, warn that WAN devices aren't supported. */
-    snprintf(errmsg, sizeof errmsg,
-       "The capture session could not be initiated (%s).\n"
-       "Please check that you have the proper interface specified.\n"
-       "\n"
-       "Note that the WinPcap 2.x version of the driver Ethereal uses for packet\n"
-       "capture on Windows doesn't support capturing on PPP/WAN interfaces in\n"
-       "Windows NT/2000/XP/2003 Server, and that the WinPcap 3.0 and later versions\n"
-       "don't support capturing on PPP/WAN interfaces at all.\n",
-       open_err_str);
+
+  /* open the "input file" from network interface or capture pipe */
+  if (!capture_loop_open_input(&capture_opts, &ld, errmsg, sizeof(errmsg),
+                               secondary_errmsg, sizeof(secondary_errmsg))) {
     goto error;
-#else
-    /* try to open cfile.iface as a pipe */
-    pipe_fd = pipe_open_live(capture_opts.iface, &hdr, &ld, errmsg,
-                             sizeof errmsg);
-
-    if (pipe_fd == -1) {
-
-      if (ld.pipe_err == PIPNEXIST) {
-       /* Pipe doesn't exist, so output message for interface */
-
-       /* If we got a "can't find PPA for XXX" message, warn the user (who
-           is running Tethereal on HP-UX) that they don't have a version
-          of libpcap that properly handles HP-UX (libpcap 0.6.x and later
-          versions, which properly handle HP-UX, say "can't find /dev/dlpi
-          PPA for XXX" rather than "can't find PPA for XXX"). */
-       if (strncmp(open_err_str, ppamsg, sizeof ppamsg - 1) == 0)
-         libpcap_warn =
-           "\n\n"
-           "You are running Tethereal with a version of the libpcap library\n"
-           "that doesn't handle HP-UX network devices well; this means that\n"
-           "Tethereal may not be able to capture packets.\n"
-           "\n"
-           "To fix this, you should install libpcap 0.6.2, or a later version\n"
-           "of libpcap, rather than libpcap 0.4 or 0.5.x.  It is available in\n"
-           "packaged binary form from the Software Porting And Archive Centre\n"
-           "for HP-UX; the Centre is at http://hpux.connect.org.uk/ - the page\n"
-           "at the URL lists a number of mirror sites.";
-       else
-         libpcap_warn = "";
-       snprintf(errmsg, sizeof errmsg,
-         "The capture session could not be initiated (%s).\n"
-         "Please check to make sure you have sufficient permissions, and that\n"
-         "you have the proper interface or pipe specified.%s", open_err_str,
-         libpcap_warn);
-      }
-      /*
-       * Else pipe (or file) does exist and pipe_open_live() has
-       * filled in errmsg
-       */
-      goto error;
-    } else
-      /* pipe_open_live() succeeded; don't want
-         error message from pcap_open_live() */
-      open_err_str[0] = '\0';
-#endif
   }
 
-#ifndef _WIN32
   /*
-   * We've opened the capture device, so, if we're set-UID or set-GID,
-   * relinquish those privileges.
+   * We've opened the capture device, so we shouldn't need any special
+   * privileges any more; relinquish those privileges.
    *
    * XXX - if we have saved set-user-ID support, we should give up those
    * privileges immediately, and then reclaim them long enough to get
    * a list of network interfaces and to open one, and then give them
    * up again, so that stuff we do while processing the argument list,
-   * reading the user's preferences, etc. is done as the real user and
-   * group, not the effective user and group.
+   * reading the user's preferences, loading and starting plugins
+   * (especially *user* plugins), etc. is done with the user's privileges,
+   * not special privileges.
    */
-  setuid(getuid());
-  setgid(getgid());
-#endif
+  relinquish_special_privs_perm();
 
-  if (capture_opts.cfilter && !ld.from_pipe) {
-    /* A capture filter was specified; set it up. */
-    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
-       * we just warn the user, and punt and use 0.
-       */
-      fprintf(stderr,
-        "Warning:  Couldn't obtain netmask info (%s).\n", lookup_net_err_str);
-      netmask = 0;
-    }
-    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"
-         "  Are you sure you didn't mix them up?",
-         pcap_geterr(ld.pch));
-      } else {
-        snprintf(errmsg, sizeof errmsg,
-         "Unable to parse capture filter string (%s).",
-         pcap_geterr(ld.pch));
-      }
-      goto error;
-    }
-    if (pcap_setfilter(ld.pch, &fcode) < 0) {
-      snprintf(errmsg, sizeof errmsg, "Can't install filter (%s).",
-       pcap_geterr(ld.pch));
-      goto error;
-    }
-  }
+  /* init the input filter from the network interface (capture pipe will do nothing) */
+  switch (capture_loop_init_filter(ld.pcap_h, ld.from_cap_pipe, capture_opts.iface, capture_opts.cfilter)) {
 
-  /* Set up to write to the capture file. */
-#ifndef _WIN32
-  if (ld.from_pipe) {
-    pcap_encap = hdr.network;
-    file_snaplen = hdr.snaplen;
-  } else
-#endif
-  {
-    pcap_encap = get_pcap_linktype(ld.pch, capture_opts.iface);
-    file_snaplen = pcap_snapshot(ld.pch);
+  case INITFILTER_NO_ERROR:
+    break;
+
+  case INITFILTER_BAD_FILTER:
+    cfilter_error = TRUE;
+    g_snprintf(errmsg, sizeof(errmsg), "%s", pcap_geterr(ld.pcap_h));
+    *secondary_errmsg = '\0';
+    goto error;
+
+  case INITFILTER_OTHER_ERROR:
+    g_snprintf(errmsg, sizeof(errmsg), "Can't install filter (%s).",
+               pcap_geterr(ld.pcap_h));
+    g_snprintf(secondary_errmsg, sizeof(secondary_errmsg), "%s", please_report);
+    goto error;
   }
-  ld.linktype = wtap_pcap_encap_to_wtap_encap(pcap_encap);
-  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;
-    }
-    ld.save_file = save_file;
-    if (capture_opts.ringbuffer_on) {
-      save_file_fd = ringbuf_init(save_file,
-        capture_opts.ringbuffer_num_files);
-      if (save_file_fd != -1) {
-        ld.pdh = ringbuf_init_wtap_dump_fdopen(out_file_type, ld.linktype,
-          file_snaplen, &err);
-      } else {
-       err = errno;    /* "ringbuf_init()" failed */
-        ld.pdh = NULL;
-      }
-    } else {
-      ld.pdh = wtap_dump_open(save_file, out_file_type,
-                ld.linktype, file_snaplen, &err);
+
+  if (capture_opts.saving_to_file) {
+    /* open the output file (temporary/specified name/ringbuffer/named pipe/stdout) */
+    if (!capture_loop_open_output(&capture_opts, &save_file_fd, errmsg, sizeof(errmsg))) {
+      *secondary_errmsg = '\0';
+      goto error;    
     }
 
-    if (ld.pdh == NULL) {
-      snprintf(errmsg, sizeof errmsg,
-              cf_open_error_message(err, NULL, TRUE, out_file_type),
-              *save_file == '\0' ? "stdout" : save_file);
+    /* set up to write to the already-opened capture output file/files */
+    if(!capture_loop_init_output(&capture_opts, save_file_fd, &ld, errmsg, sizeof errmsg)) {
+      *secondary_errmsg = '\0';
       goto error;
     }
+
+    /* Save the capture file name. */
+    ld.save_file = capture_opts.save_file;
   }
 
-  /* Does "open_err_str" contain a non-empty string?  If so, "pcap_open_live()"
-     returned a warning; print it, but keep capturing. */
-  if (open_err_str[0] != '\0')
-    fprintf(stderr, "tethereal: WARNING: %s.\n", open_err_str);
+  ld.wtap_linktype = wtap_pcap_encap_to_wtap_encap(ld.linktype);
 
 #ifdef _WIN32
   /* Catch a CTRL+C event and, if we get it, clean up and exit. */
@@ -1946,21 +1616,21 @@ capture(char *save_file, int out_file_type)
   init_capture_stop_conditions();
   /* create stop conditions */
   if (capture_opts.has_autostop_filesize)
-    cnd_stop_capturesize = cnd_new((const char*)CND_CLASS_CAPTURESIZE,
-                                   (long)capture_opts.autostop_filesize * 1000);
+    cnd_autostop_size = cnd_new((const char*)CND_CLASS_CAPTURESIZE,
+                                   (long)capture_opts.autostop_filesize * 1024);
   if (capture_opts.has_autostop_duration)
-    cnd_stop_timeout = cnd_new((const char*)CND_CLASS_TIMEOUT,
+    cnd_autostop_duration = cnd_new((const char*)CND_CLASS_TIMEOUT,
                                (gint32)capture_opts.autostop_duration);
 
-  if (capture_opts.ringbuffer_on && capture_opts.has_ring_duration)
-    cnd_ring_timeout = cnd_new(CND_CLASS_TIMEOUT, 
-                              capture_opts.ringbuffer_duration);
+  if (capture_opts.multi_files_on && capture_opts.has_file_duration)
+    cnd_file_duration = cnd_new(CND_CLASS_TIMEOUT, capture_opts.file_duration);
 
   if (!setjmp(ld.stopenv)) {
     ld.go = TRUE;
     ld.packet_count = 0;
   } else
     ld.go = FALSE;
+
   while (ld.go) {
     /* We need to be careful with automatic variables defined in the
        outer scope which are changed inside the loop.  Most compilers
@@ -1989,7 +1659,7 @@ capture(char *save_file, int out_file_type)
     int loop_err = 0;
     int packet_count_prev = 0;
 
-    if (cnd_stop_capturesize == NULL && cnd_stop_timeout == NULL) {
+    if (cnd_autostop_size == NULL && cnd_autostop_duration == NULL) {
       /* We're not stopping at a particular capture file size, and we're
          not stopping after some particular amount of time has expired,
          so either we have no stop condition or the only stop condition
@@ -2005,15 +1675,15 @@ capture(char *save_file, 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
@@ -2021,39 +1691,37 @@ capture(char *save_file, int out_file_type)
       pcap_cnt = 1;
     }
 #ifndef _WIN32
-    if (ld.from_pipe) {
-      inpkts = pipe_dispatch(pipe_fd, &ld, &hdr, &rechdr, pcap_data,
-        errmsg, sizeof errmsg);
+    if (ld.from_cap_pipe) {
+      inpkts = cap_pipe_dispatch(&ld, pcap_data, errmsg, sizeof errmsg);
     } else
 #endif
-      inpkts = pcap_dispatch(ld.pch, pcap_cnt, capture_pcap_cb, (guchar *) &ld);
+      inpkts = pcap_dispatch(ld.pcap_h, pcap_cnt, ld.packet_cb, (u_char *) &ld);
     if (inpkts < 0) {
       /* Error from "pcap_dispatch()", or error or "no more packets" from
-         "pipe_dispatch(). */
+         "cap_pipe_dispatch(). */
       ld.go = FALSE;
-    } else if (cnd_stop_timeout != NULL && cnd_eval(cnd_stop_timeout)) {
+    } else if (cnd_autostop_duration != NULL && cnd_eval(cnd_autostop_duration)) {
       /* 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. */
         ld.go = FALSE;
-      } else if (cnd_stop_capturesize != NULL &&
-                    cnd_eval(cnd_stop_capturesize,
-                              (guint32)wtap_get_bytes_dumped(ld.pdh))) {
+      } else if (cnd_autostop_size != NULL &&
+                    cnd_eval(cnd_autostop_size, (guint32)ld.bytes_written)) {
         /* 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(&ld.pdh, &save_file, &save_file_fd, &loop_err)) {
+          if (ringbuf_switch_file(&ld.pdh, &capture_opts.save_file, &save_file_fd, &loop_err)) {
             /* File switch succeeded: reset the condition */
-            cnd_reset(cnd_stop_capturesize);
-           if (cnd_ring_timeout) {
-             cnd_reset(cnd_ring_timeout);
-           }
+            cnd_reset(cnd_autostop_size);
+            if (cnd_file_duration) {
+              cnd_reset(cnd_file_duration);
+            }
           } else {
             /* File switch failed: stop here */
             volatile_err = loop_err;
@@ -2064,12 +1732,9 @@ capture(char *save_file, int out_file_type)
           ld.go = FALSE;
         }
       }
-      if (ld.output_to_pipe) {
+      if (capture_opts.output_to_pipe) {
         if (ld.packet_count > packet_count_prev) {
-          if (fflush(wtap_dump_file(ld.pdh))) {
-            volatile_err = errno;
-            ld.go = FALSE;
-          }
+          libpcap_dump_flush(ld.pdh, NULL);
           packet_count_prev = ld.packet_count;
         }
       }
@@ -2077,16 +1742,15 @@ capture(char *save_file, int out_file_type)
   } /* while (ld.go) */
 
   /* delete stop conditions */
-  if (cnd_stop_capturesize != NULL)
-    cnd_delete(cnd_stop_capturesize);
-  if (cnd_stop_timeout != NULL)
-    cnd_delete(cnd_stop_timeout);
-  if (cnd_ring_timeout != NULL)
-    cnd_delete(cnd_ring_timeout);
-
-  if ((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 (cnd_autostop_size != NULL)
+    cnd_delete(cnd_autostop_size);
+  if (cnd_autostop_duration != NULL)
+    cnd_delete(cnd_autostop_duration);
+  if (cnd_file_duration != NULL)
+    cnd_delete(cnd_file_duration);
+
+  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");
   }
@@ -2094,56 +1758,50 @@ capture(char *save_file, int out_file_type)
   /* If we got an error while capturing, report it. */
   if (inpkts < 0) {
 #ifndef _WIN32
-    if (ld.from_pipe) {
-      if (ld.pipe_err == PIPERR) {
-        fprintf(stderr, "tethereal: Error while capturing packets: %s\n",
-         errmsg);
+    if (ld.from_cap_pipe) {
+      if (ld.cap_pipe_err == PIPERR) {
+        cmdarg_err("Error while capturing packets: %s", errmsg);
       }
     } else
 #endif
     {
-      fprintf(stderr, "tethereal: Error while capturing packets: %s\n",
-         pcap_geterr(ld.pch));
+      cmdarg_err("Error while capturing packets: %s", pcap_geterr(ld.pcap_h));
     }
   }
 
   if (volatile_err == 0)
-    write_err = FALSE;
+    write_ok = TRUE;
   else {
-    show_capture_file_io_error(save_file, volatile_err, FALSE);
-    write_err = TRUE;
+    show_capture_file_io_error(capture_opts.save_file, volatile_err, FALSE);
+    write_ok = FALSE;
   }
 
-  if (save_file != NULL) {
+  if (capture_opts.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(&save_file, &err);
-    } else {
-      dump_ok = wtap_dump_close(ld.pdh, &err);
-    }
+    close_ok = capture_loop_close_output(&capture_opts, &ld, &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(save_file, err, TRUE);
+    if (!close_ok && write_ok)
+      show_capture_file_io_error(capture_opts.save_file, err, TRUE);
   }
 
 #ifndef _WIN32
-  if (ld.from_pipe && pipe_fd >= 0)
-    close(pipe_fd);
+  if (ld.from_cap_pipe && ld.cap_pipe_fd >= 0)
+    eth_close(ld.cap_pipe_fd);
   else
 #endif
   {
     /* Get the capture statistics, and, if any packets were dropped, report
        that. */
-    if (pcap_stats(ld.pch, &stats) >= 0) {
+    if (pcap_stats(ld.pcap_h, &stats) >= 0) {
       if (stats.ps_drop != 0) {
         fprintf(stderr, "%u packets dropped\n", stats.ps_drop);
       }
     } else {
-      fprintf(stderr, "tethereal: Can't get packet-drop statistics: %s\n",
-         pcap_geterr(ld.pch));
+      cmdarg_err("Can't get packet-drop statistics: %s", pcap_geterr(ld.pcap_h));
     }
-    pcap_close(ld.pch);
+    pcap_close(ld.pcap_h);
   }
 
   /* Report the number of captured packets if not reported during capture
@@ -2153,44 +1811,67 @@ capture(char *save_file, int out_file_type)
   return TRUE;
 
 error:
-  if (capture_opts.ringbuffer_on) {
+  if (capture_opts.multi_files_on) {
     ringbuf_error_cleanup();
   }
-  g_free(save_file);
-  save_file = NULL;
-  fprintf(stderr, "tethereal: %s\n", errmsg);
+  g_free(capture_opts.save_file);
+  capture_opts.save_file = NULL;
+  if (cfilter_error) {
+    dfilter_t   *rfcode = NULL;
+    if (dfilter_compile(capture_opts.cfilter, &rfcode) && rfcode != NULL) {
+      cmdarg_err(
+        "Invalid capture filter: \"%s\"!\n"
+        "\n"
+        "That string looks like a valid display filter; however, it isn't a valid\n"
+        "capture filter (%s).\n"
+        "\n"
+        "Note that display filters and capture filters don't have the same syntax,\n"
+        "so you can't use most display filter expressions as capture filters.\n"
+        "\n"
+        "See the User's Guide for a description of the capture filter syntax.",
+        capture_opts.cfilter, errmsg);
+      dfilter_free(rfcode);
+    } else {
+      cmdarg_err(
+        "Invalid capture filter: \"%s\"!\n"
+        "\n"
+        "That string isn't a valid capture filter (%s).\n"
+        "See the User's Guide for a description of the capture filter syntax.",
+        capture_opts.cfilter, errmsg);
+    }
+  } else {
+    cmdarg_err("%s", errmsg);
+    if (*secondary_errmsg != '\0') {
+      fprintf(stderr, "\n");
+      cmdarg_err_cont("%s", secondary_errmsg);
+    }
+  }
 #ifndef _WIN32
-  if (ld.from_pipe) {
-    if (pipe_fd >= 0)
-      close(pipe_fd);
+  if (ld.from_cap_pipe) {
+    if (ld.cap_pipe_fd >= 0)
+      eth_close(ld.cap_pipe_fd);
   } else
 #endif
   {
-  if (ld.pch != NULL)
-    pcap_close(ld.pch);
+  if (ld.pcap_h != NULL)
+    pcap_close(ld.pcap_h);
   }
 
   return FALSE;
 }
 
 static void
-capture_pcap_cb(guchar *user, const struct pcap_pkthdr *phdr,
-  const guchar *pd)
+capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
+  const u_char *pd)
 {
   struct wtap_pkthdr whdr;
   union wtap_pseudo_header pseudo_header;
-  loop_data *ldat = (loop_data *) user;
+  const guchar *wtap_pd;
+  loop_data *ld = (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(ldat->linktype, phdr, pd, &pseudo_header,
-                               &whdr, &err);
-  if (pd == NULL)
-    return;
+  gboolean packet_accepted;
 
 #ifdef SIGINFO
   /*
@@ -2206,29 +1887,63 @@ capture_pcap_cb(guchar *user, const struct pcap_pkthdr *phdr,
    * 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)) {
+  if (cnd_file_duration != NULL && cnd_eval(cnd_file_duration)) {
     /* time elapsed for this ring file, switch to the next */
-    if (ringbuf_switch_file(&ldat->pdh, &ldat->save_file, &save_file_fd, &loop_err)) {
+    if (ringbuf_switch_file(&ld->pdh, &ld->save_file, &save_file_fd, &loop_err)) {
       /* File switch succeeded: reset the condition */
-      cnd_reset(cnd_ring_timeout);
+      cnd_reset(cnd_file_duration);
     } else {
       /* File switch failed: stop here */
       /* XXX - we should do something with "loop_err" */
-      ldat->go = FALSE;
+      ld->go = FALSE;
     }
   }
 
-  if (!process_packet(&cfile, ldat->pdh, 0, &whdr, &pseudo_header, pd, &err)) {
-    /* Error writing to a capture file */
-    if (!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 (do_dissection) {
+    /* We're goint to print packet information, run a read filter, or
+       process taps.  Use process_packet() to handle that; in order
+       to do that, we need to convert from libpcap to Wiretap format.
+       If that fails, ignore the packet (wtap_process_pcap_packet has
+       written an error message). */
+    wtap_pd = wtap_process_pcap_packet(ld->wtap_linktype, phdr, pd,
+                                       &pseudo_header, &whdr, &err);
+    if (wtap_pd == NULL)
+      return;
+
+    packet_accepted = process_packet(&cfile, 0, &whdr, &pseudo_header, wtap_pd);
+  } else {
+    /* We're just writing out packets. */
+    packet_accepted = TRUE;
+  }
+
+  if (packet_accepted) {
+    /* Count this packet. */
+#ifdef HAVE_LIBPCAP
+    ld->packet_count++;
+#endif
+
+    if (ld->pdh != NULL) {
+      if (!libpcap_write_packet(ld->pdh, phdr, pd, &ld->bytes_written, &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");
+        }
+        show_capture_file_io_error(ld->save_file, err, FALSE);
+        pcap_close(ld->pcap_h);
+        libpcap_dump_close(ld->pdh, &err);
+        exit(2);
+      }
+    }
+    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);
+      }
     }
-    show_capture_file_io_error(ldat->save_file, err, FALSE);
-    pcap_close(ldat->pch);
-    wtap_dump_close(ldat->pdh, &err);
-    exit(2);
   }
 
 #ifdef SIGINFO
@@ -2296,13 +2011,13 @@ report_counts(void)
   signal(SIGINFO, report_counts_siginfo);
 #endif /* SIGINFO */
 
-  if (quiet || print_packet_info) {
+  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
-  infoprint = FALSE;   /* we just reported it */
+  infoprint = FALSE; /* we just reported it */
 #endif /* SIGINFO */
 }
 
@@ -2332,52 +2047,49 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type)
   int          err;
   gchar        *err_info;
   long         data_offset;
+  char         *save_file_string = NULL;
 
   linktype = wtap_file_encap(cf->wth);
   if (save_file != NULL) {
+    /* Get a string that describes what we're writing to */
+    save_file_string = output_file_description(save_file);
+
     /* 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(save_file, out_file_type,
-               linktype, snapshot_length, &err);
+    pdh = wtap_dump_open(save_file, out_file_type, linktype, snapshot_length,
+                         FALSE /* compressed */, &err);
 
     if (pdh == NULL) {
       /* We couldn't set up to write to the capture file. */
       switch (err) {
 
       case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
-        fprintf(stderr,
-               "tethereal: Capture files can't be written in that format.\n");
+        cmdarg_err("Capture files can't be written in that format.");
         break;
 
       case WTAP_ERR_UNSUPPORTED_ENCAP:
       case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
-        fprintf(stderr,
-          "tethereal: The capture file being read can't be written in "
-          "that format.\n");
+        cmdarg_err("The capture file being read can't be written in "
+          "that format.");
         break;
 
       case WTAP_ERR_CANT_OPEN:
-        fprintf(stderr,
-          "tethereal: The file \"%s\" couldn't be created for some "
-          "unknown reason.\n",
-            *save_file == '\0' ? "stdout" : save_file);
+        cmdarg_err("The %s couldn't be created for some "
+          "unknown reason.", save_file_string);
         break;
 
       case WTAP_ERR_SHORT_WRITE:
-        fprintf(stderr,
-          "tethereal: A full header couldn't be written to the file \"%s\".\n",
-               *save_file == '\0' ? "stdout" : save_file);
+        cmdarg_err("A full header couldn't be written to the %s.",
+                   save_file_string);
         break;
 
       default:
-        fprintf(stderr,
-          "tethereal: The file \"%s\" could not be created: %s\n.",
-               *save_file == '\0' ? "stdout" : save_file,
-               wtap_strerror(err));
+        cmdarg_err("The %s could not be created: %s.", save_file_string,
+                   wtap_strerror(err));
         break;
       }
       goto out;
@@ -2393,13 +2105,21 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type)
     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 (process_packet(cf, data_offset, wtap_phdr(cf->wth),
+                       wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth))) {
+      /* Either there's no read filtering or this packet passed the
+         filter, so, if we're writing to a capture file, write
+         this packet out. */
+      if (pdh != NULL) {
+        if (!wtap_dump(pdh, 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) {
@@ -2407,33 +2127,28 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type)
     switch (err) {
 
     case WTAP_ERR_UNSUPPORTED_ENCAP:
-      fprintf(stderr,
-"tethereal: \"%s\" has a packet with a network type that Tethereal doesn't support.\n(%s)\n",
-       cf->filename, err_info);
+      cmdarg_err("\"%s\" has a packet with a network type that Tethereal doesn't support.\n(%s)",
+                 cf->filename, err_info);
       break;
 
     case WTAP_ERR_CANT_READ:
-      fprintf(stderr,
-"tethereal: An attempt to read from \"%s\" failed for some unknown reason.\n",
-       cf->filename);
+      cmdarg_err("An attempt to read from \"%s\" failed for some unknown reason.",
+                 cf->filename);
       break;
 
     case WTAP_ERR_SHORT_READ:
-      fprintf(stderr,
-"tethereal: \"%s\" appears to have been cut short in the middle of a packet.\n",
-       cf->filename);
+      cmdarg_err("\"%s\" appears to have been cut short in the middle of a packet.",
+                 cf->filename);
       break;
 
     case WTAP_ERR_BAD_RECORD:
-      fprintf(stderr,
-"tethereal: \"%s\" appears to be damaged or corrupt.\n(%s)\n",
-       cf->filename, err_info);
+      cmdarg_err("\"%s\" appears to be damaged or corrupt.\n(%s)",
+                 cf->filename, err_info);
       break;
 
     default:
-      fprintf(stderr,
-"tethereal: An error occurred while reading \"%s\": %s.\n",
-       cf->filename, wtap_strerror(err));
+      cmdarg_err("An error occurred while reading \"%s\": %s.",
+                 cf->filename, wtap_strerror(err));
       break;
     }
     if (save_file != NULL) {
@@ -2460,12 +2175,15 @@ out:
   wtap_close(cf->wth);
   cf->wth = NULL;
 
+  if (save_file_string != NULL)
+    g_free(save_file_string);
+
   return err;
 }
 
 static void
 fill_in_fdata(frame_data *fdata, capture_file *cf,
-       const struct wtap_pkthdr *phdr, long offset)
+              const struct wtap_pkthdr *phdr, long offset)
 {
   fdata->next = NULL;
   fdata->prev = NULL;
@@ -2477,50 +2195,44 @@ fill_in_fdata(frame_data *fdata, capture_file *cf,
   fdata->cap_len = phdr->caplen;
   fdata->file_off = offset;
   fdata->lnk_t = phdr->pkt_encap;
-  fdata->abs_secs  = phdr->ts.tv_sec;
-  fdata->abs_usecs = phdr->ts.tv_usec;
+  fdata->abs_ts = *((nstime_t *) &phdr->ts);
   fdata->flags.passed_dfilter = 0;
   fdata->flags.encoding = CHAR_ASCII;
   fdata->flags.visited = 0;
   fdata->flags.marked = 0;
   fdata->flags.ref_time = 0;
+  fdata->color_filter = NULL;
 
   /* If we don't have the time stamp of the first packet in the
      capture, it's because this is the first packet.  Save the time
      stamp of this packet as the time stamp of the first packet. */
-  if (!firstsec && !firstusec) {
-    firstsec  = fdata->abs_secs;
-    firstusec = fdata->abs_usecs;
+  if (nstime_is_zero(&first_ts)) {
+    first_ts = fdata->abs_ts;
   }
 
   /* If we don't have the time stamp of the previous displayed packet,
      it's because this is the first displayed packet.  Save the time
      stamp of this packet as the time stamp of the previous displayed
      packet. */
-  if (!prevsec && !prevusec) {
-    prevsec  = fdata->abs_secs;
-    prevusec = fdata->abs_usecs;
+  if (nstime_is_zero(&prev_ts)) {
+    prev_ts = fdata->abs_ts;
   }
 
   /* Get the time elapsed between the first packet and this packet. */
-  compute_timestamp_diff(&fdata->rel_secs, &fdata->rel_usecs,
-               fdata->abs_secs, fdata->abs_usecs, firstsec, firstusec);
+  nstime_delta(&fdata->rel_ts, &fdata->abs_ts, &first_ts);
 
   /* If it's greater than the current elapsed time, set the elapsed time
      to it (we check for "greater than" so as not to be confused by
      time moving backwards). */
-  if ((gint32)cf->esec < fdata->rel_secs
-       || ((gint32)cf->esec == fdata->rel_secs && (gint32)cf->eusec < fdata->rel_usecs)) {
-    cf->esec = fdata->rel_secs;
-    cf->eusec = fdata->rel_usecs;
+  if ((gint32)cf->elapsed_time.secs < fdata->rel_ts.secs
+       || ((gint32)cf->elapsed_time.secs == fdata->rel_ts.secs && (gint32)cf->elapsed_time.nsecs < fdata->rel_ts.nsecs)) {
+    cf->elapsed_time = fdata->rel_ts;
   }
 
   /* Get the time elapsed between the previous displayed packet and
      this packet. */
-  compute_timestamp_diff(&fdata->del_secs, &fdata->del_usecs,
-               fdata->abs_secs, fdata->abs_usecs, prevsec, prevusec);
-  prevsec = fdata->abs_secs;
-  prevusec = fdata->abs_usecs;
+  nstime_delta(&fdata->del_ts, &fdata->abs_ts, &prev_ts);
+  prev_ts = fdata->abs_ts;
 }
 
 /* Free up all data attached to a "frame_data" structure. */
@@ -2532,10 +2244,8 @@ clear_fdata(frame_data *fdata)
 }
 
 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)
+process_packet(capture_file *cf, long offset, const struct wtap_pkthdr *whdr,
+               union wtap_pseudo_header *pseudo_header, const guchar *pd)
 {
   frame_data fdata;
   gboolean create_proto_tree;
@@ -2599,29 +2309,7 @@ process_packet(capture_file *cf, wtap_dumper *pdh, long offset,
   }
 
   if (passed) {
-    /* Count this packet. */
-#ifdef HAVE_LIBPCAP
-    ld.packet_count++;
-#endif
-
     /* 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
-      /* Report packet capture count if not quiet */
-      if (!quiet && !print_packet_info) {
-       /* Don't print a packet count if we were asked not to with "-q"
-          or if we're also printing packet info. */
-        if (ld.packet_count != 0) {
-          fprintf(stderr, "\r%u ", ld.packet_count);
-          /* stderr could be line buffered */
-          fflush(stderr);
-        }
-      }
-#endif
-    }
     if (print_packet_info) {
       /* We're printing packet information; print the information for
          this packet. */
@@ -2661,57 +2349,53 @@ process_packet(capture_file *cf, wtap_dumper *pdh, long offset,
     epan_dissect_free(edt);
     clear_fdata(&fdata);
   }
-  return TRUE;
+  return passed;
 }
 
 static void
 show_capture_file_io_error(const char *fname, int err, gboolean is_close)
 {
-  if (*fname == '\0')
-    fname = "stdout";
+  char *save_file_string;
+
+  save_file_string = output_file_description(fname);
 
   switch (err) {
 
   case ENOSPC:
-    fprintf(stderr,
-"tethereal: Not all the packets could be written to \"%s\" because there is "
-"no space left on the file system.\n",
-       fname);
+    cmdarg_err("Not all the packets could be written to the %s because there is "
+               "no space left on the file system.",
+               save_file_string);
     break;
 
 #ifdef EDQUOT
   case EDQUOT:
-    fprintf(stderr,
-"tethereal: Not all the packets could be written to \"%s\" because you are "
-"too close to, or over your disk quota.\n",
-       fname);
+    cmdarg_err("Not all the packets could be written to the %s because you are "
+               "too close to, or over your disk quota.",
+               save_file_string);
   break;
 #endif
 
   case WTAP_ERR_CANT_CLOSE:
-    fprintf(stderr,
-"tethereal: \"%s\" couldn't be closed for some unknown reason.\n",
-       fname);
+    cmdarg_err("The %s couldn't be closed for some unknown reason.",
+               save_file_string);
     break;
 
   case WTAP_ERR_SHORT_WRITE:
-    fprintf(stderr,
-"tethereal: Not all the packets could be written to \"%s\".\n",
-       fname);
+    cmdarg_err("Not all the packets could be written to the %s.",
+               save_file_string);
     break;
 
   default:
     if (is_close) {
-      fprintf(stderr,
-"tethereal: \"%s\" could not be closed: %s.\n",
-       fname, wtap_strerror(err));
+      cmdarg_err("The %s could not be closed: %s.", save_file_string,
+                 wtap_strerror(err));
     } else {
-      fprintf(stderr,
-"tethereal: An error occurred while writing to \"%s\": %s.\n",
-       fname, wtap_strerror(err));
+      cmdarg_err("An error occurred while writing to the %s: %s.",
+                 save_file_string, wtap_strerror(err));
     }
     break;
   }
+  g_free(save_file_string);
 }
 
 static gboolean
@@ -2772,6 +2456,7 @@ print_columns(capture_file *cf)
   for (i = 0; i < cf->cinfo.num_cols; i++) {
     switch (cf->cinfo.col_fmt[i]) {
     case COL_NUMBER:
+#ifdef HAVE_LIBPCAP
       /*
        * 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
@@ -2785,6 +2470,7 @@ print_columns(capture_file *cf)
        */
       if (capture_opts.iface != NULL)
         continue;
+#endif
       column_len = strlen(cf->cinfo.col_data[i]);
       if (column_len < 3)
         column_len = 3;
@@ -2795,7 +2481,7 @@ print_columns(capture_file *cf)
     case COL_CLS_TIME:
     case COL_REL_TIME:
     case COL_ABS_TIME:
-    case COL_ABS_DATE_TIME:    /* XXX - wider */
+    case COL_ABS_DATE_TIME: /* XXX - wider */
       column_len = strlen(cf->cinfo.col_data[i]);
       if (column_len < 10)
         column_len = 10;
@@ -3074,32 +2760,29 @@ show_print_file_io_error(int err)
   switch (err) {
 
   case ENOSPC:
-    fprintf(stderr,
-"tethereal: Not all the packets could be printed because there is "
-"no space left on the file system.\n");
+    cmdarg_err("Not all the packets could be printed because there is "
+"no space left on the file system.");
     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");
+    cmdarg_err("Not all the packets could be printed because you are "
+"too close to, or over your disk quota.");
   break;
 #endif
 
   default:
-    fprintf(stderr,
-"tethereal: An error occurred while printing packets: %s.\n",
+    cmdarg_err("An error occurred while printing packets: %s.",
       strerror(err));
     break;
   }
 }
 
-static char *
+static const char *
 cf_open_error_message(int err, gchar *err_info, gboolean for_writing,
                       int file_type)
 {
-  char *errmsg;
+  const char *errmsg;
   static char errmsg_errno[1024+1];
 
   if (err < 0) {
@@ -3117,7 +2800,7 @@ cf_open_error_message(int err, gchar *err_info, gboolean for_writing,
 
     case WTAP_ERR_UNSUPPORTED:
       /* Seen only when opening a capture file for reading. */
-      snprintf(errmsg_errno, sizeof(errmsg_errno),
+      g_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);
@@ -3126,9 +2809,9 @@ cf_open_error_message(int err, gchar *err_info, gboolean for_writing,
 
     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));
+      g_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;
 
@@ -3141,7 +2824,7 @@ cf_open_error_message(int err, gchar *err_info, gboolean for_writing,
       if (for_writing)
         errmsg = "Tethereal can't save this capture in that format.";
       else {
-        snprintf(errmsg_errno, sizeof(errmsg_errno),
+        g_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);
@@ -3158,7 +2841,7 @@ cf_open_error_message(int err, gchar *err_info, gboolean for_writing,
 
     case WTAP_ERR_BAD_RECORD:
       /* Seen only when opening a capture file for reading. */
-      snprintf(errmsg_errno, sizeof(errmsg_errno),
+      g_snprintf(errmsg_errno, sizeof(errmsg_errno),
                "The file \"%%s\" appears to be damaged or corrupt.\n"
                "(%s)", err_info);
       g_free(err_info);
@@ -3182,10 +2865,10 @@ cf_open_error_message(int err, gchar *err_info, gboolean for_writing,
       break;
 
     default:
-      snprintf(errmsg_errno, sizeof(errmsg_errno),
-              "The file \"%%s\" could not be %s: %s.",
-              for_writing ? "created" : "opened",
-              wtap_strerror(err));
+      g_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;
     }
@@ -3222,8 +2905,7 @@ cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
   init_dissection();
 
   cf->wth = wth;
-  cf->filed = -1;      /* not used, but set it anyway */
-  cf->f_len = 0;       /* not used, but set it anyway */
+  cf->f_datalen = 0; /* not used, but set it anyway */
 
   /* Set the file name because we need it to set the follow stream filter.
      XXX - is that still true?  We need it for other reasons, though,
@@ -3240,8 +2922,6 @@ cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
   cf->count     = 0;
   cf->drops_known = FALSE;
   cf->drops     = 0;
-  cf->esec      = 0;
-  cf->eusec     = 0;
   cf->snap      = wtap_snapshot_length(cf->wth);
   if (cf->snap == 0) {
     /* Snapshot length not known. */
@@ -3249,323 +2929,136 @@ cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
     cf->snap = WTAP_MAX_PACKET_SIZE;
   } else
     cf->has_snap = TRUE;
-  firstsec = 0, firstusec = 0;
-  prevsec = 0, prevusec = 0;
+  nstime_set_zero(&cf->elapsed_time);
+  nstime_set_zero(&first_ts);
+  nstime_set_zero(&prev_ts);
 
   return CF_OK;
 
 fail:
-  snprintf(err_msg, sizeof err_msg,
-           cf_open_error_message(*err, err_info, FALSE, 0), fname);
-  fprintf(stderr, "tethereal: %s\n", err_msg);
+  g_snprintf(err_msg, sizeof err_msg,
+             cf_open_error_message(*err, err_info, FALSE, cf->cd_t), fname);
+  cmdarg_err("%s", err_msg);
   return CF_ERROR;
 }
 
-#ifdef HAVE_LIBPCAP
-#ifndef _WIN32
-/* Take care of byte order in the libpcap headers read from pipes.
- * (function taken from wiretap/libpcap.c) */
+
+/*
+ * General errors are reported with an console message in Tethereal.
+ */
 static void
-adjust_header(loop_data *ldat, struct pcap_hdr *hdr, struct pcaprec_hdr *rechdr)
+failure_message(const char *msg_format, va_list ap)
 {
-  if (ldat->byte_swapped) {
-    /* Byte-swap the record header fields. */
-    rechdr->ts_sec = BSWAP32(rechdr->ts_sec);
-    rechdr->ts_usec = BSWAP32(rechdr->ts_usec);
-    rechdr->incl_len = BSWAP32(rechdr->incl_len);
-    rechdr->orig_len = BSWAP32(rechdr->orig_len);
-  }
-
-  /* In file format version 2.3, the "incl_len" and "orig_len" fields were
-     swapped, in order to match the BPF header layout.
-
-     Unfortunately, some files were, according to a comment in the "libpcap"
-     source, written with version 2.3 in their headers but without the
-     interchanged fields, so if "incl_len" is greater than "orig_len" - which
-     would make no sense - we assume that we need to swap them.  */
-  if (hdr->version_major == 2 &&
-      (hdr->version_minor < 3 ||
-       (hdr->version_minor == 3 && rechdr->incl_len > rechdr->orig_len))) {
-    guint32 temp;
-
-    temp = rechdr->orig_len;
-    rechdr->orig_len = rechdr->incl_len;
-    rechdr->incl_len = temp;
-  }
+  fprintf(stderr, "tethereal: ");
+  vfprintf(stderr, msg_format, ap);
+  fprintf(stderr, "\n");
 }
 
-/* Mimic pcap_open_live() for pipe captures
- * We check if "pipename" is "-" (stdin) or a FIFO, open it, and read the
- * header.
- * 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 *ldat,
-                 char *errmsg, int errmsgl)
+/*
+ * Read errors are reported with an console message in Tethereal.
+ */
+static void
+read_failure_message(const char *filename, int err)
 {
-  struct stat pipe_stat;
-  int         fd;
-  guint32     magic;
-  int         b;
-  unsigned int bytes_read;
+  cmdarg_err("An error occurred while reading from the file \"%s\": %s.",
+          filename, strerror(err));
+}
 
-  /*
-   * XXX Tethereal blocks until we return
-   */
-  if (strcmp(pipename, "-") == 0)
-    fd = 0; /* read from stdin */
-  else {
-    if (stat(pipename, &pipe_stat) < 0) {
-      if (errno == ENOENT || errno == ENOTDIR)
-        ldat->pipe_err = PIPNEXIST;
-      else {
-        snprintf(errmsg, errmsgl,
-          "The capture session could not be initiated "
-          "due to error on pipe: %s", strerror(errno));
-        ldat->pipe_err = PIPERR;
-      }
-      return -1;
-    }
-    if (! S_ISFIFO(pipe_stat.st_mode)) {
-      if (S_ISCHR(pipe_stat.st_mode)) {
-        /*
-         * Assume the user specified an interface on a system where
-         * interfaces are in /dev.  Pretend we haven't seen it.
-         */
-         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);
-        ldat->pipe_err = PIPERR;
-      }
-      return -1;
-    }
-    fd = open(pipename, O_RDONLY);
-    if (fd == -1) {
-      snprintf(errmsg, errmsgl,
-          "The capture session could not be initiated "
-          "due to error on pipe open: %s", strerror(errno));
-      ldat->pipe_err = PIPERR;
-      return -1;
-    }
-  }
+/*
+ * Report an error in command-line arguments.
+ */
+void
+cmdarg_err(const char *fmt, ...)
+{
+  va_list ap;
 
-  ldat->from_pipe = TRUE;
+  va_start(ap, fmt);
+  fprintf(stderr, "tethereal: ");
+  vfprintf(stderr, fmt, ap);
+  fprintf(stderr, "\n");
+  va_end(ap);
+}
 
-  /* read the pcap header */
-  bytes_read = 0;
-  while (bytes_read < sizeof magic) {
-    b = read(fd, ((char *)&magic)+bytes_read, sizeof magic-bytes_read);
-    if (b <= 0) {
-      if (b == 0)
-        snprintf(errmsg, errmsgl, "End of file on pipe during open");
-      else
-        snprintf(errmsg, errmsgl, "Error on pipe during open: %s",
-          strerror(errno));
-      goto error;
-    }
-    bytes_read += b;
-  }
+/*
+ * Report additional information for an error in command-line arguments.
+ */
+void
+cmdarg_err_cont(const char *fmt, ...)
+{
+  va_list ap;
 
-  switch (magic) {
-  case PCAP_MAGIC:
-    /* Host that wrote it has our byte order, and was running
-       a program using either standard or ss990417 libpcap. */
-    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. */
-    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. */
-    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. */
-    ldat->byte_swapped = TRUE;
-    ldat->modified = TRUE;
-    break;
-  default:
-    /* Not a "libpcap" type we know about. */
-    snprintf(errmsg, errmsgl, "Unrecognized libpcap format");
-    goto error;
-  }
+  va_start(ap, fmt);
+  vfprintf(stderr, fmt, ap);
+  fprintf(stderr, "\n");
+  va_end(ap);
+}
 
-  /* Read the rest of the header */
-  bytes_read = 0;
-  while (bytes_read < sizeof(struct pcap_hdr)) {
-    b = read(fd, ((char *)hdr)+bytes_read,
-          sizeof(struct pcap_hdr) - bytes_read);
-    if (b <= 0) {
-      if (b == 0)
-        snprintf(errmsg, errmsgl, "End of file on pipe during open");
-      else
-        snprintf(errmsg, errmsgl, "Error on pipe during open: %s",
-          strerror(errno));
-      goto error;
-    }
-    bytes_read += b;
-  }
 
-  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);
-    hdr->snaplen = BSWAP32(hdr->snaplen);
-    hdr->network = BSWAP32(hdr->network);
-  }
+/****************************************************************************************************************/
+/* indication report "dummies", needed for capture_loop.c */
 
-  if (hdr->version_major < 2) {
-    snprintf(errmsg, errmsgl, "Unable to read old libpcap format");
-    goto error;
-  }
+#ifdef HAVE_LIBPCAP
 
-  ldat->pipe_state = STATE_EXPECT_REC_HDR;
-  ldat->pipe_err = PIPOK;
-  return fd;
+/** Report a new capture file having been opened. */
+void
+report_new_capture_file(const char *filename)
+{
+    /* shouldn't happen */
+    g_assert_not_reached();
+}
 
-error:
-  ldat->pipe_err = PIPERR;
-  close(fd);
-  return -1;
+/** Report a number of new packets captured. */
+void
+report_packet_count(int packet_count)
+{
+    /* shouldn't happen */
+    g_assert_not_reached();
+}
 
+/** Report the packet drops once the capture finishes. */
+void
+report_packet_drops(int drops)
+{
+    /* shouldn't happen */
+    g_assert_not_reached();
 }
-/* We read one record from the pipe, take care of byte order in the record
- * header, write the record in the capture file, and update capture statistics. */
 
-static int
-pipe_dispatch(int fd, loop_data *ldat, struct pcap_hdr *hdr,
-                struct pcaprec_modified_hdr *rechdr, guchar *data,
-                char *errmsg, int errmsgl)
+/** Report an error in the capture. */
+void 
+report_capture_error(const char *errmsg, const char *secondary_error_msg)
 {
-  struct pcap_pkthdr phdr;
-  int b;
-  enum { PD_REC_HDR_READ, PD_DATA_READ, PD_PIPE_EOF, PD_PIPE_ERR,
-          PD_ERR } result;
-
-  switch (ldat->pipe_state) {
-
-  case STATE_EXPECT_REC_HDR:
-    ldat->bytes_to_read = ldat->modified ?
-      sizeof(struct pcaprec_modified_hdr) : sizeof(struct pcaprec_hdr);
-    ldat->bytes_read = 0;
-    ldat->pipe_state = STATE_READ_REC_HDR;
-    /* Fall through */
-
-  case STATE_READ_REC_HDR:
-    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;
-      else
-        result = PD_PIPE_ERR;
-      break;
-    }
-    if ((ldat->bytes_read += b) < ldat->bytes_to_read)
-        return 0;
-    result = PD_REC_HDR_READ;
-    break;
+    cmdarg_err(errmsg);
+    cmdarg_err_cont(secondary_error_msg);
+}
 
-  case STATE_EXPECT_DATA:
-    ldat->bytes_read = 0;
-    ldat->pipe_state = STATE_READ_DATA;
-    /* Fall through */
+/** Report an error with a capture filter. */
+void
+report_cfilter_error(const char *cfilter, const char *errmsg)
+{
 
-  case STATE_READ_DATA:
-    b = read(fd, data+ldat->bytes_read, rechdr->hdr.incl_len - ldat->bytes_read);
-    if (b <= 0) {
-      if (b == 0)
-        result = PD_PIPE_EOF;
-      else
-        result = PD_PIPE_ERR;
-      break;
-    }
-    if ((ldat->bytes_read += b) < rechdr->hdr.incl_len)
-      return 0;
-    result = PD_DATA_READ;
-    break;
+    cmdarg_err(
+      "Invalid capture filter: \"%s\"!\n"
+      "\n"
+      "That string isn't a valid capture filter (%s).\n"
+      "See the User's Guide for a description of the capture filter syntax.",
+      cfilter, errmsg);
+}
 
-  default:
-    snprintf(errmsg, errmsgl, "pipe_dispatch: invalid state");
-    result = PD_ERR;
+#endif /* HAVE_LIBPCAP */
 
-  } /* switch (ldat->pipe_state) */
 
-  /*
-   * We've now read as much data as we were expecting, so process it.
-   */
-  switch (result) {
-
-  case PD_REC_HDR_READ:
-    /* We've read the header. Take care of byte order. */
-    adjust_header(ldat, hdr, &rechdr->hdr);
-    if (rechdr->hdr.incl_len > WTAP_MAX_PACKET_SIZE) {
-      snprintf(errmsg, errmsgl, "Frame %u too long (%d bytes)",
-        ldat->packet_count+1, rechdr->hdr.incl_len);
-      break;
-    }
-    ldat->pipe_state = STATE_EXPECT_DATA;
-    return 0;
-
-  case PD_DATA_READ:
-    /* Fill in a "struct pcap_pkthdr", and process the packet. */
-    phdr.ts.tv_sec = rechdr->hdr.ts_sec;
-    phdr.ts.tv_usec = rechdr->hdr.ts_usec;
-    phdr.caplen = rechdr->hdr.incl_len;
-    phdr.len = rechdr->hdr.orig_len;
-
-    capture_pcap_cb((guchar *)ldat, &phdr, data);
-
-    ldat->pipe_state = STATE_EXPECT_REC_HDR;
-    return 1;
-
-  case PD_PIPE_EOF:
-    ldat->pipe_err = PIPEOF;
-    return -1;
-
-  case PD_PIPE_ERR:
-    snprintf(errmsg, errmsgl, "Error reading from pipe: %s",
-      strerror(errno));
-    /* Fall through */
-  case PD_ERR:
-    break;
-  }
+/****************************************************************************************************************/
+/* signal pipe "dummies", needed for capture_loop.c */
 
-  ldat->pipe_err = PIPERR;
-  /* Return here rather than inside the switch to prevent GCC warning */
-  return -1;
-}
-#endif /* _WIN32 */
-#endif /* HAVE_LIBPCAP */
+#ifdef HAVE_LIBPCAP
 
-/*
- * General errors are reported with an console message in Tethereal.
- */
-static void
-failure_message(const char *msg_format, va_list ap)
+#ifdef _WIN32
+gboolean
+signal_pipe_check_running(void)
 {
-  fprintf(stderr, "tethereal: ");
-  vfprintf(stderr, msg_format, ap);
-  fprintf(stderr, "\n");
+    /* currently, no check required */
+    return TRUE;
 }
+#endif  /* _WIN32 */
 
-/*
- * 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));
-}
+#endif /* HAVE_LIBPCAP */