Split the low-level print stream code into a separate file.
authorGuy Harris <guy@alum.mit.edu>
Sat, 22 Nov 2014 03:22:54 +0000 (19:22 -0800)
committerGuy Harris <guy@alum.mit.edu>
Sat, 22 Nov 2014 03:24:17 +0000 (03:24 +0000)
Put the low-level print stream code from epan/print.c into
epan/print_stream.c, leaving the higher-level stuff in print.c

Change-Id: Iae961f168ec655a29f434257b1af0937fca9f025
Reviewed-on: https://code.wireshark.org/review/5436
Reviewed-by: Guy Harris <guy@alum.mit.edu>
epan/CMakeLists.txt
epan/Makefile.common
epan/print.c
epan/print.h
epan/print_stream.c [new file with mode: 0644]
epan/print_stream.h [new file with mode: 0644]

index 7183de42bc2833cb6af27fe16f7262cb918637dd..9827d71679880b11e51ef093b81a6cfe54001477 100644 (file)
@@ -1586,6 +1586,7 @@ set(LIBWIRESHARK_FILES
        packet-range.c
        packet.c
        print.c
+       print_stream.c
        prefs.c
        proto.c
        ps.c
index e0d4d333e9130a8ceac1d2db177811fa994b908f..7d193a40d4afd04314b618eca8a61c20d3eb1d3a 100644 (file)
@@ -74,6 +74,7 @@ LIBWIRESHARK_SRC =            \
        packet.c                \
        prefs.c                 \
        print.c                 \
+       print_stream.c          \
        proto.c                 \
        range.c                 \
        reassemble.c            \
@@ -226,6 +227,7 @@ LIBWIRESHARK_INCLUDES =             \
        params.h                \
        ppptypes.h              \
        print.h                 \
+       print_stream.h          \
        prefs.h                 \
        prefs-int.h             \
        proto.h                 \
index 4336c6ad00f73ca93d1e0ba4ee72bc50bbc249b6..b0e0f0c7be59ce82cae638192ec9d2364234dafa 100644 (file)
 #include <epan/expert.h>
 
 #include <epan/packet-range.h>
-#include "print.h"
-#include "ps.h"
+#include <epan/print.h>
 #include "version_info.h"
-#include <wsutil/file_util.h>
 #include <epan/charsets.h>
 #include <epan/dissectors/packet-data.h>
 #include <epan/dissectors/packet-frame.h>
@@ -98,40 +96,12 @@ 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 gboolean print_hex_data_buffer(print_stream_t *stream, const guchar *cp,
                                       guint length, packet_char_enc encoding);
-static void ps_clean_string(char *out, const char *in,
-                            int outbuf_size);
 static void print_escaped_xml(FILE *fh, const char *unescaped_string);
 
 static void print_pdml_geninfo(proto_tree *tree, FILE *fh);
 
 static void proto_tree_get_node_field_values(proto_node *node, gpointer data);
 
-static FILE *
-open_print_dest(gboolean to_file, const char *dest)
-{
-    FILE *fh;
-
-    /* Open the file or command for output */
-    if (to_file)
-        fh = ws_fopen(dest, "w");
-    else
-        fh = popen(dest, "w");
-
-    return fh;
-}
-
-static gboolean
-close_print_dest(gboolean to_file, FILE *fh)
-{
-    /* Close the file or command */
-    if (to_file)
-        return (fclose(fh) == 0);
-    else
-        return (pclose(fh) == 0);
-}
-
-#define MAX_PS_LINE_LENGTH 256
-
 gboolean
 proto_tree_print(print_args_t *print_args, epan_dissect_t *edt,
                  print_stream_t *stream)
@@ -154,8 +124,6 @@ proto_tree_print(print_args_t *print_args, epan_dissect_t *edt,
     return data.success;
 }
 
-#define MAX_INDENT    160
-
 /* Print a tree's data, and any child nodes. */
 static void
 proto_tree_print_node(proto_node *node, gpointer data)
@@ -1049,325 +1017,6 @@ print_hex_data_buffer(print_stream_t *stream, const guchar *cp,
     return TRUE;
 }
 
-static
-void ps_clean_string(char *out, const char *in, int outbuf_size)
-{
-    int  rd, wr;
-    char c;
-
-    if (in == NULL) {
-        out[0] = '\0';
-        return;
-    }
-
-    for (rd = 0, wr = 0 ; wr < outbuf_size; rd++, wr++ ) {
-        c = in[rd];
-        switch (c) {
-        case '(':
-        case ')':
-        case '\\':
-            out[wr] = '\\';
-            out[++wr] = c;
-            break;
-
-        default:
-            out[wr] = c;
-            break;
-        }
-
-        if (c == 0) {
-            break;
-        }
-    }
-}
-
-/* Some formats need stuff at the beginning of the output */
-gboolean
-print_preamble(print_stream_t *self, gchar *filename, const char *version_string)
-{
-    return self->ops->print_preamble ? (self->ops->print_preamble)(self, filename, version_string) : TRUE;
-}
-
-gboolean
-print_line(print_stream_t *self, int indent, const char *line)
-{
-    return (self->ops->print_line)(self, indent, line);
-}
-
-/* Insert bookmark */
-gboolean
-print_bookmark(print_stream_t *self, const gchar *name, const gchar *title)
-{
-    return self->ops->print_bookmark ? (self->ops->print_bookmark)(self, name, title) : TRUE;
-}
-
-gboolean
-new_page(print_stream_t *self)
-{
-    return self->ops->new_page ? (self->ops->new_page)(self) : TRUE;
-}
-
-/* Some formats need stuff at the end of the output */
-gboolean
-print_finale(print_stream_t *self)
-{
-    return self->ops->print_finale ? (self->ops->print_finale)(self) : TRUE;
-}
-
-gboolean
-destroy_print_stream(print_stream_t *self)
-{
-    return self->ops->destroy ? (self->ops->destroy)(self) : TRUE;
-}
-
-typedef struct {
-    gboolean  to_file;
-    FILE     *fh;
-} output_text;
-
-static gboolean
-print_line_text(print_stream_t *self, int indent, const char *line)
-{
-    static char  spaces[MAX_INDENT];
-    size_t ret;
-
-    output_text *output = (output_text *)self->data;
-    unsigned int num_spaces;
-
-    /* should be space, if NUL -> initialize */
-    if (!spaces[0]) {
-        int i;
-
-        for (i = 0; i < MAX_INDENT; i++)
-            spaces[i] = ' ';
-    }
-
-    /* Prepare the tabs for printing, depending on tree level */
-    num_spaces = indent * 4;
-    if (num_spaces > MAX_INDENT)
-        num_spaces = MAX_INDENT;
-
-    ret = fwrite(spaces, 1, num_spaces, output->fh);
-    if (ret == num_spaces) {
-        fputs(line, output->fh);
-        putc('\n', output->fh);
-    }
-    return !ferror(output->fh);
-}
-
-static gboolean
-new_page_text(print_stream_t *self)
-{
-    output_text *output = (output_text *)self->data;
-
-    fputs("\f", output->fh);
-    return !ferror(output->fh);
-}
-
-static gboolean
-destroy_text(print_stream_t *self)
-{
-    output_text *output = (output_text *)self->data;
-    gboolean     ret;
-
-    ret = close_print_dest(output->to_file, output->fh);
-    g_free(output);
-    g_free(self);
-    return ret;
-}
-
-static const print_stream_ops_t print_text_ops = {
-    NULL,            /* preamble */
-    print_line_text,
-    NULL,            /* bookmark */
-    new_page_text,
-    NULL,            /* finale */
-    destroy_text
-};
-
-static print_stream_t *
-print_stream_text_alloc(gboolean to_file, FILE *fh)
-{
-    print_stream_t *stream;
-    output_text    *output;
-
-    output          = (output_text *)g_malloc(sizeof *output);
-    output->to_file = to_file;
-    output->fh      = fh;
-    stream          = (print_stream_t *)g_malloc(sizeof (print_stream_t));
-    stream->ops     = &print_text_ops;
-    stream->data    = output;
-
-    return stream;
-}
-
-print_stream_t *
-print_stream_text_new(gboolean to_file, const char *dest)
-{
-    FILE *fh;
-
-    fh = open_print_dest(to_file, dest);
-    if (fh == NULL)
-        return NULL;
-
-    return print_stream_text_alloc(to_file, fh);
-}
-
-print_stream_t *
-print_stream_text_stdio_new(FILE *fh)
-{
-    return print_stream_text_alloc(TRUE, fh);
-}
-
-typedef struct {
-    gboolean  to_file;
-    FILE     *fh;
-} output_ps;
-
-static gboolean
-print_preamble_ps(print_stream_t *self, gchar *filename, const char *version_string)
-{
-    output_ps *output = (output_ps *)self->data;
-    char       psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
-
-    print_ps_preamble(output->fh);
-
-    fputs("%% the page title\n", output->fh);
-    ps_clean_string(psbuffer, filename, MAX_PS_LINE_LENGTH);
-    fprintf(output->fh, "/ws_pagetitle (%s - Wireshark %s) def\n", psbuffer, version_string);
-    fputs("\n", output->fh);
-    return !ferror(output->fh);
-}
-
-static gboolean
-print_line_ps(print_stream_t *self, int indent, const char *line)
-{
-    output_ps *output = (output_ps *)self->data;
-    char       psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
-
-    ps_clean_string(psbuffer, line, MAX_PS_LINE_LENGTH);
-    fprintf(output->fh, "%d (%s) putline\n", indent, psbuffer);
-    return !ferror(output->fh);
-}
-
-static gboolean
-print_bookmark_ps(print_stream_t *self, const gchar *name, const gchar *title)
-{
-    output_ps *output = (output_ps *)self->data;
-    char       psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
-
-    /*
-     * See the Adobe "pdfmark reference":
-     *
-     *  http://partners.adobe.com/asn/acrobat/docs/pdfmark.pdf
-     *
-     * The pdfmark stuff tells code that turns PostScript into PDF
-     * things that it should do.
-     *
-     * The /OUT stuff creates a bookmark that goes to the
-     * destination with "name" as the name and "title" as the title.
-     *
-     * The "/DEST" creates the destination.
-     */
-    ps_clean_string(psbuffer, title, MAX_PS_LINE_LENGTH);
-    fprintf(output->fh, "[/Dest /%s /Title (%s)   /OUT pdfmark\n", name,
-          psbuffer);
-    fputs("[/View [/XYZ -4 currentpoint matrix currentmatrix matrix defaultmatrix\n",
-          output->fh);
-    fputs("matrix invertmatrix matrix concatmatrix transform exch pop 20 add null]\n",
-          output->fh);
-    fprintf(output->fh, "/Dest /%s /DEST pdfmark\n", name);
-    return !ferror(output->fh);
-}
-
-static gboolean
-new_page_ps(print_stream_t *self)
-{
-    output_ps *output = (output_ps *)self->data;
-
-    fputs("formfeed\n", output->fh);
-    return !ferror(output->fh);
-}
-
-static gboolean
-print_finale_ps(print_stream_t *self)
-{
-    output_ps *output = (output_ps *)self->data;
-
-    print_ps_finale(output->fh);
-    return !ferror(output->fh);
-}
-
-static gboolean
-destroy_ps(print_stream_t *self)
-{
-    output_ps *output = (output_ps *)self->data;
-    gboolean   ret;
-
-    ret = close_print_dest(output->to_file, output->fh);
-    g_free(output);
-    g_free(self);
-    return ret;
-}
-
-static const print_stream_ops_t print_ps_ops = {
-    print_preamble_ps,
-    print_line_ps,
-    print_bookmark_ps,
-    new_page_ps,
-    print_finale_ps,
-    destroy_ps
-};
-
-static print_stream_t *
-print_stream_ps_alloc(gboolean to_file, FILE *fh)
-{
-    print_stream_t *stream;
-    output_ps      *output;
-
-    output          = (output_ps *)g_malloc(sizeof *output);
-    output->to_file = to_file;
-    output->fh      = fh;
-    stream          = (print_stream_t *)g_malloc(sizeof (print_stream_t));
-    stream->ops     = &print_ps_ops;
-    stream->data    = output;
-
-    return stream;
-}
-
-print_stream_t *
-print_stream_ps_new(gboolean to_file, const char *dest)
-{
-    FILE *fh;
-
-    fh = open_print_dest(to_file, dest);
-    if (fh == NULL)
-        return NULL;
-
-    return print_stream_ps_alloc(to_file, fh);
-}
-
-print_stream_t *
-print_stream_ps_stdio_new(FILE *fh)
-{
-    return print_stream_ps_alloc(TRUE, fh);
-}
-
-output_fields_t* output_fields_new(void)
-{
-    output_fields_t* fields     = g_new(output_fields_t, 1);
-    fields->print_header        = FALSE;
-    fields->separator           = '\t';
-    fields->occurrence          = 'a';
-    fields->aggregator          = ',';
-    fields->fields              = NULL; /*Do lazy initialisation */
-    fields->field_indicies      = NULL;
-    fields->field_values        = NULL;
-    fields->quote               ='\0';
-    fields->includes_col_fields = FALSE;
-    return fields;
-}
-
 gsize output_fields_num_fields(output_fields_t* fields)
 {
     g_assert(fields);
@@ -1851,6 +1500,21 @@ get_field_hex_value(GSList *src_list, field_info *fi)
     }
 }
 
