Make the "human-readable text vs. PSML vs. PDML" choice separate from
authorguy <guy@f5534014-38df-0310-8fa8-9805f1628bb7>
Thu, 8 Jul 2004 10:36:29 +0000 (10:36 +0000)
committerguy <guy@f5534014-38df-0310-8fa8-9805f1628bb7>
Thu, 8 Jul 2004 10:36:29 +0000 (10:36 +0000)
the "text vs.  PostScript" choice.  The "text vs. PostScript" choice
should probably ultimately be done with a generic set of print methods,
to handle various platform-native print mechanisms more cleanly (and
perhaps the dialog box code for "export as {PDML,PSML}" should be
separate from the "export as text"/"print" dialog).

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@11342 f5534014-38df-0310-8fa8-9805f1628bb7

file.c
file.h
gtk/print_dlg.c
print.c
print.h
tethereal.c

diff --git a/file.c b/file.c
index c7a0708df8c945eb55d80b536722ef80b3c26e2f..2de8633f7fc564c11215ffbb1760242c68d18c84 100644 (file)
--- a/file.c
+++ b/file.c
@@ -1,7 +1,7 @@
 /* file.c
  * File I/O routines
  *
- * $Id: file.c,v 1.387 2004/07/08 07:45:46 guy Exp $
+ * $Id: file.c,v 1.388 2004/07/08 10:36:26 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -1519,11 +1519,13 @@ print_packet(capture_file *cf, frame_data *fdata,
   int             cp_off;
   gboolean        proto_tree_needed;
 
+  /* Create the protocol tree if we're printing the dissection or the hex
+     data. */
   proto_tree_needed = 
       args->print_args->print_dissections != print_dissections_none || args->print_args->print_hex;
 
-  /* Fill in the column information, but don't bother creating
-     the logical protocol tree. */
+  /* Fill in the column information.
+     XXX - do we need to do so if we're not printing it? */
   edt = epan_dissect_new(proto_tree_needed, proto_tree_needed);
   epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
   epan_dissect_fill_in_columns(edt);
@@ -1751,11 +1753,152 @@ print_packets(capture_file *cf, print_args_t *print_args)
     return PP_WRITE_ERROR;
   }
 
+  /* XXX - check for an error */
   close_print_dest(print_args->to_file, callback_args.print_fh);
 
   return PP_OK;
 }
 
+static gboolean
+write_pdml_packet(capture_file *cf _U_, frame_data *fdata,
+                  union wtap_pseudo_header *pseudo_header, const guint8 *pd,
+                 void *argsp)
+{
+  FILE *fh = argsp;
+  epan_dissect_t *edt;
+
+  /* Create the protocol tree, but don't fill in the column information. */
+  edt = epan_dissect_new(TRUE, TRUE);
+  epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
+
+  /* Write out the information in that tree. */
+  proto_tree_write_pdml(edt, fh);
+
+  epan_dissect_free(edt);
+
+  return !ferror(fh);
+}
+
+pp_return_t
+write_pdml_packets(capture_file *cf, print_args_t *print_args)
+{
+  FILE        *fh;
+  psp_return_t ret;
+
+  fh = fopen(print_args->file, "w");
+  if (fh == NULL)
+    return PP_OPEN_ERROR;      /* attempt to open destination failed */
+
+  write_pdml_preamble(fh);
+  if (ferror(fh)) {
+    fclose(fh);
+    return PP_WRITE_ERROR;
+  }
+
+  /* Iterate through the list of packets, printing the packets we were
+     told to print. */
+  ret = process_specified_packets(cf, &print_args->range, "Writing PDML",
+                                  "selected packets", write_pdml_packet,
+                                  fh);
+
+  switch (ret) {
+
+  case PSP_FINISHED:
+    /* Completed successfully. */
+    break;
+
+  case PSP_STOPPED:
+    /* Well, the user decided to abort the printing. */
+    break;
+
+  case PSP_FAILED:
+    /* Error while printing. */
+    fclose(fh);
+    return PP_WRITE_ERROR;
+  }
+
+  write_pdml_finale(fh);
+  if (ferror(fh)) {
+    fclose(fh);
+    return PP_WRITE_ERROR;
+  }
+
+  /* XXX - check for an error */
+  fclose(fh);
+
+  return PP_OK;
+}
+
+static gboolean
+write_psml_packet(capture_file *cf, frame_data *fdata,
+                  union wtap_pseudo_header *pseudo_header, const guint8 *pd,
+                 void *argsp)
+{
+  FILE *fh = argsp;
+  epan_dissect_t *edt;
+
+  /* Fill in the column information, but don't create the protocol tree. */
+  edt = epan_dissect_new(FALSE, FALSE);
+  epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
+
+  /* Write out the information in that tree. */
+  proto_tree_write_psml(edt, fh);
+
+  epan_dissect_free(edt);
+
+  return !ferror(fh);
+}
+
+pp_return_t
+write_psml_packets(capture_file *cf, print_args_t *print_args)
+{
+  FILE        *fh;
+  psp_return_t ret;
+
+  fh = fopen(print_args->file, "w");
+  if (fh == NULL)
+    return PP_OPEN_ERROR;      /* attempt to open destination failed */
+
+  write_psml_preamble(fh);
+  if (ferror(fh)) {
+    fclose(fh);
+    return PP_WRITE_ERROR;
+  }
+
+  /* Iterate through the list of packets, printing the packets we were
+     told to print. */
+  ret = process_specified_packets(cf, &print_args->range, "Writing PSML",
+                                  "selected packets", write_psml_packet,
+                                  fh);
+
+  switch (ret) {
+
+  case PSP_FINISHED:
+    /* Completed successfully. */
+    break;
+
+  case PSP_STOPPED:
+    /* Well, the user decided to abort the printing. */
+    break;
+
+  case PSP_FAILED:
+    /* Error while printing. */
+    fclose(fh);
+    return PP_WRITE_ERROR;
+  }
+
+  write_psml_finale(fh);
+  if (ferror(fh)) {
+    fclose(fh);
+    return PP_WRITE_ERROR;
+  }
+
+  /* XXX - check for an error */
+  fclose(fh);
+
+  return PP_OK;
+}
+
 /* Scan through the packet list and change all columns that use the
    "command-line-specified" time stamp format to use the current
    value of that format. */
