Change some of the merge.c APIs to return more information on failure,
authorGuy Harris <guy@alum.mit.edu>
Wed, 27 Oct 2004 23:28:37 +0000 (23:28 -0000)
committerGuy Harris <guy@alum.mit.edu>
Wed, 27 Oct 2004 23:28:37 +0000 (23:28 -0000)
and use that information to provide better error messages.

Have "merge_open_outfile()" do all the work of filling in the
merge_out_file_t structure, with the values to use passed as arguments.
Get rid of some structure members that used to be used solely to pass
information to "merge_open_outfile()".

Add a "cf_merge_files()" routine to do the merging and reporting of errors.

svn path=/trunk/; revision=12420

file.c
file.h
gtk/file_dlg.c
gtk/main.c
merge.c
merge.h
mergecap.c

diff --git a/file.c b/file.c
index c4b6a0c570bcd34e419b79a31d4532a330089124..f7c3f1b71d4d0371289131e4454920d34bf5284f 100644 (file)
--- a/file.c
+++ b/file.c
@@ -75,6 +75,7 @@
 #include "file.h"
 #include "menu.h"
 #include "util.h"
+#include "merge.h"
 #include "alert_box.h"
 #include "simple_dialog.h"
 #include "progress_dlg.h"
@@ -967,6 +968,40 @@ read_packet(capture_file *cf, long offset)
   }
 }
 
+gboolean
+cf_merge_files(const char *out_file, int out_fd, int in_file_count,
+               char *const *in_filenames, int filetype, gboolean do_append)
+{
+  merge_status_e  merge_status;
+  int             err;
+  gchar          *err_info;
+  int             err_fileno; 
+
+  merge_status = merge_n_files(out_fd, in_file_count, in_filenames, filetype,
+                               do_append, &err, &err_info, &err_fileno);
+
+  switch (merge_status) {
+
+  case MERGE_SUCCESS:
+    return TRUE;
+
+  case MERGE_OPEN_INPUT_FAILED:
+    cf_open_failure_alert_box(in_filenames[err_fileno], err, err_info, FALSE, 0);
+    return FALSE;
+
+  case MERGE_OPEN_OUTPUT_FAILED:
+    cf_open_failure_alert_box(out_file, err, err_info, TRUE, filetype);
+    return FALSE;
+
+  /* XXX - what about read failures? */
+
+  case MERGE_WRITE_FAILED:
+    cf_write_failure_alert_box(out_file, err);
+    return FALSE;
+  }
+  return TRUE;
+}
+
 gboolean
 filter_packets(capture_file *cf, gchar *dftext, gboolean force)
 {
diff --git a/file.h b/file.h
index b72c9d09ba2e0673a8262d16108d678cdcd87237..967eeb8aaa43e7314d84dc0785002679e498b31e 100644 (file)
--- a/file.h
+++ b/file.h
@@ -53,6 +53,10 @@ read_status_t cf_finish_tail(capture_file *, int *);
 gboolean cf_save(char *fname, capture_file * cf, packet_range_t *range, guint save_format);
 gchar *cf_get_display_name(capture_file *);
 
+gboolean
+cf_merge_files(const char *out_file, int out_fd, int in_file_count,
+               char *const *in_filenames, int filetype, gboolean do_append);
+
 gboolean filter_packets(capture_file *cf, gchar *dfilter, gboolean force);
 void reftime_packets(capture_file *);
 void colorize_packets(capture_file *);
index 131ade221bec62286e10b7f97fa14bb9ba768c6c..2d2fe308162200b758bfe96150ed8ecfd70a9e58 100644 (file)
@@ -998,8 +998,8 @@ file_merge_ok_cb(GtkWidget *w, gpointer fs) {
   int        err;
   gboolean   merge_ok;
   char      *in_filenames[2];
-  int       out_fd;
-  char      tmpname[128+1];
+  int        out_fd;
+  char       tmpname[128+1];
 
 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
   cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
@@ -1030,33 +1030,32 @@ file_merge_ok_cb(GtkWidget *w, gpointer fs) {
   /* merge or append the two files */
   rb = OBJECT_GET_DATA(w, E_MERGE_CHRONO_KEY);
   if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (rb))) {
-      /* chonological order */
+      /* chronological order */
       in_filenames[0] = cfile.filename;
       in_filenames[1] = cf_name;
-      merge_ok = merge_n_files(out_fd, 2, in_filenames, filetype, FALSE, &err);
+      merge_ok = cf_merge_files(tmpname, out_fd, 2, in_filenames,
+                                filetype, FALSE);
   } else {
       rb = OBJECT_GET_DATA(w, E_MERGE_PREPEND_KEY);
       if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (rb))) {
           /* prepend file */
           in_filenames[0] = cfile.filename;
           in_filenames[1] = cf_name;
-          merge_ok = merge_n_files(out_fd, 2, in_filenames, filetype, TRUE, &err);
+          merge_ok = cf_merge_files(tmpname, out_fd, 2, in_filenames,
+                                    filetype, TRUE);
       } else {
           /* append file */
           in_filenames[0] = cf_name;
           in_filenames[1] = cfile.filename;
-          merge_ok = merge_n_files(out_fd, 2, in_filenames, filetype, TRUE, &err);
+          merge_ok = cf_merge_files(tmpname, out_fd, 2, in_filenames,
+                                    filetype, TRUE);
       }
   }
 
   g_free(cf_name);
   