+output_fields_t* output_fields_new(void)
+{
+    output_fields_t* fields     = g_new(output_fields_t, 1);
+    fields->print_header        = FALSE;
+    fields->separator           = '\t';
+    fields->occurrence          = 'a';
+    fields->aggregator          = ',';
+    fields->fields              = NULL; /*Do lazy initialisation */
+    fields->field_indicies      = NULL;
+    fields->field_values        = NULL;
+    fields->quote               ='\0';
+    fields->includes_col_fields = FALSE;
+    return fields;
+}
+
 /*
  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
  *
index 9832d575a44eec67b82c6a484ae8d2be4f0dfb2d..816c401660fc1402b340d04783ddb2dfb2126817 100644 (file)
 #include <epan/epan.h>
 #include <epan/packet.h>
 
+#include <epan/print_stream.h>
+
 #include <epan/packet-range.h>
 
+#include "ws_symbol_export.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
 
-/*
- * Print stream code; this provides a "print stream" class with subclasses
- * of various sorts.  Additional subclasses might be implemented elsewhere.
- */
-struct print_stream;
-
-typedef struct print_stream_ops {
-       gboolean (*print_preamble)(struct print_stream *self, gchar *filename, const char *version_string);
-       gboolean (*print_line)(struct print_stream *self, int indent,
-           const char *line);
-       gboolean (*print_bookmark)(struct print_stream *self,
-           const gchar *name, const gchar *title);
-       gboolean (*new_page)(struct print_stream *self);
-       gboolean (*print_finale)(struct print_stream *self);
-       gboolean (*destroy)(struct print_stream *self);
-} print_stream_ops_t;
-
-typedef struct print_stream {
-       const print_stream_ops_t *ops;
-       void *data;
-} print_stream_t;
-
-WS_DLL_PUBLIC print_stream_t *print_stream_text_new(gboolean to_file, const char *dest);
-WS_DLL_PUBLIC print_stream_t *print_stream_text_stdio_new(FILE *fh);
-WS_DLL_PUBLIC print_stream_t *print_stream_ps_new(gboolean to_file, const char *dest);
-WS_DLL_PUBLIC print_stream_t *print_stream_ps_stdio_new(FILE *fh);
-
-WS_DLL_PUBLIC gboolean print_preamble(print_stream_t *self, gchar *filename, const char *version_string);
-WS_DLL_PUBLIC gboolean print_line(print_stream_t *self, int indent, const char *line);
-WS_DLL_PUBLIC gboolean print_bookmark(print_stream_t *self, const gchar *name,
-    const gchar *title);
-WS_DLL_PUBLIC gboolean new_page(print_stream_t *self);
-WS_DLL_PUBLIC gboolean print_finale(print_stream_t *self);
-WS_DLL_PUBLIC gboolean destroy_print_stream(print_stream_t *self);
-
 /* print output format */
 typedef enum {
   PR_FMT_TEXT,    /* plain text */
diff --git a/epan/print_stream.c b/epan/print_stream.c
new file mode 100644 (file)
index 0000000..5f93072
--- /dev/null
@@ -0,0 +1,367 @@
+/* print.c
+ * Routines for printing packet analysis trees.
+ *
+ * Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+
+#include <glib.h>
+
+#include <epan/print_stream.h>
+
+#include <epan/ps.h>
+
+#include <wsutil/file_util.h>
+
+static FILE *
+open_print_dest(gboolean to_file, const char *dest)
+{
+    FILE *fh;
+
+    /* Open the file or command for output */
+    if (to_file)
+        fh = ws_fopen(dest, "w");
+    else
+        fh = popen(dest, "w");
+
+    return fh;
+}
+
+static gboolean
+close_print_dest(gboolean to_file, FILE *fh)
+{
+    /* Close the file or command */
+    if (to_file)
+        return (fclose(fh) == 0);
+    else
+        return (pclose(fh) == 0);
+}
+
+/* Some formats need stuff at the beginning of the output */
+gboolean
+print_preamble(print_stream_t *self, gchar *filename, const char *version_string)
+{
+    return self->ops->print_preamble ? (self->ops->print_preamble)(self, filename, version_string) : TRUE;
+}
+
+gboolean
+print_line(print_stream_t *self, int indent, const char *line)
+{
+    return (self->ops->print_line)(self, indent, line);
+}
+
+/* Insert bookmark */
+gboolean
+print_bookmark(print_stream_t *self, const gchar *name, const gchar *title)
+{
+    return self->ops->print_bookmark ? (self->ops->print_bookmark)(self, name, title) : TRUE;
+}
+
+gboolean
+new_page(print_stream_t *self)
+{
+    return self->ops->new_page ? (self->ops->new_page)(self) : TRUE;
+}
+
+/* Some formats need stuff at the end of the output */
+gboolean
+print_finale(print_stream_t *self)
+{
+    return self->ops->print_finale ? (self->ops->print_finale)(self) : TRUE;
+}
+
+gboolean
+destroy_print_stream(print_stream_t *self)
+{
+    return self->ops->destroy ? (self->ops->destroy)(self) : TRUE;
+}
+
+typedef struct {
+    gboolean  to_file;
+    FILE     *fh;
+} output_text;
+
+#define MAX_INDENT    160
+
+static gboolean
+print_line_text(print_stream_t *self, int indent, const char *line)
+{
+    static char  spaces[MAX_INDENT];
+    size_t ret;
+
+    output_text *output = (output_text *)self->data;
+    unsigned int num_spaces;
+
+    /* should be space, if NUL -> initialize */
+    if (!spaces[0]) {
+        int i;
+
+        for (i = 0; i < MAX_INDENT; i++)
+            spaces[i] = ' ';
+    }
+
+    /* Prepare the tabs for printing, depending on tree level */
+    num_spaces = indent * 4;
+    if (num_spaces > MAX_INDENT)
+        num_spaces = MAX_INDENT;
+
+    ret = fwrite(spaces, 1, num_spaces, output->fh);
+    if (ret == num_spaces) {
+        fputs(line, output->fh);
+        putc('\n', output->fh);
+    }
+    return !ferror(output->fh);
+}
+
+static gboolean
+new_page_text(print_stream_t *self)
+{
+    output_text *output = (output_text *)self->data;
+
+    fputs("\f", output->fh);
+    return !ferror(output->fh);
+}
+
+static gboolean
+destroy_text(print_stream_t *self)
+{
+    output_text *output = (output_text *)self->data;
+    gboolean     ret;
+
+    ret = close_print_dest(output->to_file, output->fh);
+    g_free(output);
+    g_free(self);
+    return ret;
+}
+
+static const print_stream_ops_t print_text_ops = {
+    NULL,            /* preamble */
+    print_line_text,
+    NULL,            /* bookmark */
+    new_page_text,
+    NULL,            /* finale */
+    destroy_text
+};
+
+static print_stream_t *
+print_stream_text_alloc(gboolean to_file, FILE *fh)
+{
+    print_stream_t *stream;
+    output_text    *output;
+
+    output          = (output_text *)g_malloc(sizeof *output);
+    output->to_file = to_file;
+    output->fh      = fh;
+    stream          = (print_stream_t *)g_malloc(sizeof (print_stream_t));
+    stream->ops     = &print_text_ops;
+    stream->data    = output;
+
+    return stream;
+}
+
+print_stream_t *
+print_stream_text_new(gboolean to_file, const char *dest)
+{
+    FILE *fh;
+
+    fh = open_print_dest(to_file, dest);
+    if (fh == NULL)
+        return NULL;
+
+    return print_stream_text_alloc(to_file, fh);
+}
+
+print_stream_t *
+print_stream_text_stdio_new(FILE *fh)
+{
+    return print_stream_text_alloc(TRUE, fh);
+}
+
+typedef struct {
+    gboolean  to_file;
+    FILE     *fh;
+} output_ps;
+
+#define MAX_PS_LINE_LENGTH 256
+
+static
+void ps_clean_string(char *out, const char *in, int outbuf_size)
+{
+    int  rd, wr;
+    char c;
+
+    if (in == NULL) {
+        out[0] = '\0';
+        return;
+    }
+
+    for (rd = 0, wr = 0 ; wr < outbuf_size; rd++, wr++ ) {
+        c = in[rd];
+        switch (c) {
+        case '(':
+        case ')':
+        case '\\':
+            out[wr] = '\\';
+            out[++wr] = c;
+            break;
+
+        default:
+            out[wr] = c;
+            break;
+        }
+
+        if (c == 0) {
+            break;
+        }
+    }
+}
+
+static gboolean
+print_preamble_ps(print_stream_t *self, gchar *filename, const char *version_string)
+{
+    output_ps *output = (output_ps *)self->data;
+    char       psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
+
+    print_ps_preamble(output->fh);
+
+    fputs("%% the page title\n", output->fh);
+    ps_clean_string(psbuffer, filename, MAX_PS_LINE_LENGTH);
+    fprintf(output->fh, "/ws_pagetitle (%s - Wireshark %s) def\n", psbuffer, version_string);
+    fputs("\n", output->fh);
+    return !ferror(output->fh);
+}
+
+static gboolean
+print_line_ps(print_stream_t *self, int indent, const char *line)
+{
+    output_ps *output = (output_ps *)self->data;
+    char       psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
+
+    ps_clean_string(psbuffer, line, MAX_PS_LINE_LENGTH);
+    fprintf(output->fh, "%d (%s) putline\n", indent, psbuffer);
+    return !ferror(output->fh);
+}
+
+static gboolean
+print_bookmark_ps(print_stream_t *self, const gchar *name, const gchar *title)
+{
+    output_ps *output = (output_ps *)self->data;
+    char       psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
+
+    /*
+     * See the Adobe "pdfmark reference":
+     *
+     *  http://partners.adobe.com/asn/acrobat/docs/pdfmark.pdf
+     *
+     * The pdfmark stuff tells code that turns PostScript into PDF
+     * things that it should do.
+     *
+     * The /OUT stuff creates a bookmark that goes to the
+     * destination with "name" as the name and "title" as the title.
+     *
+     * The "/DEST" creates the destination.
+     */
+    ps_clean_string(psbuffer, title, MAX_PS_LINE_LENGTH);
+    fprintf(output->fh, "[/Dest /%s /Title (%s)   /OUT pdfmark\n", name,
+          psbuffer);
+    fputs("[/View [/XYZ -4 currentpoint matrix currentmatrix matrix defaultmatrix\n",
+          output->fh);
+    fputs("matrix invertmatrix matrix concatmatrix transform exch pop 20 add null]\n",
+          output->fh);
+    fprintf(output->fh, "/Dest /%s /DEST pdfmark\n", name);
+    return !ferror(output->fh);
+}
+
+static gboolean
+new_page_ps(print_stream_t *self)
+{
+    output_ps *output = (output_ps *)self->data;
+
+    fputs("formfeed\n", output->fh);
+    return !ferror(output->fh);
+}
+
+static gboolean
+print_finale_ps(print_stream_t *self)
+{
+    output_ps *output = (output_ps *)self->data;
+
+    print_ps_finale(output->fh);
+    return !ferror(output->fh);
+}
+
+static gboolean
+destroy_ps(print_stream_t *self)
+{
+    output_ps *output = (output_ps *)self->data;
+    gboolean   ret;
+
+    ret = close_print_dest(output->to_file, output->fh);
+    g_free(output);
+    g_free(self);
+    return ret;
+}
+
+static const print_stream_ops_t print_ps_ops = {
+    print_preamble_ps,
+    print_line_ps,
+    print_bookmark_ps,
+    new_page_ps,
+    print_finale_ps,
+    destroy_ps
+};
+
+static print_stream_t *
+print_stream_ps_alloc(gboolean to_file, FILE *fh)
+{
+    print_stream_t *stream;
+    output_ps      *output;
+
+    output          = (output_ps *)g_malloc(sizeof *output);
+    output->to_file = to_file;
+    output->fh      = fh;
+    stream          = (print_stream_t *)g_malloc(sizeof (print_stream_t));
+    stream->ops     = &print_ps_ops;
+    stream->data    = output;
+
+    return stream;
+}
+
+print_stream_t *
+print_stream_ps_new(gboolean to_file, const char *dest)
+{
+    FILE *fh;
+
+    fh = open_print_dest(to_file, dest);
+    if (fh == NULL)
+        return NULL;
+
+    return print_stream_ps_alloc(to_file, fh);
+}
+
+print_stream_t *
+print_stream_ps_stdio_new(FILE *fh)
+{
+    return print_stream_ps_alloc(TRUE, fh);
+}
diff --git a/epan/print_stream.h b/epan/print_stream.h
new file mode 100644 (file)
index 0000000..3a326c4
--- /dev/null
@@ -0,0 +1,73 @@
+/* print.h
+ * Definitions for printing packet analysis trees.
+ *
+ * Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __PRINT_STREAM_H__
+#define __PRINT_STREAM_H__
+
+#include "ws_symbol_export.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*
+ * Print stream code; this provides a "print stream" class with subclasses
+ * of various sorts.  Additional subclasses might be implemented elsewhere.
+ */
+struct print_stream;
+
+typedef struct print_stream_ops {
+       gboolean (*print_preamble)(struct print_stream *self, gchar *filename, const char *version_string);
+       gboolean (*print_line)(struct print_stream *self, int indent,
+           const char *line);
+       gboolean (*print_bookmark)(struct print_stream *self,
+           const gchar *name, const gchar *title);
+       gboolean (*new_page)(struct print_stream *self);
+       gboolean (*print_finale)(struct print_stream *self);
+       gboolean (*destroy)(struct print_stream *self);
+} print_stream_ops_t;
+
+typedef struct print_stream {
+       const print_stream_ops_t *ops;
+       void *data;
+} print_stream_t;
+
+WS_DLL_PUBLIC print_stream_t *print_stream_text_new(gboolean to_file, const char *dest);
+WS_DLL_PUBLIC print_stream_t *print_stream_text_stdio_new(FILE *fh);
+WS_DLL_PUBLIC print_stream_t *print_stream_ps_new(gboolean to_file, const char *dest);
+WS_DLL_PUBLIC print_stream_t *print_stream_ps_stdio_new(FILE *fh);
+
+WS_DLL_PUBLIC gboolean print_preamble(print_stream_t *self, gchar *filename, const char *version_string);
+WS_DLL_PUBLIC gboolean print_line(print_stream_t *self, int indent, const char *line);
+WS_DLL_PUBLIC gboolean print_bookmark(print_stream_t *self, const gchar *name,
+    const gchar *title);
+WS_DLL_PUBLIC gboolean new_page(print_stream_t *self);
+WS_DLL_PUBLIC gboolean print_finale(print_stream_t *self);
+WS_DLL_PUBLIC gboolean destroy_print_stream(print_stream_t *self);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* print_stream.h */