diff --git a/file.h b/file.h
index 677aa25946650ce2e142c78e65692fc6d27d04d6..f7743a84a109fcac3da1ce03df8432be1312ad42 100644 (file)
--- a/file.h
+++ b/file.h
@@ -1,7 +1,7 @@
 /* file.h
  * Definitions for file structures and routines
  *
- * $Id: file.h,v 1.118 2004/03/08 23:45:25 guy Exp $
+ * $Id: file.h,v 1.119 2004/07/08 10:36:26 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -63,6 +63,9 @@ typedef enum {
        PP_WRITE_ERROR
 } pp_return_t;
 pp_return_t print_packets(capture_file *cf, print_args_t *print_args);
+pp_return_t write_pdml_packets(capture_file *cf, print_args_t *print_args);
+pp_return_t write_psml_packets(capture_file *cf, print_args_t *print_args);
+
 void change_time_formats(capture_file *);
 
 gboolean find_packet_protocol_tree(capture_file *cf, const char *string);
index 3e5963ca3c8bce1dd67eff6fc37ee75ab0e7d125..c37b2c2cf81514a356ea6df1c67dc7085550a702 100644 (file)
@@ -1,7 +1,7 @@
 /* print_dlg.c
- * Dialog boxes for printing
+ * Dialog boxes for printing and exporting to text files
  *
- * $Id: print_dlg.c,v 1.80 2004/06/29 03:27:52 jmayer Exp $
+ * $Id: print_dlg.c,v 1.81 2004/07/08 10:36:29 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -256,7 +256,7 @@ export_psml_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
   /* get settings from preferences (and other initial values) only once */
   if(export_psml_prefs_init == FALSE) {
       export_psml_prefs_init    = TRUE;
-      args->format              = PR_FMT_PSML;
+      args->format              = PR_FMT_TEXT; /* XXX */
       args->to_file             = TRUE;
       args->file                = g_strdup("");
       args->cmd                 = g_strdup("");
@@ -300,7 +300,7 @@ export_pdml_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
   /* get settings from preferences (and other initial values) only once */
   if(export_pdml_prefs_init == FALSE) {
       export_pdml_prefs_init    = TRUE;
-      args->format              = PR_FMT_PDML;
+      args->format              = PR_FMT_TEXT; /* XXX */
       args->to_file             = TRUE;
       args->file                = g_strdup("");
       args->cmd                 = g_strdup("");
@@ -412,7 +412,7 @@ open_print_dialog(char *title, output_action_e action, print_args_t *args)
     gtk_widget_show(ps_rb);
 
   pdml_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(text_rb, "PDM_L (XML: Packet Details Markup Language)", accel_group);
-  if (args->format == PR_FMT_PDML)
+  if (action == output_action_export_pdml)
     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(pdml_rb), TRUE);
   gtk_tooltips_set_tip (tooltips, pdml_rb,
       "Print output in \"PDML\" (Packet Details Markup Language), "
@@ -422,7 +422,7 @@ open_print_dialog(char *title, output_action_e action, print_args_t *args)
   /* gtk_widget_show(pdml_rb); */
 
   psml_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(text_rb, "PSML (XML: Packet Summary Markup Language)", accel_group);
-  if (args->format == PR_FMT_PSML)
+  if (action == output_action_export_psml)
     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(psml_rb), TRUE);
   gtk_tooltips_set_tip (tooltips, psml_rb,
       "Print output in \"PSML\" (Packet Summary Markup Language), "
@@ -739,9 +739,11 @@ print_ok_cb(GtkWidget *ok_bt, gpointer parent_w)
   const gchar   *g_dest;
   gchar         *f_name;
   gchar         *dirname;
+  gboolean      export_as_pdml = FALSE, export_as_psml = FALSE;
 #ifdef _WIN32
   gboolean win_printer = FALSE;
 #endif
+  pp_return_t   status;
 
   args = (print_args_t *)OBJECT_GET_DATA(ok_bt, PRINT_ARGS_KEY);
 
@@ -783,10 +785,10 @@ print_ok_cb(GtkWidget *ok_bt, gpointer parent_w)
     args->format = PR_FMT_PS;
   button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_PDML_RB_KEY);
   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button)))
-    args->format = PR_FMT_PDML;
+    export_as_pdml = TRUE;
   button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_PSML_RB_KEY);
   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button)))
-    args->format = PR_FMT_PSML;
+    export_as_psml = TRUE;
 
   button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_SUMMARY_CB_KEY);
   args->print_summary = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button));
@@ -819,8 +821,14 @@ print_ok_cb(GtkWidget *ok_bt, gpointer parent_w)
 
   window_destroy(GTK_WIDGET(parent_w));
 