-  if(!merge_ok) {
-    /* merge failed */
-    simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-                 "An error occurred while merging the files: %s.",
-                 wtap_strerror(err));
-    close(out_fd);
+  if (!merge_ok) {
+    close(out_fd);     /* XXX - it's already closed, right? */
     if (rfcode != NULL)
       dfilter_free(rfcode);
     return;
index 25e5dc30abeac3e4607f1218bc35bf8724ac562e..259e1c2cd4b28a0c0b67af1cd85fd69251e52637 100644 (file)
@@ -1319,53 +1319,51 @@ dnd_merge_files(int in_file_count, char **in_filenames)
     out_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
 
     /* merge the files in chonological order */
-    merge_ok = merge_n_files(out_fd, in_file_count, in_filenames, WTAP_FILE_PCAP, FALSE, &err);
-
-  if(!merge_ok) {
-    /* merge failed */
-    simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-                 "An error occurred while merging the files: \"%s\".",
-                 wtap_strerror(err));
-    close(out_fd);
-    return;
-  }
+    merge_ok = cf_merge_files(tmpname, out_fd, in_file_count, in_filenames,
+                              WTAP_FILE_PCAP, FALSE);
 
-  cf_close(&cfile);
+    if (!merge_ok) {
+        /* merge failed */
+       close(out_fd);  /* XXX - isn't it already closed? */
+       return;
+    }
 
-  /* Try to open the merged capture file. */
-  if ((err = cf_open(tmpname, TRUE /* temporary file */, &cfile)) != 0) {
-    /* We couldn't open it; don't dismiss the open dialog box,
-       just leave it around so that the user can, after they
-       dismiss the alert box popped up for the open error,
-       try again. */
-    return;
-  }
+    cf_close(&cfile);
 
-  switch (cf_read(&cfile)) {
+    /* Try to open the merged capture file. */
+    if ((err = cf_open(tmpname, TRUE /* temporary file */, &cfile)) != 0) {
+       /* We couldn't open it; don't dismiss the open dialog box,
+          just leave it around so that the user can, after they
+          dismiss the alert box popped up for the open error,
+          try again. */
+       return;
+    }
 
-  case READ_SUCCESS:
-  case READ_ERROR:
-    /* Just because we got an error, that doesn't mean we were unable
-       to read any of the file; we handle what we could get from the
-       file. */
-    break;
+    switch (cf_read(&cfile)) {
 
-  case READ_ABORTED:
-    /* The user bailed out of re-reading the capture file; the
-       capture file has been closed - just free the capture file name
-       string and return (without changing the last containing
-       directory). */
-    return;
-  }
+    case READ_SUCCESS:
+    case READ_ERROR:
+       /* Just because we got an error, that doesn't mean we were unable
+          to read any of the file; we handle what we could get from the
+          file. */
+       break;
+
+    case READ_ABORTED:
+       /* The user bailed out of re-reading the capture file; the
+          capture file has been closed - just free the capture file name
+          string and return (without changing the last containing
+          directory). */
+       return;
+    }
 
