From b650d01031807a9832039d81c634913730dc779c Mon Sep 17 00:00:00 2001 From: Guy Harris Date: Thu, 8 Jul 2004 10:36:29 +0000 Subject: Make the "human-readable text vs. PSML vs. PDML" choice separate from 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). svn path=/trunk/; revision=11342 --- file.c | 149 ++++++++++++++- file.h | 5 +- gtk/print_dlg.c | 32 ++-- print.c | 575 +++++++++++++++++++++++++++++--------------------------- print.h | 11 +- tethereal.c | 510 ++++++++++++++++++++++++++++--------------------- 6 files changed, 770 insertions(+), 512 deletions(-) diff --git a/file.c b/file.c index c7a0708df8..2de8633f7f 100644 --- 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 @@ -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 677aa25946..f7743a84a1 100644 --- 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 @@ -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); diff --git a/gtk/print_dlg.c b/gtk/print_dlg.c index 3e5963ca3c..c37b2c2cf8 100644 --- a/gtk/print_dlg.c +++ b/gtk/print_dlg.c @@ -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 @@ -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 adc4c1ea53..159989d7f7 100644 --- 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 * @@ -46,26 +46,35 @@ #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, "\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, "\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, "\n"); - - for(i=0; i < edt->pi.cinfo->num_cols; i++) { - fprintf(fh, "
"); - print_escaped_xml(fh, edt->pi.cinfo->col_title[i]); - fprintf(fh, "
\n"); - } - - fprintf(fh, "
\n\n"); - } - - fprintf(fh, "\n"); - - for(i=0; i < edt->pi.cinfo->num_cols; i++) { - fprintf(fh, "
"); - print_escaped_xml(fh, edt->pi.cinfo->col_data[i]); - fprintf(fh, "
\n"); - } - - fprintf(fh, "
\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("&", fh); - break; - case '<': - fputs("<", fh); - break; - case '>': - fputs(">", fh); - break; - case '"': - fputs(""", fh); - break; - case '\'': - fputs("'", 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("\n", fh); + fputs("\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, "\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, "\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("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, " \n", frame_finfo->length); /* Print geninfo.num */ - fprintf(pdata->fh, + fprintf(fh, " \n", num, num, frame_finfo->length); /* Print geninfo.len */ - fprintf(pdata->fh, + fprintf(fh, " \n", len, len, frame_finfo->length); /* Print geninfo.caplen */ - fprintf(pdata->fh, + fprintf(fh, " \n", caplen, caplen, frame_finfo->length); /* Print geninfo.timestamp */ - fprintf(pdata->fh, + fprintf(fh, " \n", abs_time_to_str(timestamp), (int) timestamp->secs, timestamp->nsecs, frame_finfo->length); /* Print geninfo end */ - fprintf(pdata->fh, + fprintf(fh, " \n"); } +void +write_pdml_finale(FILE *fh) +{ + fputs("\n", fh); +} + +void +write_psml_preamble(FILE *fh) +{ + fputs("\n", fh); + fputs("\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, "\n"); + + for(i=0; i < edt->pi.cinfo->num_cols; i++) { + fprintf(fh, "
"); + print_escaped_xml(fh, edt->pi.cinfo->col_title[i]); + fprintf(fh, "
\n"); + } + + fprintf(fh, "
\n\n"); + } + + fprintf(fh, "\n"); + + for(i=0; i < edt->pi.cinfo->num_cols; i++) { + fprintf(fh, "
"); + print_escaped_xml(fh, edt->pi.cinfo->col_data[i]); + fprintf(fh, "
\n"); + } + + fprintf(fh, "
\n\n"); +} + +void +write_psml_finale(FILE *fh) +{ + fputs("
\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("&", fh); + break; + case '<': + fputs("<", fh); + break; + case '>': + fputs(">", fh); + break; + case '"': + fputs(""", fh); + break; + case '\'': + fputs("'", 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("\n", fh); - fputs("\n", PACKAGE, VERSION); - break; - case(PR_FMT_PSML): - fputs("\n", fh); - fputs("\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("\n", fh); - break; - case(PR_FMT_PSML): - fputs("\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 51670c597a..73f9116d38 100644 --- 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 * @@ -29,13 +29,10 @@ #include - /* 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); diff --git a/tethereal.c b/tethereal.c index d3b683c9b3..166d80e2f4 100644 --- a/tethereal.c +++ b/tethereal.c @@ -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 @@ -116,11 +116,22 @@ * various functions that output the usage for this parameter. */ static const gchar decode_as_arg_template[] = "==,"; + 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; } } -- cgit v1.2.3