-  /* Now print the packets */
-  switch (print_packets(&cfile, args)) {
+  /* Now print/export the packets */
+  if (export_as_pdml)
+    status = write_pdml_packets(&cfile, args);
+  else if (export_as_psml)
+    status = write_psml_packets(&cfile, args);
+  else
+    status = print_packets(&cfile, args);
+  switch (status) {
 
   case PP_OK:
     break;
@@ -869,7 +877,3 @@ print_destroy_cb(GtkWidget *win, gpointer user_data)
   /* Note that we no longer have a "Print" dialog box. */
   *((gpointer *) user_data) = NULL;
 }
-
-
-
-
diff --git a/print.c b/print.c
index adc4c1ea53dc54ce3eef295a904a271066bb433c..159989d7f733119642ce6355b69c3a60a27256c0 100644 (file)
--- a/print.c
+++ b/print.c
@@ -1,7 +1,7 @@
 /* print.c
  * Routines for printing packet analysis trees.
  *
- * $Id: print.c,v 1.83 2004/07/05 16:39:20 ulfl Exp $
+ * $Id: print.c,v 1.84 2004/07/08 10:36:27 guy Exp $
  *
  * Gilbert Ramirez <gram@alumni.rice.edu>
  *
 #define PDML_VERSION "0"
 #define PSML_VERSION "0"
 
+typedef struct {
+       int                     level;
+       FILE                    *fh;
+       GSList                  *src_list;
+       print_dissections_e     print_dissections;
+       gboolean                print_hex_for_data;
+       char_enc                encoding;
+       gint                    format;
+       epan_dissect_t          *edt;
+} print_data;
+
+typedef struct {
+       int                     level;
+       FILE                    *fh;
+       GSList                  *src_list;
+       epan_dissect_t          *edt;
+} write_pdml_data;
+
 static void proto_tree_print_node(proto_node *node, gpointer data);
-static void proto_tree_print_node_pdml(proto_node *node, gpointer data);
+static void proto_tree_write_node_pdml(proto_node *node, gpointer data);
+static const guint8 *get_field_data(GSList *src_list, field_info *fi);
+static void write_pdml_field_hex_value(write_pdml_data *pdata, field_info *fi);
 static void print_hex_data_buffer(FILE *fh, register const guchar *cp,
     register guint length, char_enc encoding, print_format_e format);
 static void ps_clean_string(unsigned char *out, const unsigned char *in,
                        int outbuf_size);
 static void print_escaped_xml(FILE *fh, char *unescaped_string);
 
-typedef struct {
-       int                         level;
-       FILE                    *fh;
-       GSList                  *src_list;
-       print_dissections_e print_dissections;
-       gboolean                print_hex_for_data;
-       char_enc                encoding;
-       gint                    format;
-       epan_dissect_t      *edt;
-} print_data;
-
-static void print_pdml_geninfo(proto_tree *tree, print_data *pdata);
+static void print_pdml_geninfo(proto_tree *tree, FILE *fh);
 
 FILE *open_print_dest(int to_file, const char *dest)
 {
@@ -89,13 +98,43 @@ gboolean close_print_dest(int to_file, FILE *fh)
                return (pclose(fh) == 0);
 }
 
+#define MAX_PS_LINE_LENGTH 256
+
+/* Some formats need stuff at the beginning of the output */
+void
+print_preamble(FILE *fh, print_format_e format, gchar *filename)
+{
+       char            psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
+
+    
+       switch (format) {
+
+       case(PR_FMT_TEXT):
+               /* do nothing */
+               break;
+
+       case(PR_FMT_PS):
+               print_ps_preamble(fh);
+
+               fputs("%% Set the font to 10 point\n", fh);
+               fputs("/Courier findfont 10 scalefont setfont\n", fh);
+               fputs("\n", fh);
+               fputs("%% the page title\n", fh);
+               ps_clean_string(psbuffer, filename, MAX_PS_LINE_LENGTH);
+               fprintf(fh, "/eth_pagetitle (%s - Ethereal) def\n", psbuffer);
+               fputs("\n", fh);
+               break;
+
+       default:
+               g_assert_not_reached();
+       }
+}
 
 void
 proto_tree_print(print_args_t *print_args, epan_dissect_t *edt,
     FILE *fh)
 {
        print_data data;
-       gint    i;
 
        /* Create the output */
        data.level = 0;
@@ -103,101 +142,17 @@ proto_tree_print(print_args_t *print_args, epan_dissect_t *edt,
        data.src_list = edt->pi.data_src;
        data.encoding = edt->pi.fd->flags.encoding;
        data.print_dissections = print_args->print_dissections;
+       /* If we're printing the entire packet in hex, don't
+          print uninterpreted data fields in hex as well. */
        data.print_hex_for_data = !print_args->print_hex;
-           /* If we're printing the entire packet in hex, don't
-              print uninterpreted data fields in hex as well. */
        data.format = print_args->format;
        data.edt = edt;
 
-    switch(data.format) {
-    case(PR_FMT_TEXT):  /* fall through */
-    case(PR_FMT_PS):
-               proto_tree_children_foreach(edt->tree, proto_tree_print_node, &data);
-        break;
-    case(PR_FMT_PDML):
-               fprintf(fh, "<packet>\n");
-
-               /* Print a "geninfo" protocol as required by PDML */
-               print_pdml_geninfo(edt->tree, &data);
-
-               proto_tree_children_foreach(edt->tree, proto_tree_print_node_pdml, &data);
-
-               fprintf(fh, "</packet>\n\n");
-        break;
-    case(PR_FMT_PSML):
-        /* if this is the first packet, we have to create the PSML structure output */
-        if(edt->pi.fd->num == 1) {
-            fprintf(fh, "<structure>\n");
-
-            for(i=0; i < edt->pi.cinfo->num_cols; i++) {
-                fprintf(fh, "<section>");
-                print_escaped_xml(fh, edt->pi.cinfo->col_title[i]);
-                fprintf(fh, "</section>\n");
-            }
-
-            fprintf(fh, "</structure>\n\n");
-        }
-
-               fprintf(fh, "<packet>\n");
-
-        for(i=0; i < edt->pi.cinfo->num_cols; i++) {
-            fprintf(fh, "<section>");
-            print_escaped_xml(fh, edt->pi.cinfo->col_data[i]);
-            fprintf(fh, "</section>\n");
-        }
-
-               fprintf(fh, "</packet>\n\n");
-        break;
-    default:
-        g_assert_not_reached();
-       }
-}
-
-/*
- * Find the data source for a specified field, and return a pointer
- * to the data in it. Returns NULL if the data is out of bounds.
- */
-static const guint8 *
-get_field_data(GSList *src_list, field_info *fi)
-{
-       GSList *src_le;
-       data_source *src;
-       tvbuff_t *src_tvb;
-       gint length, tvbuff_length;
-
-       for (src_le = src_list; src_le != NULL; src_le = src_le->next) {
-               src = src_le->data;
-               src_tvb = src->tvb;
-               if (fi->ds_tvb == src_tvb) {
-                       /*
-                        * Found it.
-                        *
-                        * XXX - a field can have a length that runs past
-                        * the end of the tvbuff.  Ideally, that should
-                        * be fixed when adding an item to the protocol
-                        * tree, but checking the length when doing
-                        * that could be expensive.  Until we fix that,
-                        * we'll do the check here.
-                        */
-                       tvbuff_length = tvb_length_remaining(src_tvb,
-                           fi->start);
-                       if (tvbuff_length < 0) {
-                               return NULL;
-                       }
-                       length = fi->length;
-                       if (length > tvbuff_length)
-                               length = tvbuff_length;
-                       return tvb_get_ptr(src_tvb, fi->start, length);
-               }
-       }
-       g_assert_not_reached();
-       return NULL;    /* not found */
+       proto_tree_children_foreach(edt->tree, proto_tree_print_node, &data);
 }
 
 #define MAX_INDENT     160
 
-#define MAX_PS_LINE_LENGTH 256
-
 /* Print a tree's data, and any child nodes. */
 static
 void proto_tree_print_node(proto_node *node, gpointer data)
@@ -212,7 +167,7 @@ void proto_tree_print_node(proto_node *node, gpointer data)
        if (PROTO_ITEM_IS_HIDDEN(node))
                return;
 
-    /* was a free format label produced? */
+       /* was a free format label produced? */
        if (fi->rep) {
                label_ptr = fi->rep->representation;
        }
@@ -242,7 +197,7 @@ void proto_tree_print_node(proto_node *node, gpointer data)
        g_assert(fi->tree_type >= -1 && fi->tree_type < num_tree_types);
        if (pdata->print_dissections == print_dissections_expanded ||
            (pdata->print_dissections == print_dissections_as_displayed &&
-        fi->tree_type >= 0 && tree_is_expanded[fi->tree_type])) {
+               fi->tree_type >= 0 && tree_is_expanded[fi->tree_type])) {
                if (node->first_child != NULL) {
                        pdata->level++;
                        proto_tree_children_foreach(node,
@@ -252,66 +207,61 @@ void proto_tree_print_node(proto_node *node, gpointer data)
        }
 }
 
-/* Print a string, escaping out certain characters that need to
- * escaped out for XML. */
-static void
-print_escaped_xml(FILE *fh, char *unescaped_string)
+/* Some formats need stuff at the end of the output */
+void
+print_finale(FILE *fh, print_format_e format)
 {
-       unsigned char *p;
+       switch (format) {
 
-       for (p = unescaped_string; *p != '\0'; p++) {
-               switch (*p) {
-                       case '&':
-                               fputs("&amp;", fh);
-                               break;
-                       case '<':
-                               fputs("&lt;", fh);
-                               break;
-                       case '>':
-                               fputs("&gt;", fh);
-                               break;
-                       case '"':
-                               fputs("&quot;", fh);
-                               break;
-                       case '\'':
-                               fputs("&apos;", fh);
-                               break;
-                       default:
-                               fputc(*p, fh);
-               }
+       case(PR_FMT_TEXT):
+               /* do nothing */
+               break;
+
+       case(PR_FMT_PS):
+               print_ps_finale(fh);
+               break;
+
+       default:
+               g_assert_not_reached();
        }
 }
 
-static void
-print_field_hex_value(print_data *pdata, field_info *fi)
+void
+write_pdml_preamble(FILE *fh)
 {
-       int i;
-       const guint8 *pd;
+       fputs("<?xml version=\"1.0\"?>\n", fh);
+       fputs("<pdml version=\"" PDML_VERSION "\" ", fh);
+       fprintf(fh, "creator=\"%s/%s\">\n", PACKAGE, VERSION);
+}
 
+void
+proto_tree_write_pdml(epan_dissect_t *edt, FILE *fh)
+{
+       write_pdml_data data;
 
-    if(fi->length > tvb_length_remaining(fi->ds_tvb, fi->start)) {
-        fprintf(pdata->fh, "field length invalid!");
-        return;
-    }
+       /* Create the output */
+       data.level = 0;
+       data.fh = fh;
+       data.src_list = edt->pi.data_src;
+       data.edt = edt;
 
-       /* Find the data for this field. */
-       pd = get_field_data(pdata->src_list, fi);
+       fprintf(fh, "<packet>\n");
 
-       if (pd) {
-               /* Print a simple hex dump */
-               for (i = 0 ; i < fi->length; i++) {
-                       fprintf(pdata->fh, "%02x", pd[i]);
-               }
-       }
-}
+       /* Print a "geninfo" protocol as required by PDML */
+       print_pdml_geninfo(edt->tree, fh);
 
+       proto_tree_children_foreach(edt->tree, proto_tree_write_node_pdml,
+           &data);
 
-/* Print a tree's data, and any child nodes, as PDML */
+       fprintf(fh, "</packet>\n\n");
+}
+
+/* Write out a tree's data, and any child nodes, as PDML */
 static void
-proto_tree_print_node_pdml(proto_node *node, gpointer data)
+proto_tree_write_node_pdml(proto_node *node, gpointer data)
 {
        field_info      *fi = PITEM_FINFO(node);
-       print_data      *pdata = (print_data*) data;
+       write_pdml_data *pdata = (write_pdml_data*) data;
        gchar           *label_ptr;
        gchar           label_str[ITEM_LABEL_LENGTH];
        char            *dfilter_string;
@@ -339,7 +289,7 @@ proto_tree_print_node_pdml(proto_node *node, gpointer data)
                fprintf(pdata->fh, "\" pos=\"%d", fi->start);
 
                fputs("\" value=\"", pdata->fh);
-               print_field_hex_value(pdata, fi);
+               write_pdml_field_hex_value(pdata, fi);
 
                if (node->first_child != NULL) {
                        fputs("\">\n", pdata->fh);
@@ -354,7 +304,7 @@ proto_tree_print_node_pdml(proto_node *node, gpointer data)
 
                fputs("<field name=\"data\" value=\"", pdata->fh);
 
-               print_field_hex_value(pdata, fi);
+               write_pdml_field_hex_value(pdata, fi);
 
                fputs("\"/>\n", pdata->fh);
 
@@ -370,19 +320,19 @@ proto_tree_print_node_pdml(proto_node *node, gpointer data)
                print_escaped_xml(pdata->fh, fi->hfinfo->abbrev);
 
 #if 0
-        /* PDML spec, see: 
-         * http://analyzer.polito.it/30alpha/docs/dissectors/PDMLSpec.htm
-         *
-         * the show fields contains things in 'human readable' format
-         * showname: contains only the name of the field
-         * show: contains only the data of the field
-         * showdtl: contains additional details of the field data
-         * showmap: contains mappings of the field data (e.g. the hostname to an IP address)
-         *
-         * XXX - the showname shouldn't contain the field data itself 
-         * (like it's contained in the fi->rep->representation). 
-         * Unfortunately, we don't have the field data representation for 
-         * all fields, so this isn't currently possible */
+       /* PDML spec, see: 
+        * http://analyzer.polito.it/30alpha/docs/dissectors/PDMLSpec.htm
+        *
+        * the show fields contains things in 'human readable' format
+        * showname: contains only the name of the field
+        * show: contains only the data of the field
+        * showdtl: contains additional details of the field data
+        * showmap: contains mappings of the field data (e.g. the hostname to an IP address)
+        *
+        * XXX - the showname shouldn't contain the field data itself 
+        * (like it's contained in the fi->rep->representation). 
+        * Unfortunately, we don't have the field data representation for 
+        * all fields, so this isn't currently possible */
                fputs("\" showname=\"", pdata->fh);
                print_escaped_xml(pdata->fh, fi->hfinfo->name);
 #endif
@@ -398,9 +348,8 @@ proto_tree_print_node_pdml(proto_node *node, gpointer data)
                        print_escaped_xml(pdata->fh, label_ptr);
                }
 
-        if(PROTO_ITEM_IS_HIDDEN(node)) {
-               fprintf(pdata->fh, "\" hide=\"yes");
-        }
+               if (PROTO_ITEM_IS_HIDDEN(node))
+                       fprintf(pdata->fh, "\" hide=\"yes");
 
                fprintf(pdata->fh, "\" size=\"%d", fi->length);
                fprintf(pdata->fh, "\" pos=\"%d", fi->start);
@@ -431,7 +380,7 @@ proto_tree_print_node_pdml(proto_node *node, gpointer data)
                        }
                        if (fi->length > 0) {
                                fputs("\" value=\"", pdata->fh);
-                               print_field_hex_value(pdata, fi);
+                               write_pdml_field_hex_value(pdata, fi);
                        }
                }
 
@@ -450,7 +399,7 @@ proto_tree_print_node_pdml(proto_node *node, gpointer data)
        if (node->first_child != NULL) {
                pdata->level++;
                proto_tree_children_foreach(node,
-                               proto_tree_print_node_pdml, pdata);
+                               proto_tree_write_node_pdml, pdata);
                pdata->level--;
        }
 