-  gtk_widget_grab_focus(packet_list);
+    gtk_widget_grab_focus(packet_list);
 }
 
 /* open/merge the dnd file */
 void
 dnd_open_file_cmd(GtkSelectionData *selection_data)
 {
-       int       err;
+    int       err;
     gchar     *cf_name, *cf_name_freeme;
     int       in_files;
     gpointer  dialog;
diff --git a/merge.c b/merge.c
index e71f1c42d65978e36d789f46e151e24c66ea3ba9..c1dfe0e4a4b292eb33c890cf90cd788837f986f0 100644 (file)
--- a/merge.c
+++ b/merge.c
@@ -183,7 +183,7 @@ merge_files(int count, merge_in_file_t in_files[], merge_out_file_t *out_file, i
      * input file
      */
     if(!write_frame(in_files[i].wth, out_file, err))
-                return FALSE;
+        return FALSE;
     in_files[i].ok = wtap_read(in_files[i].wth, &(in_files[i].err),
                                &(in_files[i].err_info),
                                &(in_files[i].data_offset));
@@ -242,15 +242,16 @@ merge_select_frame_type(int count, merge_in_file_t files[])
 /*
  * Close the output file
  */
-void
-merge_close_outfile(merge_out_file_t *out_file)
+gboolean
+merge_close_outfile(merge_out_file_t *out_file, int *err)
 {
-  int err;
-  if (!wtap_dump_close(out_file->pdh, &err)) {
+  if (!wtap_dump_close(out_file->pdh, err)) {
     if (merge_verbose == VERBOSE_ERRORS)
         fprintf(stderr, "mergecap: Error closing output file: %s\n",
-            wtap_strerror(err));
+            wtap_strerror(*err));
+    return FALSE;
   }
+  return TRUE;
 }
 
 
@@ -260,7 +261,8 @@ merge_close_outfile(merge_out_file_t *out_file)
  * Return FALSE if file cannot be opened (so caller can clean up)
  */
 gboolean
-merge_open_outfile(merge_out_file_t *out_file, int snapshot_len, int *err)
+merge_open_outfile(merge_out_file_t *out_file, int fd, int file_type,
+                   int frame_type, int snapshot_len, int *err)
 {
 
   if (!out_file) {
@@ -269,9 +271,8 @@ merge_open_outfile(merge_out_file_t *out_file, int snapshot_len, int *err)
     return FALSE;
   }
 
-
-  out_file->pdh = wtap_dump_fdopen(out_file->fd, out_file->file_type,
-                                 out_file->frame_type, snapshot_len, err);
+  out_file->pdh = wtap_dump_fdopen(fd, file_type, frame_type, snapshot_len,
+                                   err);
   if (!out_file->pdh) {
     if (merge_verbose == VERBOSE_ERRORS) {
         fprintf(stderr, "mergecap: Can't open/create output file:\n");
@@ -279,6 +280,9 @@ merge_open_outfile(merge_out_file_t *out_file, int snapshot_len, int *err)
     }
     return FALSE;
   }
+
+  out_file->snaplen = snapshot_len;
+  out_file->count = 1;
   return TRUE;
 }
 
@@ -323,26 +327,26 @@ merge_close_in_files(int count, merge_in_file_t in_files[])
  * Scan through the arguments and open the input files
  */
 int
-merge_open_in_files(int in_file_count, char *in_file_names[], merge_in_file_t *in_files[], int *err)
+merge_open_in_files(int in_file_count, char *const *in_file_names,
+                    merge_in_file_t **in_files, int *err, gchar **err_info,
+                    int *err_fileno)
 {
   int i;
   int count = 0;
-  gchar *err_info;
   int files_size = in_file_count * sizeof(merge_in_file_t);
   merge_in_file_t *files;
 
-
   files = g_malloc(files_size);
   *in_files = files;
 
   for (i = 0; i < in_file_count; i++) {
     files[count].filename    = in_file_names[i];
-    files[count].wth         = wtap_open_offline(in_file_names[i], err, &err_info, FALSE);
+    files[count].wth         = wtap_open_offline(in_file_names[i], err, err_info, FALSE);
     files[count].err         = 0;
     files[count].data_offset = 0;
     files[count].ok          = TRUE;
     if (!files[count].wth) {
-      if (merge_verbose == VERBOSE_ERRORS) {
+      if (merge_verbose >= VERBOSE_ERRORS) {
         fprintf(stderr, "mergecap: skipping %s: %s\n", in_file_names[i],
               wtap_strerror(*err));
         switch (*err) {
@@ -350,10 +354,17 @@ merge_open_in_files(int in_file_count, char *in_file_names[], merge_in_file_t *i
         case WTAP_ERR_UNSUPPORTED:
         case WTAP_ERR_UNSUPPORTED_ENCAP:
         case WTAP_ERR_BAD_RECORD:
-          fprintf(stderr, "(%s)\n", err_info);
-          g_free(err_info);
+          fprintf(stderr, "(%s)\n", *err_info);
+          g_free(*err_info);
           break;
         }
+      } else {
+        /*
+         * We aren't reporting the errors, so return immediately so our
+         * caller can report the error.
+         */
+        *err_fileno = count;
+        return 0;
       }
     } else {
       if (merge_verbose == VERBOSE_ALL) {
@@ -372,41 +383,34 @@ merge_open_in_files(int in_file_count, char *in_file_names[], merge_in_file_t *i
 
 
 /*
- * Convenience function: merge two files into one.
+ * Convenience function: merge two or more files into one.
  */
-gboolean
-merge_n_files(int out_fd, int in_file_count, char **in_filenames, int filetype, gboolean do_append, int *err)
+merge_status_e
+merge_n_files(int out_fd, int in_file_count, char *const *in_filenames,
+              int file_type, gboolean do_append, int *err, gchar **err_info,
+              int *err_fileno)
 {
-  extern char *optarg;
-  extern int   optind;
-  merge_in_file_t   *in_files      = NULL;
-  merge_out_file_t   out_file;
-  gboolean     ret;
-
-  /* initialize out_file */
-  out_file.fd         = out_fd;
-  out_file.pdh        = NULL;              /* wiretap dumpfile */
-  out_file.file_type  = filetype;
-  out_file.frame_type = -2;                /* leave type alone */
-  out_file.snaplen    = 0;                 /* no limit */
-  out_file.count      = 1;                 /* frames output */
+  merge_in_file_t  *in_files      = NULL;
+  merge_out_file_t  out_file;
+  gboolean          ret;
+  int               close_err;
 
   /* open the input files */
-  in_file_count = merge_open_in_files(in_file_count, in_filenames, &in_files, err);
+  in_file_count = merge_open_in_files(in_file_count, in_filenames, &in_files,
+                                      err, err_info, err_fileno);
   if (in_file_count < 2) {
     if (merge_verbose == VERBOSE_ALL)
         fprintf(stderr, "mergecap: Not all input files valid\n");
-    return FALSE;
+    free(in_files);
+    return MERGE_OPEN_INPUT_FAILED;
   }
 
-  /* set the outfile frame type */
-  if (out_file.frame_type == -2)
-    out_file.frame_type = merge_select_frame_type(in_file_count, in_files);
-
-  /* open the outfile */
-  if (!merge_open_outfile(&out_file, merge_max_snapshot_length(in_file_count, in_files), err)) {
+  if (!merge_open_outfile(&out_file, out_fd, file_type,
+      merge_select_frame_type(in_file_count, in_files),
+      merge_max_snapshot_length(in_file_count, in_files), err)) {
     merge_close_in_files(in_file_count, in_files);
-    return FALSE;
+    free(in_files);
+    return MERGE_OPEN_OUTPUT_FAILED;
   }
 
   /* do the merge (or append) */
@@ -416,9 +420,12 @@ merge_n_files(int out_fd, int in_file_count, char **in_filenames, int filetype,
     ret = merge_files(in_file_count, in_files, &out_file, err);
 
   merge_close_in_files(in_file_count, in_files);
-  merge_close_outfile(&out_file);
+  if (ret)
+      ret = merge_close_outfile(&out_file, err);
+  else
+      merge_close_outfile(&out_file, &close_err);
 
   free(in_files);
 
-  return ret;
+  return ret ? MERGE_SUCCESS : MERGE_WRITE_FAILED;
 }
diff --git a/merge.h b/merge.h
index def3afb4db3b6ecc37f9854be795b8688b3b19c1..81dff56169afd5a4a9e655848e1630d62219d238 100644 (file)
--- a/merge.h
+++ b/merge.h
@@ -1,6 +1,5 @@
 /* merge.h
- * Definitions for menu routines with toolkit-independent APIs but
- * toolkit-dependent implementations.
+ * Definitions for routines for merging files.
  *
  * $Id$
  *
@@ -46,10 +45,7 @@ typedef struct merge_in_file_s {
  * Structures to manage our output file.
  */
 typedef struct merge_out_file_s {
-  int          fd;
   wtap_dumper *pdh;
-  int          file_type;
-  int          frame_type;
   unsigned int snaplen;
   int          count;
 } merge_out_file_t;
@@ -69,11 +65,15 @@ extern int merge_verbose;
  * @param in_file_count number of entries in in_file_names and in_files
  * @param in_file_names filenames of the input files
  * @param in_files input file array to be filled (>= sizeof(merge_in_file_t) * in_file_count)
- * @param err wiretap error, if failed
+ * @param err wiretap error, if failed and VERBOSE_NONE
+ * @param err_info wiretap error string, if failed and VERBOSE_NONE
+ * @param err_fileno file on which open failed, if VERBOSE_NONE
  * @return number of opened input files
  */
 extern int
-merge_open_in_files(int in_file_count, char *in_file_names[], merge_in_file_t *in_files[], int *err);
+merge_open_in_files(int in_file_count, char *const *in_file_names,
+                    merge_in_file_t **in_files, int *err, gchar **err_info,
+                    int *err_fileno);
 
 /** Close the input files again.
  * 
@@ -85,20 +85,26 @@ merge_close_in_files(int in_file_count, merge_in_file_t in_files[]);
 
 /** Open the output file.
  * 
- * @param out_file the prefilled output file array
+ * @param out_file the output file array, which we fill in
+ * @param fd the file descriptor to use for the output file
+ * @param file_type the file type to write
+ * @param frame_type the frame type to write
  * @param snapshot_len the snapshot length of the output file
  * @param err wiretap error, if failed
  * @return TRUE, if the output file could be opened
  */
 extern gboolean
-merge_open_outfile(merge_out_file_t *out_file, int snapshot_len, int *err);
+merge_open_outfile(merge_out_file_t *out_file, int fd, int file_type,
+                   int frame_type, int snapshot_len, int *err);
 
 /** Close the output file again.
  * 
  * @param out_file the output file array
+ * @param err wiretap error, if failed
+ * @return TRUE if the close succeeded, FALSE otherwise
  */
-extern void
-merge_close_outfile(merge_out_file_t *out_file);
+extern gboolean
+merge_close_outfile(merge_out_file_t *out_file, int *err);
 
 /** Try to get the frame type from the input files.
  * 
@@ -124,7 +130,7 @@ merge_max_snapshot_length(int in_file_count, merge_in_file_t in_files[]);
  * @param in_files input file array
  * @param out_file the output file array
  * @param err wiretap error, if failed
- * @return TRUE if function succeeded
+ * @return TRUE on success or read failure, FALSE on write failure
  */
 extern gboolean
 merge_files(int in_file_count, merge_in_file_t in_files[], merge_out_file_t *out_file, int *err);
@@ -135,11 +141,18 @@ merge_files(int in_file_count, merge_in_file_t in_files[], merge_out_file_t *out
  * @param in_files input file array
  * @param out_file the output file array
  * @param err wiretap error, if failed
- * @return TRUE if function succeeded
+ * @return TRUE on success or read failure, FALSE on write failure
  */
 extern gboolean
 merge_append_files(int in_file_count, merge_in_file_t in_files[], merge_out_file_t *out_file, int *err);
 
+/** Return status from merge_n_files */
+typedef enum {
+    MERGE_SUCCESS,
+    MERGE_OPEN_INPUT_FAILED,
+    MERGE_OPEN_OUTPUT_FAILED,
+    MERGE_WRITE_FAILED
+} merge_status_e;
 
 /*
  * Convenience function: merge any number of input files into one.
@@ -148,11 +161,15 @@ merge_append_files(int in_file_count, merge_in_file_t in_files[], merge_out_file
  * @param in_file_count number of input files
  * @param in_filenames array of input filenames
  * @param do_append TRUE to append, FALSE to merge chronologically
- * @param err wiretap error, if failed
- * @return TRUE if function succeeded
+ * @param err wiretap error, if failed and VERBOSE_NONE
+ * @param err_info wiretap error string, if failed and VERBOSE_NONE
+ * @param err_fileno file on which open failed, if VERBOSE_NONE
+ * @return merge_status_e
  */
-extern gboolean
-merge_n_files(int out_fd, int in_file_count, char **in_filenames, int filetype, gboolean do_append, int *err);
+extern merge_status_e
+merge_n_files(int out_fd, int in_file_count, char *const *in_filenames,
+              int filetype, gboolean do_append, int *err, gchar **err_info,
+              int *err_fileno);
 
 
 #ifdef __cplusplus
index 047979b46ba381971b8c8922fd6e5419aa85c8b6..05a3a159e2b523c40a0155861751c6fac493c6e8 100644 (file)
 #define O_BINARY       0
 #endif
 
+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, "mergecap: The specified %s \"%s\" is not a decimal number\n",
+           name, string);
+    exit(1);
+  }
+  if (number < 0) {
+    fprintf(stderr, "mergecap: The specified %s is a negative number\n",
+           name);
+    exit(1);
+  }
+  if (number > INT_MAX) {
+    fprintf(stderr, "mergecap: 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, "mergecap: The specified %s is zero\n",
+           name);
+    exit(1);
+  }
+
+  return number;
+}
+
 /*
  * Show the usage
  */
@@ -89,22 +130,19 @@ main(int argc, char *argv[])
   extern char *optarg;
   extern int   optind;
   int          opt;
-  char        *p;
   gboolean     do_append     = FALSE;
   int          in_file_count = 0;
+  int          snaplen = 0;
+  int          file_type = WTAP_FILE_PCAP;     /* default to libpcap format */
+  int          frame_type = -2;
+  int          out_fd;
   merge_in_file_t   *in_files      = NULL;
   merge_out_file_t   out_file;
   int          err;
+  gchar       *err_info;
+  int          err_fileno;
   char        *out_filename = NULL;
 
-  /* initialize out_file */
-  out_file.fd         = 0;
-  out_file.pdh        = NULL;              /* wiretap dumpfile */
-  out_file.file_type  = WTAP_FILE_PCAP;    /* default to "libpcap" */
-  out_file.frame_type = -2;                /* leave type alone */
-  out_file.snaplen    = 0;                 /* no limit */
-  out_file.count      = 1;                 /* frames output */
-
   merge_verbose = VERBOSE_ERRORS;
 
   /* Process the options first */
@@ -120,8 +158,8 @@ main(int argc, char *argv[])
       break;
 
     case 'T':
-      out_file.frame_type = wtap_short_string_to_encap(optarg);
-      if (out_file.frame_type < 0) {
+      frame_type = wtap_short_string_to_encap(optarg);
+      if (frame_type < 0) {
        fprintf(stderr, "mergecap: \"%s\" is not a valid encapsulation type\n",
            optarg);
        exit(1);
@@ -129,8 +167,8 @@ main(int argc, char *argv[])
       break;
 
     case 'F':
-      out_file.file_type = wtap_short_string_to_file_type(optarg);
-      if (out_file.file_type < 0) {
+      file_type = wtap_short_string_to_file_type(optarg);
+      if (file_type < 0) {
        fprintf(stderr, "mergecap: \"%s\" is not a valid capture file type\n",
            optarg);
        exit(1);
@@ -142,12 +180,7 @@ main(int argc, char *argv[])
       break;
 
     case 's':
-      out_file.snaplen = strtol(optarg, &p, 10);
-      if (p == optarg || *p != '\0') {
-       fprintf(stderr, "mergecap: \"%s\" is not a valid snapshot length\n",
-           optarg);
-       exit(1);
-      }
+      snaplen = get_positive_int(optarg, "snapshot length");
       break;
 
     case 'h':
@@ -184,32 +217,46 @@ main(int argc, char *argv[])
   }
 
   /* open the input files */
-  in_file_count = merge_open_in_files(in_file_count, &argv[optind], &in_files, &err);
+  in_file_count = merge_open_in_files(in_file_count, &argv[optind], &in_files,
+                                      &err, &err_info, &err_fileno);
   if (in_file_count < 1) {
     fprintf(stderr, "mergecap: No valid input files\n");
     exit(1);
   }
 
+  if (snaplen == 0) {
+    /*
+     * Snapshot length not specified - default to the maximum of the
+     * snapshot lengths of the input files.
+     */
+    snaplen = merge_max_snapshot_length(in_file_count, in_files);
+  }
+
   /* set the outfile frame type */
-  if (out_file.frame_type == -2)
-    out_file.frame_type = merge_select_frame_type(in_file_count, in_files);
+  if (frame_type == -2) {
+    /*
+     * Default to the appropriate frame type for the input files.
+     */
+    frame_type = merge_select_frame_type(in_file_count, in_files);
+  }
 
   /* open the outfile */
   if (strncmp(out_filename, "-", 2) == 0) {  
     /* use stdout as the outfile */
-    out_file.fd = 1 /*stdout*/;
+    out_fd = 1 /*stdout*/;
   } else {
     /* open the outfile */
-    out_file.fd = open(out_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
-  }
-  if (out_file.fd == -1) {
-    fprintf(stderr, "mergecap: Couldn't open output file %s: %s\n",
-            out_filename, strerror(errno));
-    exit(1);
+    out_fd = open(out_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+    if (out_fd == -1) {
+      fprintf(stderr, "mergecap: Couldn't open output file %s: %s\n",
+              out_filename, strerror(errno));
+      exit(1);
+    }
   }  
     
   /* prepare the outfile */
-  if (!merge_open_outfile(&out_file, merge_max_snapshot_length(in_file_count, in_files), &err)) {
+  if (!merge_open_outfile(&out_file, out_fd, file_type, frame_type, snaplen,
+                          &err)) {
     merge_close_in_files(in_file_count, in_files);
     exit(1);
   }
@@ -221,7 +268,7 @@ main(int argc, char *argv[])
     merge_files(in_file_count, in_files, &out_file, &err);
 
   merge_close_in_files(in_file_count, in_files);
-  merge_close_outfile(&out_file);
+  merge_close_outfile(&out_file, &err);
 
   free(in_files);