@@ -472,7 +421,7 @@ proto_tree_print_node_pdml(proto_node *node, gpointer data)
  * but we produce a 'geninfo' protocol in the PDML to conform to spec.
  * The 'frame' protocol follows the 'geninfo' protocol in the PDML. */
 static void
-print_pdml_geninfo(proto_tree *tree, print_data *pdata)
+print_pdml_geninfo(proto_tree *tree, FILE *fh)
 {
        guint32 num, len, caplen;
        nstime_t *timestamp;
@@ -520,35 +469,177 @@ print_pdml_geninfo(proto_tree *tree, print_data *pdata)
        g_ptr_array_free(finfo_array, FALSE);
 
        /* Print geninfo start */
-       fprintf(pdata->fh,
+       fprintf(fh,
 "  <proto name=\"geninfo\" pos=\"0\" showname=\"General information\" size=\"%u\">\n",
                frame_finfo->length);
 
        /* Print geninfo.num */
-       fprintf(pdata->fh,
+       fprintf(fh,
 "    <field name=\"num\" pos=\"0\" show=\"%u\" showname=\"Number\" value=\"%x\" size=\"%u\"/>\n",
                num, num, frame_finfo->length);
 
        /* Print geninfo.len */
-       fprintf(pdata->fh,
+       fprintf(fh,
 "    <field name=\"len\" pos=\"0\" show=\"%u\" showname=\"Packet Length\" value=\"%x\" size=\"%u\"/>\n",
                len, len, frame_finfo->length);
 
        /* Print geninfo.caplen */
-       fprintf(pdata->fh,
+       fprintf(fh,
 "    <field name=\"caplen\" pos=\"0\" show=\"%u\" showname=\"Captured Length\" value=\"%x\" size=\"%u\"/>\n",
                caplen, caplen, frame_finfo->length);
 
        /* Print geninfo.timestamp */
-       fprintf(pdata->fh,
+       fprintf(fh,
 "    <field name=\"timestamp\" pos=\"0\" show=\"%s\" showname=\"Captured Time\" value=\"%d.%09d\" size=\"%u\"/>\n",
                abs_time_to_str(timestamp), (int) timestamp->secs, timestamp->nsecs, frame_finfo->length);
 
        /* Print geninfo end */
-       fprintf(pdata->fh,
+       fprintf(fh,
 "  </proto>\n");
 }
 
+void
+write_pdml_finale(FILE *fh)
+{
+       fputs("</pdml>\n", fh);
+}
+
+void
+write_psml_preamble(FILE *fh)
+{
+       fputs("<?xml version=\"1.0\"?>\n", fh);
+       fputs("<psml version=\"" PSML_VERSION "\" ", fh);
+       fprintf(fh, "creator=\"%s/%s\">\n", PACKAGE, VERSION);
+}
+
+void
+proto_tree_write_psml(epan_dissect_t *edt, FILE *fh)
+{
+       gint    i;
+
+       /* if this is the first packet, we have to create the PSML structure output */
+       if(edt->pi.fd->num == 1) {
+           fprintf(fh, "<structure>\n");
+
+           for(i=0; i < edt->pi.cinfo->num_cols; i++) {
+               fprintf(fh, "<section>");
+               print_escaped_xml(fh, edt->pi.cinfo->col_title[i]);
+               fprintf(fh, "</section>\n");
+           }
+
+           fprintf(fh, "</structure>\n\n");
+       }
+
+       fprintf(fh, "<packet>\n");
+
+       for(i=0; i < edt->pi.cinfo->num_cols; i++) {
+           fprintf(fh, "<section>");
+           print_escaped_xml(fh, edt->pi.cinfo->col_data[i]);
+           fprintf(fh, "</section>\n");
+       }
+
+       fprintf(fh, "</packet>\n\n");
+}
+
+void
+write_psml_finale(FILE *fh)
+{
+       fputs("</psml>\n", fh);
+}
+
+/*
+ * Find the data source for a specified field, and return a pointer
+ * to the data in it. Returns NULL if the data is out of bounds.
+ */
+static const guint8 *
+get_field_data(GSList *src_list, field_info *fi)
+{
+       GSList *src_le;
+       data_source *src;
+       tvbuff_t *src_tvb;
+       gint length, tvbuff_length;
+
+       for (src_le = src_list; src_le != NULL; src_le = src_le->next) {
+               src = src_le->data;
+               src_tvb = src->tvb;
+               if (fi->ds_tvb == src_tvb) {
+                       /*
+                        * Found it.
+                        *
+                        * XXX - a field can have a length that runs past
+                        * the end of the tvbuff.  Ideally, that should
+                        * be fixed when adding an item to the protocol
+                        * tree, but checking the length when doing
+                        * that could be expensive.  Until we fix that,
+                        * we'll do the check here.
+                        */
+                       tvbuff_length = tvb_length_remaining(src_tvb,
+                           fi->start);
+                       if (tvbuff_length < 0) {
+                               return NULL;
+                       }
+                       length = fi->length;
+                       if (length > tvbuff_length)
+                               length = tvbuff_length;
+                       return tvb_get_ptr(src_tvb, fi->start, length);
+               }
+       }
+       g_assert_not_reached();
+       return NULL;    /* not found */
+}
+
+/* Print a string, escaping out certain characters that need to
+ * escaped out for XML. */
+static void
+print_escaped_xml(FILE *fh, char *unescaped_string)
+{
+       unsigned char *p;
+
+       for (p = unescaped_string; *p != '\0'; p++) {
+               switch (*p) {
+                       case '&':
+                               fputs("&amp;", fh);
+                               break;
+                       case '<':
+                               fputs("&lt;", fh);
+                               break;
+                       case '>':
+                               fputs("&gt;", fh);
+                               break;
+                       case '"':
+                               fputs("&quot;", fh);
+                               break;
+                       case '\'':
+                               fputs("&apos;", fh);
+                               break;
+                       default:
+                               fputc(*p, fh);
+               }
+       }
+}
+
+static void
+write_pdml_field_hex_value(write_pdml_data *pdata, field_info *fi)
+{
+       int i;
+       const guint8 *pd;
+
+       if (fi->length > tvb_length_remaining(fi->ds_tvb, fi->start)) {
+               fprintf(pdata->fh, "field length invalid!");
+               return;
+       }
+
+       /* Find the data for this field. */
+       pd = get_field_data(pdata->src_list, fi);
+
+       if (pd) {
+               /* Print a simple hex dump */
+               for (i = 0 ; i < fi->length; i++) {
+                       fprintf(pdata->fh, "%02x", pd[i]);
+               }
+       }
+}
+
 
 void print_hex_data(FILE *fh, print_format_e format, epan_dissect_t *edt)
 {
@@ -718,108 +809,43 @@ void ps_clean_string(unsigned char *out, const unsigned char *in,
        }
 }
 
-/* Some formats need stuff at the beginning of the output */
 void
-print_preamble(FILE *fh, print_format_e format, gchar *filename)
-{
+print_packet_header(FILE *fh, print_format_e format, guint32 number, gchar *summary) {
        char            psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
 
-    
-    switch(format) {
-    case(PR_FMT_TEXT):
-        /* do nothing */
-        break;
-    case(PR_FMT_PS):
-               print_ps_preamble(fh);
+       switch (format) {
 
-               fputs("%% Set the font to 10 point\n", fh);
-               fputs("/Courier findfont 10 scalefont setfont\n", fh);
-               fputs("\n", fh);
-               fputs("%% the page title\n", fh);
-               ps_clean_string(psbuffer, filename, MAX_PS_LINE_LENGTH);
-               fprintf(fh, "/eth_pagetitle (%s - Ethereal) def\n", psbuffer);
-               fputs("\n", fh);
-        break;
-    case(PR_FMT_PDML):
-               fputs("<?xml version=\"1.0\"?>\n", fh);
-               fputs("<pdml version=\"" PDML_VERSION "\" ", fh);
-               fprintf(fh, "creator=\"%s/%s\">\n", PACKAGE, VERSION);
-        break;
-    case(PR_FMT_PSML):
-               fputs("<?xml version=\"1.0\"?>\n", fh);
-               fputs("<psml version=\"" PSML_VERSION "\" ", fh);
-               fprintf(fh, "creator=\"%s/%s\">\n", PACKAGE, VERSION);
-        break;
-    default:
-               g_assert_not_reached();
-       }
-}
+       case(PR_FMT_TEXT):
+               /* do nothing */
+               break;
 
-void
-print_packet_header(FILE *fh, print_format_e format, guint32 number, gchar *summary) {
-       char            psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
-
-    
-    switch(format) {
-    case(PR_FMT_TEXT):
-        /* do nothing */
-        break;
-    case(PR_FMT_PS):
+       case(PR_FMT_PS):
                ps_clean_string(psbuffer, summary, MAX_PS_LINE_LENGTH);
-        fprintf(fh, "[/Dest /__frame%u__ /Title (%s)   /OUT pdfmark\n", number, psbuffer);
-        fputs("[/View [/XYZ -4 currentpoint matrix currentmatrix matrix defaultmatrix\n", fh);
-        fputs("matrix invertmatrix matrix concatmatrix transform exch pop 20 add null]\n", fh);
-        fprintf(fh, "/Dest /__frame%u__ /DEST pdfmark\n", number);
-        break;
-    case(PR_FMT_PDML):
-        /* do nothing */
-        break;
-    case(PR_FMT_PSML):
-        /* do nothing */
-        break;
-    default:
+               fprintf(fh, "[/Dest /__frame%u__ /Title (%s)   /OUT pdfmark\n", number, psbuffer);
+               fputs("[/View [/XYZ -4 currentpoint matrix currentmatrix matrix defaultmatrix\n", fh);
+               fputs("matrix invertmatrix matrix concatmatrix transform exch pop 20 add null]\n", fh);
+               fprintf(fh, "/Dest /__frame%u__ /DEST pdfmark\n", number);
+               break;
+
+       default:
                g_assert_not_reached();
        }
 }
 
 void
-print_formfeed(FILE *fh, print_format_e format) {
-    switch(format) {
-    case(PR_FMT_TEXT):
+print_formfeed(FILE *fh, print_format_e format)
+{
+       switch (format) {
+
+       case(PR_FMT_TEXT):
                fputs("\f", fh);
-        break;
-    case(PR_FMT_PS):
+               break;
+
+       case(PR_FMT_PS):
                fputs("formfeed\n", fh);
-        break;
-    case(PR_FMT_PDML):
-        /* do nothing */
-        break;
-    case(PR_FMT_PSML):
-        /* do nothing */
-        break;
-    default:
-               g_assert_not_reached();
-       }
-}
+               break;
 
-/* Some formats need stuff at the end of the output */
-void
-print_finale(FILE *fh, print_format_e format)
-{
-    switch(format) {
-    case(PR_FMT_TEXT):
-        /* do nothing */
-        break;
-    case(PR_FMT_PS):
-               print_ps_finale(fh);
-        break;
-    case(PR_FMT_PDML):
-               fputs("</pdml>\n", fh);
-        break;
-    case(PR_FMT_PSML):
-               fputs("</psml>\n", fh);
-        break;
-    default:
+       default:
                g_assert_not_reached();
        }
 }
@@ -832,8 +858,9 @@ print_line(FILE *fh, int indent, print_format_e format, char *line)
        int             num_spaces;
        char            psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
 
-    switch(format) {
-    case(PR_FMT_TEXT):
+       switch (format) {
+
+       case(PR_FMT_TEXT):
                /* Prepare the tabs for printing, depending on tree level */
                num_spaces = indent * 4;
                if (num_spaces > MAX_INDENT) {
@@ -848,18 +875,14 @@ print_line(FILE *fh, int indent, print_format_e format, char *line)
                fputs(space, fh);
                fputs(line, fh);
                putc('\n', fh);
-        break;
-    case(PR_FMT_PS):
+               break;
+
+       case(PR_FMT_PS):
                ps_clean_string(psbuffer, line, MAX_PS_LINE_LENGTH);
                fprintf(fh, "%d (%s) putline\n", indent, psbuffer);
-        break;
-    case(PR_FMT_PDML):
-        /* do nothing */
-        break;
-    case(PR_FMT_PSML):
-        /* do nothing */
-        break;
-    default:
+               break;
+
+       default:
                g_assert_not_reached();
     }
 }
diff --git a/print.h b/print.h
index 51670c597a67dc209fd60c26c09ea405efcb6006..73f9116d38339229170a1562499a1a525b74f92d 100644 (file)
--- a/print.h
+++ b/print.h
@@ -1,7 +1,7 @@
 /* print.h
  * Definitions for printing packet analysis trees.
  *
- * $Id: print.h,v 1.44 2004/05/09 10:03:37 guy Exp $
+ * $Id: print.h,v 1.45 2004/07/08 10:36:27 guy Exp $
  *
  * Gilbert Ramirez <gram@alumni.rice.edu>
  *
 
 #include <epan/packet.h>
 
-
 /* print output format */
 typedef enum {
   PR_FMT_TEXT,    /* plain text */
   PR_FMT_PS,      /* postscript */
-  PR_FMT_PSML,    /* packet summary markup language */
-  PR_FMT_PDML     /* packet data markup language */
 } print_format_e;
 
 /* print_range, enum which frames should be printed */
@@ -80,6 +77,12 @@ extern void print_formfeed(FILE *fh, print_format_e format);
 extern void print_finale(FILE *fh, print_format_e format);
 extern void proto_tree_print(print_args_t *print_args, epan_dissect_t *edt,
      FILE *fh);
+extern void write_pdml_preamble(FILE *fh);
+extern void proto_tree_write_pdml(epan_dissect_t *edt, FILE *fh);
+extern void write_pdml_finale(FILE *fh);
+extern void write_psml_preamble(FILE *fh);
+extern void proto_tree_write_psml(epan_dissect_t *edt, FILE *fh);
+extern void write_psml_finale(FILE *fh);
 extern void print_hex_data(FILE *fh, print_format_e format, epan_dissect_t *edt);
 extern void print_line(FILE *fh, int indent, print_format_e format, char *line);
 
index d3b683c9b3670a147c568ea755ffac174a0c6f6e..166d80e2f4b0af0d3f308764aced6c43421a8d44 100644 (file)
@@ -1,6 +1,6 @@
 /* tethereal.c
  *
- * $Id: tethereal.c,v 1.245 2004/07/08 07:47:29 guy Exp $
+ * $Id: tethereal.c,v 1.246 2004/07/08 10:36:27 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
  * various functions that output the usage for this parameter.
  */
 static const gchar decode_as_arg_template[] = "<layer_type>==<selector>,<decode_as_protocol>";
+
 static guint32 firstsec, firstusec;
 static guint32 prevsec, prevusec;
 static GString *comp_info_str, *runtime_info_str;
 static gboolean quiet;
+
 static gboolean print_packet_info;     /* TRUE if we're to print packet information */
+/*
+ * The way the packet decode is to be written.
+ */
+typedef enum {
+       WRITE_TEXT,     /* summary or detail text */
+       WRITE_XML       /* PDML or PSML */
+       /* Add CSV and the like here */
+} output_action_e;
+static output_action_e output_action;
 static gboolean do_dissection; /* TRUE if we have to dissect each packet */
 static gboolean verbose;
 static gboolean print_hex;
@@ -173,7 +184,9 @@ static gboolean process_packet(capture_file *cf, wtap_dumper *pdh, long offset,
     const guchar *pd, int *err);
 static void show_capture_file_io_error(const char *, int, gboolean);
 static void show_print_file_io_error(int err);
+static void write_preamble(capture_file *cf);
 static void print_packet(capture_file *cf, epan_dissect_t *edt);
+static void write_finale(void);
 static char *cf_open_error_message(int err, gchar *err_info,
     gboolean for_writing, int file_type);
 #ifdef HAVE_LIBPCAP
@@ -1118,7 +1131,7 @@ main(int argc, char *argv[])
           is probably actually better for "-V", as it does fewer
           writes).
 
-          See the comment in "print_packet()" for an explanation of
+          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",
@@ -1209,15 +1222,22 @@ main(int argc, char *argv[])
         }
         break;
       case 'T':        /* printing Type */
-        if (strcmp(optarg, "text") == 0)
+        if (strcmp(optarg, "text") == 0) {
+               output_action = WRITE_TEXT;
                print_format = PR_FMT_TEXT;
-       else if (strcmp(optarg, "pdml") == 0)
-               print_format = PR_FMT_PDML;
-       else if (strcmp(optarg, "ps") == 0)
+       } else if (strcmp(optarg, "ps") == 0) {
+               output_action = WRITE_TEXT;
                print_format = PR_FMT_PS;
-       else {
+               verbose = TRUE;
+       } 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\" or \"pdml\".\n");
+               fprintf(stderr, "It must be \"ps\", \"text\", \"pdml\", or \"psml\".\n");
                exit(1);
        }
        break;
@@ -1280,10 +1300,6 @@ main(int argc, char *argv[])
     }
   }
 
-  /* If printing PDML or PS, force -V */
-  if (print_format == PR_FMT_PDML || print_format == PR_FMT_PS)
-         verbose = TRUE;
-
   /* If no capture filter or read filter has been specified, and there are
      still command-line arguments, treat them as the tokens of a capture
      filter (if no "-r" flag was specified) or a read filter (if a "-r"
@@ -1366,6 +1382,11 @@ main(int argc, char *argv[])
     exit(1);
   }
 
+  if (output_action != WRITE_TEXT) {
+    fprintf(stderr, "tethereal: Raw packet hex data can only be printed as text or PostScript\n");
+    exit(1);
+  }
+
 #ifdef HAVE_LIBPCAP
   if (list_link_layer_types) {
     /* We're supposed to list the link-layer types for an interface;
@@ -2322,7 +2343,7 @@ load_cap_file(capture_file *cf, int out_file_type)
       goto out;
     }
   } else {
-    print_preamble(stdout, print_format, cf->filename);
+    write_preamble(cf);
     if (ferror(stdout)) {
       err = errno;
       show_print_file_io_error(err);
@@ -2385,7 +2406,7 @@ load_cap_file(capture_file *cf, int out_file_type)
       if (!wtap_dump_close(pdh, &err))
         show_capture_file_io_error(cfile.save_file, err, TRUE);
     } else {
-      print_finale(stdout, print_format);
+      write_finale();
       if (ferror(stdout)) {
         err = errno;
         show_print_file_io_error(err);
@@ -2561,6 +2582,34 @@ process_packet(capture_file *cf, wtap_dumper *pdh, long offset,
       /* We're printing packet information; print the information for
          this packet. */
       print_packet(cf, edt);
+
+      /* The ANSI C standard does not appear to *require* that a line-buffered
+         stream be flushed to the host environment whenever a newline is
+         written, it just says that, on such a stream, characters "are
+         intended to be transmitted to or from the host environment as a
+         block when a new-line character is encountered".
+
+         The Visual C++ 6.0 C implementation doesn't do what is intended;
+         even if you set a stream to be line-buffered, it still doesn't
+         flush the buffer at the end of every line.
+
+         So, if the "-l" flag was specified, we flush the standard output
+         at the end of a packet.  This will do the right thing if we're
+         printing packet summary lines, and, as we print the entire protocol
+         tree for a single packet without waiting for anything to happen,
+         it should be as good as line-buffered mode if we're printing
+         protocol trees.  (The whole reason for the "-l" flag in either
+         tcpdump or Tethereal is to allow the output of a live capture to
+         be piped to a program or script and to have that script see the
+         information for the packet as soon as it's printed, rather than
+         having to wait until a standard I/O buffer fills up. */
+      if (line_buffered)
+        fflush(stdout);
+
+      if (ferror(stdout)) {
+        show_print_file_io_error(errno);
+        exit(2);
+      }
     }
   }
 
@@ -2622,244 +2671,277 @@ show_capture_file_io_error(const char *fname, int err, gboolean is_close)
 }
 
 static void
-print_packet(capture_file *cf, epan_dissect_t *edt)
+write_preamble(capture_file *cf)
 {
-  print_args_t  print_args;
-  int           i;
+  switch (output_action) {
 
-  print_args.to_file = TRUE;
-  print_args.format = print_format;
-  print_args.print_summary = !verbose;
-  print_args.print_hex = verbose && print_hex;
-  print_args.print_formfeed = FALSE;
-  print_args.print_dissections = verbose ? print_dissections_expanded : print_dissections_none;
+  case WRITE_TEXT:
+    print_preamble(stdout, print_format, cf->filename);
+    break;
 
-  /* init the packet range */
-  packet_range_init(&print_args.range);
+  case WRITE_XML:
+    if (verbose)
+      write_pdml_preamble(stdout);
+    else
+      write_psml_preamble(stdout);
+    break;
+  }
+}
 
-  if (verbose) {
-    /* Print the information in the protocol tree. */
-    proto_tree_print(&print_args, edt, stdout);
-    if (!print_hex) {
-      /* "print_hex_data()" will put out a leading blank line, as well
-       as a trailing one; print one here, to separate the packets,
-       only if "print_hex_data()" won't be called. */
-      printf("\n");
-    }
-  } else {
-    /* Just fill in the columns. */
-    epan_dissect_fill_in_columns(edt);
+static void
+print_columns(capture_file *cf)
+{
+  int i;
 
-    /* Now print them. */
-    for (i = 0; i < cf->cinfo.num_cols; i++) {
-      switch (cf->cinfo.col_fmt[i]) {
-      case COL_NUMBER:
-       /*
-        * Don't print this if we're doing a live capture from a network
-        * interface - if we're doing a live capture, you won't be
-        * able to look at the capture in the future (it's not being
-        * saved anywhere), so the frame numbers are unlikely to be
-        * useful.
-        *
-        * (XXX - it might be nice to be able to save and print at
-        * the same time, sort of like an "Update list of packets
-        * in real time" capture in Ethereal.)
-        */
-        if (cf->iface != NULL)
-          continue;
-        printf("%3s", cf->cinfo.col_data[i]);
-        break;
+  for (i = 0; i < cf->cinfo.num_cols; i++) {
+    switch (cf->cinfo.col_fmt[i]) {
+    case COL_NUMBER:
+      /*
+       * Don't print this if we're doing a live capture from a network
+       * interface - if we're doing a live capture, you won't be
+       * able to look at the capture in the future (it's not being
+       * saved anywhere), so the frame numbers are unlikely to be
+       * useful.
+       *
+       * (XXX - it might be nice to be able to save and print at
+       * the same time, sort of like an "Update list of packets
+       * in real time" capture in Ethereal.)
+       */
+      if (cf->iface != NULL)
+        continue;
+      printf("%3s", cf->cinfo.col_data[i]);
+      break;
 
-      case COL_CLS_TIME:
-      case COL_REL_TIME:
-      case COL_ABS_TIME:
-      case COL_ABS_DATE_TIME:  /* XXX - wider */
-        printf("%10s", cf->cinfo.col_data[i]);
-        break;
+    case COL_CLS_TIME:
+    case COL_REL_TIME:
+    case COL_ABS_TIME:
+    case COL_ABS_DATE_TIME:    /* XXX - wider */
+      printf("%10s", cf->cinfo.col_data[i]);
+      break;
+
+    case COL_DEF_SRC:
+    case COL_RES_SRC:
+    case COL_UNRES_SRC:
+    case COL_DEF_DL_SRC:
+    case COL_RES_DL_SRC:
+    case COL_UNRES_DL_SRC:
+    case COL_DEF_NET_SRC:
+    case COL_RES_NET_SRC:
+    case COL_UNRES_NET_SRC:
+      printf("%12s", cf->cinfo.col_data[i]);
+      break;
+
+    case COL_DEF_DST:
+    case COL_RES_DST:
+    case COL_UNRES_DST:
+    case COL_DEF_DL_DST:
+    case COL_RES_DL_DST:
+    case COL_UNRES_DL_DST:
+    case COL_DEF_NET_DST:
+    case COL_RES_NET_DST:
+    case COL_UNRES_NET_DST:
+      printf("%-12s", cf->cinfo.col_data[i]);
+      break;
+
+    default:
+      printf("%s", cf->cinfo.col_data[i]);
+      break;
+    }
+    if (i != cf->cinfo.num_cols - 1) {
+      /*
+       * This isn't the last column, so we need to print a
+       * separator between this column and the next.
+       *
+       * If we printed a network source and are printing a
+       * network destination of the same type next, separate
+       * them with "->"; if we printed a network destination
+       * and are printing a network source of the same type
+       * next, separate them with "<-"; otherwise separate them
+       * with a space.
+       */
+      switch (cf->cinfo.col_fmt[i]) {
 
       case COL_DEF_SRC:
       case COL_RES_SRC:
       case COL_UNRES_SRC:
+        switch (cf->cinfo.col_fmt[i + 1]) {
+
+        case COL_DEF_DST:
+        case COL_RES_DST:
+        case COL_UNRES_DST:
+          printf(" -> ");
+          break;
+
+        default:
+          putchar(' ');
+          break;
+        }
+        break;
+
       case COL_DEF_DL_SRC:
       case COL_RES_DL_SRC:
       case COL_UNRES_DL_SRC:
+        switch (cf->cinfo.col_fmt[i + 1]) {
+
+        case COL_DEF_DL_DST:
+        case COL_RES_DL_DST:
+        case COL_UNRES_DL_DST:
+          printf(" -> ");
+          break;
+
+        default:
+          putchar(' ');
+          break;
+        }
+        break;
+
       case COL_DEF_NET_SRC:
       case COL_RES_NET_SRC:
       case COL_UNRES_NET_SRC:
-        printf("%12s", cf->cinfo.col_data[i]);
+        switch (cf->cinfo.col_fmt[i + 1]) {
+
+        case COL_DEF_NET_DST:
+        case COL_RES_NET_DST:
+        case COL_UNRES_NET_DST:
+          printf(" -> ");
+          break;
+
+        default:
+          putchar(' ');
+          break;
+        }
         break;
 
       case COL_DEF_DST:
       case COL_RES_DST:
       case COL_UNRES_DST:
+        switch (cf->cinfo.col_fmt[i + 1]) {
+
+        case COL_DEF_SRC:
+        case COL_RES_SRC:
+        case COL_UNRES_SRC:
+          printf(" <- ");
+          break;
+
+        default:
+          putchar(' ');
+          break;
+        }
+        break;
+
       case COL_DEF_DL_DST:
       case COL_RES_DL_DST:
       case COL_UNRES_DL_DST:
+        switch (cf->cinfo.col_fmt[i + 1]) {
+
+        case COL_DEF_DL_SRC:
+        case COL_RES_DL_SRC:
+        case COL_UNRES_DL_SRC:
+          printf(" <- ");
+          break;
+
+        default:
+          putchar(' ');
+          break;
+        }
+        break;
+
       case COL_DEF_NET_DST:
       case COL_RES_NET_DST:
       case COL_UNRES_NET_DST:
-        printf("%-12s", cf->cinfo.col_data[i]);
+        switch (cf->cinfo.col_fmt[i + 1]) {
+
+        case COL_DEF_NET_SRC:
+        case COL_RES_NET_SRC:
+        case COL_UNRES_NET_SRC:
+          printf(" <- ");
+          break;
+
+        default:
+          putchar(' ');
+          break;
+        }
         break;
 
       default:
-        printf("%s", cf->cinfo.col_data[i]);
+        putchar(' ');
         break;
       }
-      if (i != cf->cinfo.num_cols - 1) {
-        /*
-        * This isn't the last column, so we need to print a
-        * separator between this column and the next.
-        *
-        * If we printed a network source and are printing a
-        * network destination of the same type next, separate
-        * them with "->"; if we printed a network destination
-        * and are printing a network source of the same type
-        * next, separate them with "<-"; otherwise separate them
-        * with a space.
-        */
-       switch (cf->cinfo.col_fmt[i]) {
-
-       case COL_DEF_SRC:
-       case COL_RES_SRC:
-       case COL_UNRES_SRC:
-         switch (cf->cinfo.col_fmt[i + 1]) {
-
-         case COL_DEF_DST:
-         case COL_RES_DST:
-         case COL_UNRES_DST:
-           printf(" -> ");
-           break;
-
-         default:
-           putchar(' ');
-           break;
-         }
-         break;
-
-       case COL_DEF_DL_SRC:
-       case COL_RES_DL_SRC:
-       case COL_UNRES_DL_SRC:
-         switch (cf->cinfo.col_fmt[i + 1]) {
-
-         case COL_DEF_DL_DST:
-         case COL_RES_DL_DST:
-         case COL_UNRES_DL_DST:
-           printf(" -> ");
-           break;
-
-         default:
-           putchar(' ');
-           break;
-         }
-         break;
-
-       case COL_DEF_NET_SRC:
-       case COL_RES_NET_SRC:
-       case COL_UNRES_NET_SRC:
-         switch (cf->cinfo.col_fmt[i + 1]) {
-
-         case COL_DEF_NET_DST:
-         case COL_RES_NET_DST:
-         case COL_UNRES_NET_DST:
-           printf(" -> ");
-           break;
-
-         default:
-           putchar(' ');
-           break;
-         }
-         break;
-
-       case COL_DEF_DST:
-       case COL_RES_DST:
-       case COL_UNRES_DST:
-         switch (cf->cinfo.col_fmt[i + 1]) {
-
-         case COL_DEF_SRC:
-         case COL_RES_SRC:
-         case COL_UNRES_SRC:
-           printf(" <- ");
-           break;
-
-         default:
-           putchar(' ');
-           break;
-         }
-         break;
-
-       case COL_DEF_DL_DST:
-       case COL_RES_DL_DST:
-       case COL_UNRES_DL_DST:
-         switch (cf->cinfo.col_fmt[i + 1]) {
-
-         case COL_DEF_DL_SRC:
-         case COL_RES_DL_SRC:
-         case COL_UNRES_DL_SRC:
-           printf(" <- ");
-           break;
-
-         default:
-           putchar(' ');
-           break;
-         }
-         break;
-
-       case COL_DEF_NET_DST:
-       case COL_RES_NET_DST:
-       case COL_UNRES_NET_DST:
-         switch (cf->cinfo.col_fmt[i + 1]) {
-
-         case COL_DEF_NET_SRC:
-         case COL_RES_NET_SRC:
-         case COL_UNRES_NET_SRC:
-           printf(" <- ");
-           break;
-
-         default:
-           putchar(' ');
-           break;
-         }
-         break;
-
-       default:
-         putchar(' ');
-         break;
-       }
-      }
     }
-    putchar('\n');
+  }
+  putchar('\n');
+}
+
+static void
+print_packet(capture_file *cf, epan_dissect_t *edt)
+{
+  print_args_t  print_args;
+
+  if (verbose) {
+    /* Print the information in the protocol tree. */
+    switch (output_action) {
+
+    case WRITE_TEXT:
+      print_args.to_file = TRUE;
+      print_args.format = print_format;
+      print_args.print_summary = !verbose;
+      print_args.print_hex = verbose && print_hex;
+      print_args.print_formfeed = FALSE;
+      print_args.print_dissections = verbose ? print_dissections_expanded : print_dissections_none;
+
+      /* init the packet range */
+      packet_range_init(&print_args.range);
+
+      proto_tree_print(&print_args, edt, stdout);
+      break;
+
+    case WRITE_XML:
+      proto_tree_write_pdml(edt, stdout);
+      break;
+    }
+    if (!print_hex) {
+      /* "print_hex_data()" will put out a leading blank line, as well
+       as a trailing one; print one here, to separate the packets,
+       only if "print_hex_data()" won't be called. */
+      printf("\n");
+    }
+  } else {
+    /* Just fill in the columns. */
+    epan_dissect_fill_in_columns(edt);
+
+    /* Now print them. */
+    switch (output_action) {
+
+    case WRITE_TEXT:
+        print_columns(cf);
+        break;
+
+    case WRITE_XML:
+        proto_tree_write_psml(edt, stdout);
+        break;
+    }
   }
   if (print_hex) {
-    print_hex_data(stdout, print_args.format, edt);
+    print_hex_data(stdout, print_format, edt);
     putchar('\n');
   }
+}
 
-  /* The ANSI C standard does not appear to *require* that a line-buffered
-     stream be flushed to the host environment whenever a newline is
-     written, it just says that, on such a stream, characters "are
-     intended to be transmitted to or from the host environment as a
-     block when a new-line character is encountered".
-
-     The Visual C++ 6.0 C implementation doesn't do what is intended;
-     even if you set a stream to be line-buffered, it still doesn't
-     flush the buffer at the end of every line.
-
-     So, if the "-l" flag was specified, we flush the standard output
-     at the end of a packet.  This will do the right thing if we're
-     printing packet summary lines, and, as we print the entire protocol
-     tree for a single packet without waiting for anything to happen,
-     it should be as good as line-buffered mode if we're printing
-     protocol trees.  (The whole reason for the "-l" flag in either
-     tcpdump or Tethereal is to allow the output of a live capture to
-     be piped to a program or script and to have that script see the
-     information for the packet as soon as it's printed, rather than
-     having to wait until a standard I/O buffer fills up. */
-  if (line_buffered)
-    fflush(stdout);
-
-  if (ferror(stdout)) {
-    show_print_file_io_error(errno);
-    exit(2);
+static void
+write_finale(void)
+{
+  switch (output_action) {
+
+  case WRITE_TEXT:
+    print_finale(stdout, print_format);
+    break;
+
+  case WRITE_XML:
+    if (verbose)
+      write_pdml_finale(stdout);
+    else
+      write_psml_finale(stdout);
+    break;
   }
 }