diff options
author | Guy Harris <guy@alum.mit.edu> | 2004-07-25 08:53:38 +0000 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2004-07-25 08:53:38 +0000 |
commit | 5a3ab160c1f0d7c54b27bf339d0a0e99fecb4878 (patch) | |
tree | bd82ff9fdbe1928ad507cefd67b92ce2816e2b92 | |
parent | 809bd53e813b4cae8c1d9120618a894fd50a25f9 (diff) |
Make some generic print routines that take, as an argument, a pointer to
a structure containing a pointer to print operations for that object and
a pointer to the private subclass-dependent data for that object, with
subclasses for text and PostScript, and use those rather than the old
scheme where a print format was passed as an argument - or where (as in
the case of printing summary information in Tethereal) we just printed
as text even if "-T ps" was selected.
Check whether those routines succeed or get an I/O error writing output.
Clean up indentation.
svn path=/trunk/; revision=11514
-rw-r--r-- | file.c | 108 | ||||
-rw-r--r-- | gtk/follow_dlg.c | 126 | ||||
-rw-r--r-- | print.c | 449 | ||||
-rw-r--r-- | print.h | 49 | ||||
-rw-r--r-- | tethereal.c | 212 |
5 files changed, 677 insertions, 267 deletions
@@ -1495,7 +1495,7 @@ retap_packets(capture_file *cf) typedef struct { print_args_t *print_args; - FILE *print_fh; + print_stream_t *stream; gboolean print_header_line; char *header_line_buf; int header_line_buf_len; @@ -1519,6 +1519,8 @@ print_packet(capture_file *cf, frame_data *fdata, int column_len; int cp_off; gboolean proto_tree_needed; + char bookmark_name[9+10+1]; /* "__frameNNNNNNNNNN__\0" */ + char bookmark_title[6+10+1]; /* "Frame NNNNNNNNNN__\0" */ /* Create the protocol tree, and make it visible, if we're printing the dissection or the hex data. @@ -1536,16 +1538,25 @@ print_packet(capture_file *cf, frame_data *fdata, epan_dissect_run(edt, pseudo_header, pd, fdata, NULL); if (args->print_formfeed) { - print_formfeed(args->print_fh, args->print_args->format); + if (!new_page(args->stream)) + goto fail; } else { - if (args->print_separator) - print_line(args->print_fh, 0, args->print_args->format, ""); + if (args->print_separator) { + if (!print_line(args->stream, 0, "")) + goto fail; + } } + /* + * We generate bookmarks, if the output format supports them. + * The name is "__frameN__". + */ + sprintf(bookmark_name, "__frame%u__", fdata->num); + if (args->print_args->print_summary) { if (args->print_header_line) { - print_line(args->print_fh, 0, args->print_args->format, - args->header_line_buf); + if (!print_line(args->stream, 0, args->header_line_buf)) + goto fail; args->print_header_line = FALSE; /* we might not need to print any more */ } cp = &args->line_buf[0]; @@ -1577,19 +1588,34 @@ print_packet(capture_file *cf, frame_data *fdata, } *cp = '\0'; - print_packet_header(args->print_fh, args->print_args->format, fdata->num, args->line_buf); + /* + * Generate a bookmark, using the summary line as the title. + */ + if (!print_bookmark(args->stream, bookmark_name, args->line_buf)) + goto fail; - print_line(args->print_fh, 0, args->print_args->format, args->line_buf); + if (!print_line(args->stream, 0, args->line_buf)) + goto fail; + } else { + /* + * Generate a bookmark, using "Frame N" as the title, as we're not + * printing the summary line. + */ + sprintf(bookmark_title, "Frame %u", fdata->num); + if (!print_bookmark(args->stream, bookmark_name, bookmark_title)) + goto fail; } /* if (print_summary) */ - + if (args->print_args->print_dissections != print_dissections_none) { if (args->print_args->print_summary) { /* Separate the summary line from the tree with a blank line. */ - print_line(args->print_fh, 0, args->print_args->format, ""); + if (!print_line(args->stream, 0, "")) + goto fail; } /* Print the information in that tree. */ - proto_tree_print(args->print_args, edt, args->print_fh); + if (!proto_tree_print(args->print_args, edt, args->stream)) + goto fail; /* Print a blank line if we print anything after this (aka more than one packet). */ args->print_separator = TRUE; @@ -1600,14 +1626,15 @@ print_packet(capture_file *cf, frame_data *fdata, if (args->print_args->print_hex) { /* Print the full packet data as hex. */ - print_hex_data(args->print_fh, args->print_args->format, edt); + if (!print_hex_data(args->stream, edt)) + goto fail; /* Print a blank line if we print anything after this (aka more than one packet). */ args->print_separator = TRUE; /* Print a header line if we print any more packet summaries */ args->print_header_line = TRUE; - } /* if (print_summary) */ + } /* if (args->print_args->print_dissections != print_dissections_none) */ epan_dissect_free(edt); @@ -1616,7 +1643,11 @@ print_packet(capture_file *cf, frame_data *fdata, args->print_formfeed = TRUE; } - return !ferror(args->print_fh); + return TRUE; + +fail: + epan_dissect_free(edt); + return FALSE; } pp_return_t @@ -1631,19 +1662,37 @@ print_packets(capture_file *cf, print_args_t *print_args) int line_len; psp_return_t ret; - if(print_args->to_file) { - callback_args.print_fh = open_print_dest(print_args->to_file, - print_args->file); - } else { - callback_args.print_fh = open_print_dest(print_args->to_file, - print_args->cmd); + switch (print_args->format) { + + case PR_FMT_TEXT: + if (print_args->to_file) { + callback_args.stream = print_stream_text_new(print_args->to_file, + print_args->file); + } else { + callback_args.stream = print_stream_text_new(print_args->to_file, + print_args->cmd); + } + break; + + case PR_FMT_PS: + if (print_args->to_file) { + callback_args.stream = print_stream_ps_new(print_args->to_file, + print_args->file); + } else { + callback_args.stream = print_stream_ps_new(print_args->to_file, + print_args->cmd); + } + break; + + default: + g_assert_not_reached(); + return PP_OPEN_ERROR; } - if (callback_args.print_fh == NULL) + if (callback_args.stream == NULL) return PP_OPEN_ERROR; /* attempt to open destination failed */ - print_preamble(callback_args.print_fh, print_args->format, cf->filename); - if (ferror(callback_args.print_fh)) { - close_print_dest(print_args->to_file, callback_args.print_fh); + if (!print_preamble(callback_args.stream, cf->filename)) { + destroy_print_stream(callback_args.stream); return PP_WRITE_ERROR; } @@ -1746,18 +1795,17 @@ print_packets(capture_file *cf, print_args_t *print_args) will get printed if we're piping to a print program; we'd have to write to a file and then hand that to the print program to make it actually not print anything. */ - close_print_dest(print_args->to_file, callback_args.print_fh); + destroy_print_stream(callback_args.stream); return PP_WRITE_ERROR; } - print_finale(callback_args.print_fh, print_args->format); - if (ferror(callback_args.print_fh)) { - close_print_dest(print_args->to_file, callback_args.print_fh); + if (!print_finale(callback_args.stream)) { + destroy_print_stream(callback_args.stream); return PP_WRITE_ERROR; } - /* XXX - check for an error */ - close_print_dest(print_args->to_file, callback_args.print_fh); + if (!destroy_print_stream(callback_args.stream)) + return PP_WRITE_ERROR; return PP_OK; } diff --git a/gtk/follow_dlg.c b/gtk/follow_dlg.c index 1fb308edcf..ce695ab82e 100644 --- a/gtk/follow_dlg.c +++ b/gtk/follow_dlg.c @@ -256,33 +256,33 @@ follow_stream_cb(GtkWidget * w, gpointer data _U_) follow_info->streamwindow = streamwindow; gtk_widget_set_name(streamwindow, "TCP stream window"); - gtk_window_set_default_size(GTK_WINDOW(streamwindow), DEF_WIDTH, DEF_HEIGHT); + gtk_window_set_default_size(GTK_WINDOW(streamwindow), DEF_WIDTH, DEF_HEIGHT); gtk_container_border_width(GTK_CONTAINER(streamwindow), 6); /* setup the container */ - tooltips = gtk_tooltips_new (); + tooltips = gtk_tooltips_new (); vbox = gtk_vbox_new(FALSE, 6); gtk_container_add(GTK_CONTAINER(streamwindow), vbox); /* content frame */ if (incomplete_tcp_stream) { - stream_fr = gtk_frame_new("Stream Content (incomplete)"); + stream_fr = gtk_frame_new("Stream Content (incomplete)"); } else { - stream_fr = gtk_frame_new("Stream Content"); + stream_fr = gtk_frame_new("Stream Content"); } gtk_container_add(GTK_CONTAINER(vbox), stream_fr); gtk_widget_show(stream_fr); - stream_vb = gtk_vbox_new(FALSE, 6); + stream_vb = gtk_vbox_new(FALSE, 6); gtk_container_set_border_width( GTK_CONTAINER(stream_vb) , 6); gtk_container_add(GTK_CONTAINER(stream_fr), stream_vb); /* create a scrolled window for the text */ txt_scrollw = scrolled_window_new(NULL, NULL); #if GTK_MAJOR_VERSION >= 2 - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(txt_scrollw), - GTK_SHADOW_IN); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(txt_scrollw), + GTK_SHADOW_IN); #endif gtk_box_pack_start(GTK_BOX(stream_vb), txt_scrollw, TRUE, TRUE, 0); @@ -303,15 +303,15 @@ follow_stream_cb(GtkWidget * w, gpointer data _U_) gtk_box_pack_start(GTK_BOX(stream_vb), hbox, FALSE, FALSE, 0); /* Create Save As Button */ - button = BUTTON_NEW_FROM_STOCK(GTK_STOCK_SAVE_AS); + button = BUTTON_NEW_FROM_STOCK(GTK_STOCK_SAVE_AS); SIGNAL_CONNECT(button, "clicked", follow_save_as_cmd_cb, follow_info); - gtk_tooltips_set_tip (tooltips, button, "Save the content as currently displayed ", NULL); + gtk_tooltips_set_tip (tooltips, button, "Save the content as currently displayed ", NULL); gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); /* Create Print Button */ - button = BUTTON_NEW_FROM_STOCK(GTK_STOCK_PRINT); + button = BUTTON_NEW_FROM_STOCK(GTK_STOCK_PRINT); SIGNAL_CONNECT(button, "clicked", follow_print_stream, follow_info); - gtk_tooltips_set_tip (tooltips, button, "Print the content as currently displayed", NULL); + gtk_tooltips_set_tip (tooltips, button, "Print the content as currently displayed", NULL); gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); /* Stream to show */ @@ -373,8 +373,8 @@ follow_stream_cb(GtkWidget * w, gpointer data _U_) gtk_option_menu_set_menu(GTK_OPTION_MENU(stream_om), stream_menu); /* Set history to 0th item, i.e., the first item. */ gtk_option_menu_set_history(GTK_OPTION_MENU(stream_om), 0); - gtk_tooltips_set_tip (tooltips, stream_om, - "Select the stream direction to display", NULL); + gtk_tooltips_set_tip (tooltips, stream_om, + "Select the stream direction to display", NULL); gtk_box_pack_start(GTK_BOX(hbox), stream_om, FALSE, FALSE, 0); /* ASCII radio button */ @@ -419,24 +419,24 @@ follow_stream_cb(GtkWidget * w, gpointer data _U_) /* button hbox */ button_hbox = gtk_hbutton_box_new(); gtk_box_pack_start(GTK_BOX(vbox), button_hbox, FALSE, FALSE, 0); - gtk_button_box_set_layout (GTK_BUTTON_BOX(button_hbox), GTK_BUTTONBOX_END); - gtk_button_box_set_spacing(GTK_BUTTON_BOX(button_hbox), 5); + gtk_button_box_set_layout (GTK_BUTTON_BOX(button_hbox), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(button_hbox), 5); /* Create exclude stream button */ button = gtk_button_new_with_label("Filter out this stream"); SIGNAL_CONNECT(button, "clicked", follow_filter_out_stream, follow_info); - gtk_tooltips_set_tip (tooltips, button, + gtk_tooltips_set_tip (tooltips, button, "Build a display filter which cuts this stream from the capture", NULL); gtk_box_pack_start(GTK_BOX(button_hbox), button, FALSE, FALSE, 0); /* Create Close Button */ - button = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLOSE); - gtk_tooltips_set_tip (tooltips, button, - "Close the dialog and keep the current display filter", NULL); + button = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLOSE); + gtk_tooltips_set_tip (tooltips, button, + "Close the dialog and keep the current display filter", NULL); gtk_box_pack_start(GTK_BOX(button_hbox), button, FALSE, FALSE, 0); - GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); - window_set_cancel_button(streamwindow, button, window_cancel_button_cb); + window_set_cancel_button(streamwindow, button, window_cancel_button_cb); /* Tuck away the follow_info object into the window */ OBJECT_SET_DATA(streamwindow, E_FOLLOW_INFO_KEY, follow_info); @@ -446,7 +446,7 @@ follow_stream_cb(GtkWidget * w, gpointer data _U_) data_out_file = NULL; - SIGNAL_CONNECT(streamwindow, "delete_event", window_delete_event_cb, NULL); + SIGNAL_CONNECT(streamwindow, "delete_event", window_delete_event_cb, NULL); SIGNAL_CONNECT(streamwindow, "destroy", follow_destroy_cb, NULL); /* Make sure this widget gets destroyed if we quit the main loop, @@ -465,14 +465,14 @@ static void follow_destroy_cb(GtkWidget *w, gpointer data _U_) { follow_info_t *follow_info; - int i; + int i; follow_info = OBJECT_GET_DATA(w, E_FOLLOW_INFO_KEY); i = unlink(follow_info->data_out_filename); - if(i != 0) { - g_warning("Follow: Couldn't remove temporary file: \"%s\", errno: %s (%u)", - follow_info->data_out_filename, strerror(errno), errno); - } + if(i != 0) { + g_warning("Follow: Couldn't remove temporary file: \"%s\", errno: %s (%u)", + follow_info->data_out_filename, strerror(errno), errno); + } g_free(follow_info->filter_out_filter); forget_follow_info(follow_info); g_free(follow_info); @@ -536,8 +536,8 @@ typedef enum { static frs_return_t follow_read_stream(follow_info_t *follow_info, - gboolean (*print_line) (char *, int, gboolean, void *, print_format_e), - void *arg, print_format_e format) + gboolean (*print_line) (char *, int, gboolean, void *), + void *arg) { tcp_stream_chunk sc; int bcount, iplen; @@ -597,7 +597,7 @@ follow_read_stream(follow_info_t *follow_info, case SHOW_EBCDIC: /* If our native arch is ASCII, call: */ EBCDIC_to_ASCII(buffer, nchars); - if (!(*print_line) (buffer, nchars, is_server, arg, format)) + if (!(*print_line) (buffer, nchars, is_server, arg)) goto print_error; break; @@ -605,7 +605,7 @@ follow_read_stream(follow_info_t *follow_info, /* If our native arch is EBCDIC, call: * ASCII_TO_EBCDIC(buffer, nchars); */ - if (!(*print_line) (buffer, nchars, is_server, arg, format)) + if (!(*print_line) (buffer, nchars, is_server, arg)) goto print_error; break; @@ -662,7 +662,7 @@ follow_read_stream(follow_info_t *follow_info, (*global_pos) += i; hexbuf[cur++] = '\n'; hexbuf[cur] = 0; - if (!(*print_line) (hexbuf, strlen(hexbuf), is_server, arg, format)) + if (!(*print_line) (hexbuf, strlen(hexbuf), is_server, arg)) goto print_error; } break; @@ -671,7 +671,7 @@ follow_read_stream(follow_info_t *follow_info, current_pos = 0; g_snprintf(initbuf, 256, "char peer%d_%d[] = {\n", is_server ? 1 : 0, is_server ? server_packet_count++ : client_packet_count++); - if (!(*print_line) (initbuf, strlen(initbuf), is_server, arg, format)) + if (!(*print_line) (initbuf, strlen(initbuf), is_server, arg)) goto print_error; while (current_pos < nchars) { gchar hexbuf[256]; @@ -705,7 +705,7 @@ follow_read_stream(follow_info_t *follow_info, (*global_pos) += i; hexbuf[cur++] = '\n'; hexbuf[cur] = 0; - if (!(*print_line) (hexbuf, strlen(hexbuf), is_server, arg, format)) + if (!(*print_line) (hexbuf, strlen(hexbuf), is_server, arg)) goto print_error; } break; @@ -740,9 +740,9 @@ print_error: * suggestion. */ static gboolean -follow_print_text(char *buffer, int nchars, gboolean is_server _U_, void *arg, print_format_e format) +follow_print_text(char *buffer, int nchars, gboolean is_server _U_, void *arg) { - FILE *fh = arg; + print_stream_t *stream = arg; int i; char *str; @@ -759,7 +759,7 @@ follow_print_text(char *buffer, int nchars, gboolean is_server _U_, void *arg, p str = g_malloc(nchars + 1); memcpy(str, buffer, nchars); str[nchars] = 0; - print_line(fh, /*indent*/ 0, format, str); + print_line(stream, /*indent*/ 0, str); g_free(str); return TRUE; @@ -788,7 +788,7 @@ follow_filter_out_stream(GtkWidget * w _U_, gpointer data) static void follow_print_stream(GtkWidget * w _U_, gpointer data) { - FILE *fh; + print_stream_t *stream; gboolean to_file; char *print_dest; follow_info_t *follow_info = data; @@ -796,7 +796,6 @@ follow_print_stream(GtkWidget * w _U_, gpointer data) gboolean win_printer = FALSE; #endif - switch (prefs.pr_dest) { case PR_DEST_CMD: #ifdef _WIN32 @@ -820,8 +819,21 @@ follow_print_stream(GtkWidget * w _U_, gpointer data) return; } - fh = open_print_dest(to_file, print_dest); - if (fh == NULL) { + switch (prefs.pr_format) { + + case PR_FMT_TEXT: + stream = print_stream_text_new(to_file, print_dest); + break; + + case PR_FMT_PS: + stream = print_stream_ps_new(to_file, print_dest); + break; + + default: + g_assert_not_reached(); + stream = NULL; + } + if (stream == NULL) { if (to_file) { open_failure_alert_box(prefs.pr_file, errno, TRUE); } else { @@ -831,31 +843,29 @@ follow_print_stream(GtkWidget * w _U_, gpointer data) return; } - print_preamble(fh, prefs.pr_format, cfile.filename); - if (ferror(fh)) + if (!print_preamble(stream, cfile.filename)) goto print_error; - switch (follow_read_stream(follow_info, follow_print_text, fh, prefs.pr_format)) { + switch (follow_read_stream(follow_info, follow_print_text, stream)) { case FRS_OK: break; case FRS_OPEN_ERROR: case FRS_READ_ERROR: /* XXX - cancel printing? */ - close_print_dest(to_file, fh); + destroy_print_stream(stream); return; case FRS_PRINT_ERROR: goto print_error; } - print_finale(fh, prefs.pr_format); - if (ferror(fh)) + if (!print_finale(stream)) goto print_error; - if (!close_print_dest(to_file, fh)) { + if (!destroy_print_stream(stream)) { if (to_file) { - write_failure_alert_box(prefs.pr_file, errno); + write_failure_alert_box(prefs.pr_file, errno); } else { - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Error closing print destination."); } } @@ -877,7 +887,7 @@ print_error: "Error writing to print command: %s", strerror(errno)); } /* XXX - cancel printing? */ - close_print_dest(to_file, fh); + destroy_print_stream(stream); #ifdef _WIN32 if (win_printer) { @@ -889,7 +899,7 @@ print_error: static gboolean follow_add_to_gtk_text(char *buffer, int nchars, gboolean is_server, - void *arg, print_format_e format _U_) + void *arg) { GtkWidget *text = arg; GdkColor fg, bg; @@ -964,7 +974,7 @@ follow_load_text(follow_info_t *follow_info) #else gtk_text_buffer_set_text(buf, "", -1); #endif - follow_read_stream(follow_info, follow_add_to_gtk_text, follow_info->text, PR_FMT_TEXT); + follow_read_stream(follow_info, follow_add_to_gtk_text, follow_info->text); #if GTK_MAJOR_VERSION < 2 gtk_text_thaw(GTK_TEXT(follow_info->text)); #endif @@ -1030,6 +1040,7 @@ follow_save_as_ok_cb(GtkWidget * w _U_, gpointer fs) gchar *to_name; follow_info_t *follow_info; FILE *fh; + print_stream_t *stream; gchar *dirname; #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2 @@ -1055,26 +1066,27 @@ follow_save_as_ok_cb(GtkWidget * w _U_, gpointer fs) g_free(to_name); return; } + stream = print_stream_text_stdio_new(fh); gtk_widget_hide(GTK_WIDGET(fs)); follow_info = OBJECT_GET_DATA(fs, E_FOLLOW_INFO_KEY); window_destroy(GTK_WIDGET(fs)); - switch (follow_read_stream(follow_info, follow_print_text, fh, PR_FMT_TEXT)) { + switch (follow_read_stream(follow_info, follow_print_text, stream)) { case FRS_OK: - if (fclose(fh) == EOF) + if (!destroy_print_stream(stream)) write_failure_alert_box(to_name, errno); break; case FRS_OPEN_ERROR: case FRS_READ_ERROR: - fclose(fh); + destroy_print_stream(stream); break; case FRS_PRINT_ERROR: write_failure_alert_box(to_name, errno); - fclose(fh); + destroy_print_stream(stream); break; } @@ -48,12 +48,12 @@ typedef struct { int level; - FILE *fh; + print_stream_t *stream; + gboolean success; GSList *src_list; print_dissections_e print_dissections; gboolean print_hex_for_data; char_enc encoding; - gint format; epan_dissect_t *edt; } print_data; @@ -68,15 +68,16 @@ static void proto_tree_print_node(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 gboolean print_hex_data_buffer(print_stream_t *stream, const guchar *cp, + guint length, char_enc encoding); 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); static void print_pdml_geninfo(proto_tree *tree, FILE *fh); -FILE *open_print_dest(int to_file, const char *dest) +static FILE * +open_print_dest(int to_file, const char *dest) { FILE *fh; @@ -89,7 +90,8 @@ FILE *open_print_dest(int to_file, const char *dest) return fh; } -gboolean close_print_dest(int to_file, FILE *fh) +static gboolean +close_print_dest(int to_file, FILE *fh) { /* Close the file or command */ if (to_file) @@ -100,55 +102,26 @@ gboolean close_print_dest(int to_file, FILE *fh) #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 +gboolean proto_tree_print(print_args_t *print_args, epan_dissect_t *edt, - FILE *fh) + print_stream_t *stream) { print_data data; /* Create the output */ data.level = 0; - data.fh = fh; + data.stream = stream; + data.success = TRUE; 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; - data.format = print_args->format; data.edt = edt; proto_tree_children_foreach(edt->tree, proto_tree_print_node, &data); + return data.success; } #define MAX_INDENT 160 @@ -167,6 +140,10 @@ void proto_tree_print_node(proto_node *node, gpointer data) if (PROTO_ITEM_IS_HIDDEN(node)) return; + /* Give up if we've already gotten an error. */ + if (!pdata->success) + return; + /* was a free format label produced? */ if (fi->rep) { label_ptr = fi->rep->representation; @@ -176,7 +153,10 @@ void proto_tree_print_node(proto_node *node, gpointer data) proto_item_fill_label(fi, label_str); } - print_line(pdata->fh, pdata->level, pdata->format, label_ptr); + if (!print_line(pdata->stream, pdata->level, label_ptr)) { + pdata->success = FALSE; + return; + } /* If it's uninterpreted data, dump it (unless our caller will be printing the entire packet in hex). */ @@ -186,8 +166,11 @@ void proto_tree_print_node(proto_node *node, gpointer data) */ pd = get_field_data(pdata->src_list, fi); if (pd) { - print_hex_data_buffer(pdata->fh, pd, fi->length, - pdata->encoding, pdata->format); + if (!print_hex_data_buffer(pdata->stream, pd, + fi->length, pdata->encoding)) { + pdata->success = FALSE; + return; + } } } @@ -203,29 +186,12 @@ void proto_tree_print_node(proto_node *node, gpointer data) proto_tree_children_foreach(node, proto_tree_print_node, pdata); pdata->level--; + if (!pdata->success) + return; } } } -/* 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; - - default: - g_assert_not_reached(); - } -} - void write_pdml_preamble(FILE *fh) { @@ -640,8 +606,8 @@ write_pdml_field_hex_value(write_pdml_data *pdata, field_info *fi) } } - -void print_hex_data(FILE *fh, print_format_e format, epan_dissect_t *edt) +gboolean +print_hex_data(print_stream_t *stream, epan_dissect_t *edt) { gboolean multiple_sources; GSList *src_le; @@ -666,18 +632,20 @@ void print_hex_data(FILE *fh, print_format_e format, epan_dissect_t *edt) tvb = src->tvb; if (multiple_sources) { name = src->name; - print_line(fh, 0, format, ""); + print_line(stream, 0, ""); line = g_malloc(strlen(name) + 2); /* <name>:\0 */ strcpy(line, name); strcat(line, ":"); - print_line(fh, 0, format, line); + print_line(stream, 0, line); g_free(line); } length = tvb_length(tvb); cp = tvb_get_ptr(tvb, 0, length); - print_hex_data_buffer(fh, cp, length, - edt->pi.fd->flags.encoding, format); + if (!print_hex_data_buffer(stream, cp, length, + edt->pi.fd->flags.encoding)) + return FALSE; } + return TRUE; } /* @@ -702,9 +670,9 @@ void print_hex_data(FILE *fh, print_format_e format, epan_dissect_t *edt) offset, 2 blanks separating offset from data dump, data dump */ -static void -print_hex_data_buffer(FILE *fh, register const guchar *cp, - register guint length, char_enc encoding, print_format_e format) +static gboolean +print_hex_data_buffer(print_stream_t *stream, const guchar *cp, + guint length, char_enc encoding) { register unsigned int ad, i, j, k, l; guchar c; @@ -714,7 +682,8 @@ print_hex_data_buffer(FILE *fh, register const guchar *cp, '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - print_line(fh, 0, format, ""); + if (!print_line(stream, 0, "")) + return FALSE; /* * How many of the leading digits of the offset will we supply? @@ -775,10 +744,12 @@ print_hex_data_buffer(FILE *fh, register const guchar *cp, * and advance the offset. */ line[k] = '\0'; - print_line(fh, 0, format, line); + if (!print_line(stream, 0, line)) + return FALSE; ad += 16; } } + return TRUE; } static @@ -821,6 +792,17 @@ print_packet_header(FILE *fh, print_format_e format, guint32 number, gchar *summ case(PR_FMT_PS): ps_clean_string(psbuffer, summary, MAX_PS_LINE_LENGTH); + /* + * See the Adobe "pdfmark reference". The pdfmark stuff + * tells code that turns PostScript into PDF stuff that + * it should do. + * + * The /OUT stuff creates a bookmark that goes to the + * destination with the name "__frame{N}__", where N is + * the "number" argument, and with "summary" as the title. + * + * The "/DEST" creates the destination. + */ 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); @@ -832,57 +814,300 @@ print_packet_header(FILE *fh, print_format_e format, guint32 number, gchar *summ } } -void -print_formfeed(FILE *fh, print_format_e format) +/* Some formats need stuff at the beginning of the output */ +gboolean +print_preamble(print_stream_t *self, gchar *filename) { - switch (format) { + return (self->ops->print_preamble)(self, filename); +} - case(PR_FMT_TEXT): - fputs("\f", fh); - break; +gboolean +print_line(print_stream_t *self, int indent, const char *line) +{ + return (self->ops->print_line)(self, indent, line); +} - case(PR_FMT_PS): - fputs("formfeed\n", fh); - break; +/* Insert bookmark */ +gboolean +print_bookmark(print_stream_t *self, const gchar *name, const gchar *title) +{ + return (self->ops->print_bookmark)(self, name, title); +} - default: - g_assert_not_reached(); +gboolean +new_page(print_stream_t *self) +{ + return (self->ops->new_page)(self); +} + +/* Some formats need stuff at the end of the output */ +gboolean +print_finale(print_stream_t *self) +{ + return (self->ops->print_finale)(self); +} + +gboolean +destroy_print_stream(print_stream_t *self) +{ + return (self->ops->destroy)(self); +} + +typedef struct { + int to_file; + FILE *fh; +} output_text; + +static gboolean +print_preamble_text(print_stream_t *self _U_, gchar *filename _U_) +{ + /* do nothing */ + return TRUE; /* always succeeds */ +} + +static gboolean +print_line_text(print_stream_t *self, int indent, const char *line) +{ + output_text *output = self->data; + char space[MAX_INDENT+1]; + int i; + int num_spaces; + + /* Prepare the tabs for printing, depending on tree level */ + num_spaces = indent * 4; + if (num_spaces > MAX_INDENT) { + num_spaces = MAX_INDENT; } + for (i = 0; i < num_spaces; i++) { + space[i] = ' '; + } + /* The string is NUL-terminated */ + space[num_spaces] = '\0'; + + fputs(space, output->fh); + fputs(line, output->fh); + putc('\n', output->fh); + return !ferror(output->fh); } -void -print_line(FILE *fh, int indent, print_format_e format, char *line) +static gboolean +print_bookmark_text(print_stream_t *self _U_, const gchar *name _U_, + const gchar *title _U_) { - char space[MAX_INDENT+1]; - int i; - int num_spaces; + /* do nothing */ + return TRUE; +} + +static gboolean +new_page_text(print_stream_t *self) +{ + output_text *output = self->data; + + fputs("\f", output->fh); + return !ferror(output->fh); +} + +static gboolean +print_finale_text(print_stream_t *self _U_) +{ + /* do nothing */ + return TRUE; /* always succeeds */ +} + +static gboolean +destroy_text(print_stream_t *self) +{ + output_text *output = 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 = { + print_preamble_text, + print_line_text, + print_bookmark_text, + new_page_text, + print_finale_text, + destroy_text +}; + +print_stream_t * +print_stream_text_new(int to_file, const char *dest) +{ + FILE *fh; + print_stream_t *stream; + output_text *output; + + fh = open_print_dest(to_file, dest); + if (fh == NULL) + return NULL; + + output = g_malloc(sizeof *output); + output->to_file = to_file; + output->fh = fh; + stream = g_malloc(sizeof (print_stream_t)); + stream->ops = &print_text_ops; + stream->data = output; + + return stream; +} + +print_stream_t * +print_stream_text_stdio_new(FILE *fh) +{ + print_stream_t *stream; + output_text *output; + + output = g_malloc(sizeof *output); + output->to_file = TRUE; + output->fh = fh; + stream = g_malloc(sizeof (print_stream_t)); + stream->ops = &print_text_ops; + stream->data = output; + + return stream; +} + +typedef struct { + int to_file; + FILE *fh; +} output_ps; + +static gboolean +print_preamble_ps(print_stream_t *self, gchar *filename) +{ + output_ps *output = self->data; char psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */ - switch (format) { + print_ps_preamble(output->fh); - case(PR_FMT_TEXT): - /* Prepare the tabs for printing, depending on tree level */ - num_spaces = indent * 4; - if (num_spaces > MAX_INDENT) { - num_spaces = MAX_INDENT; - } - for (i = 0; i < num_spaces; i++) { - space[i] = ' '; - } - /* The string is NUL-terminated */ - space[num_spaces] = '\0'; + fputs("%% Set the font to 10 point\n", output->fh); + fputs("/Courier findfont 10 scalefont setfont\n", output->fh); + fputs("\n", output->fh); + fputs("%% the page title\n", output->fh); + ps_clean_string(psbuffer, filename, MAX_PS_LINE_LENGTH); + fprintf(output->fh, "/eth_pagetitle (%s - Ethereal) def\n", psbuffer); + fputs("\n", output->fh); + return !ferror(output->fh); +} - fputs(space, fh); - fputs(line, fh); - putc('\n', fh); - break; +static gboolean +print_line_ps(print_stream_t *self, int indent, const char *line) +{ + output_ps *output = self->data; + char psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */ - case(PR_FMT_PS): - ps_clean_string(psbuffer, line, MAX_PS_LINE_LENGTH); - fprintf(fh, "%d (%s) putline\n", indent, psbuffer); - break; + ps_clean_string(psbuffer, line, MAX_PS_LINE_LENGTH); + fprintf(output->fh, "%d (%s) putline\n", indent, psbuffer); + return !ferror(output->fh); +} - default: - g_assert_not_reached(); - } +static gboolean +print_bookmark_ps(print_stream_t *self, const gchar *name, const gchar *title) +{ + output_ps *output = 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 = self->data; + + fputs("formfeed\n", output->fh); + return !ferror(output->fh); +} + +static gboolean +print_finale_ps(print_stream_t *self) +{ + output_ps *output = self->data; + + print_ps_finale(output->fh); + return !ferror(output->fh); +} + +static gboolean +destroy_ps(print_stream_t *self) +{ + output_ps *output = 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 +}; + +print_stream_t * +print_stream_ps_new(int to_file, const char *dest) +{ + FILE *fh; + print_stream_t *stream; + output_ps *output; + + fh = open_print_dest(to_file, dest); + if (fh == NULL) + return NULL; + + output = g_malloc(sizeof *output); + output->to_file = to_file; + output->fh = fh; + stream = g_malloc(sizeof (print_stream_t)); + stream->ops = &print_ps_ops; + stream->data = output; + + return stream; +} + +print_stream_t * +print_stream_ps_stdio_new(FILE *fh) +{ + print_stream_t *stream; + output_ps *output; + + output = g_malloc(sizeof *output); + output->to_file = TRUE; + output->fh = fh; + stream = g_malloc(sizeof (print_stream_t)); + stream->ops = &print_ps_ops; + stream->data = output; + + return stream; } @@ -52,7 +52,7 @@ typedef enum { } print_dissections_e; typedef struct { - print_format_e format; /* plain text, PostScript, PDML, ... */ + print_format_e format; /* plain text or PostScript */ gboolean to_file; /* TRUE if we're printing to a file */ char *file; /* file output pathname */ char *cmd; /* print command string (not win32) */ @@ -69,21 +69,48 @@ typedef struct { /* Functions in print.h */ -extern FILE *open_print_dest(int to_file, const char *dest); -extern gboolean close_print_dest(int to_file, FILE *fh); -extern void print_preamble(FILE *fh, print_format_e format, gchar *filename); -extern void print_packet_header(FILE *fh, print_format_e format, guint32 number, gchar *summary); -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); + +struct print_stream; + +typedef struct print_stream_ops { + gboolean (*print_preamble)(struct print_stream *self, gchar *filename); + 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; + +extern gboolean proto_tree_print(print_args_t *print_args, epan_dissect_t *edt, + print_stream_t *stream); +extern gboolean print_hex_data(print_stream_t *stream, epan_dissect_t *edt); +extern void print_packet_header(FILE *fh, print_format_e format, guint32 number, gchar *summary); + +extern print_stream_t *print_stream_text_new(int to_file, const char *dest); +extern print_stream_t *print_stream_text_stdio_new(FILE *fh); +extern print_stream_t *print_stream_ps_new(int to_file, const char *dest); +extern print_stream_t *print_stream_ps_stdio_new(FILE *fh); + +extern gboolean print_preamble(print_stream_t *self, gchar *filename); +extern gboolean print_line(print_stream_t *self, int indent, const char *line); +extern gboolean print_bookmark(print_stream_t *self, const gchar *name, + const gchar *title); +extern gboolean new_page(print_stream_t *self); +extern gboolean print_finale(print_stream_t *self); +extern gboolean destroy_print_stream(print_stream_t *self); #endif /* print.h */ diff --git a/tethereal.c b/tethereal.c index 3c1384adb9..b6dcab2e34 100644 --- a/tethereal.c +++ b/tethereal.c @@ -137,7 +137,8 @@ static gboolean verbose; static gboolean print_hex; static gboolean line_buffered; static guint32 cum_bytes = 0; -static print_format_e print_format; +static print_format_e print_format = PR_FMT_TEXT; +static print_stream_t *print_stream; #ifdef HAVE_LIBPCAP typedef struct _loop_data { @@ -184,9 +185,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 gboolean write_preamble(capture_file *cf); +static gboolean print_packet(capture_file *cf, epan_dissect_t *edt); +static gboolean write_finale(void); static char *cf_open_error_message(int err, gchar *err_info, gboolean for_writing, int file_type); #ifdef HAVE_LIBPCAP @@ -1223,21 +1224,21 @@ main(int argc, char *argv[]) break; case 'T': /* printing Type */ if (strcmp(optarg, "text") == 0) { - output_action = WRITE_TEXT; - print_format = PR_FMT_TEXT; + output_action = WRITE_TEXT; + print_format = PR_FMT_TEXT; } else if (strcmp(optarg, "ps") == 0) { - output_action = WRITE_TEXT; - print_format = PR_FMT_PS; + output_action = WRITE_TEXT; + print_format = PR_FMT_PS; } else if (strcmp(optarg, "pdml") == 0) { - output_action = WRITE_XML; - verbose = TRUE; + output_action = WRITE_XML; + verbose = TRUE; } else if (strcmp(optarg, "psml") == 0) { - output_action = WRITE_XML; - verbose = FALSE; + output_action = WRITE_XML; + verbose = FALSE; } else { - fprintf(stderr, "tethereal: Invalid -T parameter.\n"); - fprintf(stderr, "It must be \"ps\", \"text\", \"pdml\", or \"psml\".\n"); - exit(1); + fprintf(stderr, "tethereal: Invalid -T parameter.\n"); + fprintf(stderr, "It must be \"ps\", \"text\", \"pdml\", or \"psml\".\n"); + exit(1); } break; case 'v': /* Show version and exit */ @@ -1528,6 +1529,26 @@ main(int argc, char *argv[]) } cfile.rfcode = rfcode; + if (print_packet_info) { + /* If we're printing as text or PostScript, we have + to create a print stream. */ + if (output_action == WRITE_TEXT) { + switch (print_format) { + + case PR_FMT_TEXT: + print_stream = print_stream_text_stdio_new(stdout); + break; + + case PR_FMT_PS: + print_stream = print_stream_ps_stdio_new(stdout); + break; + + default: + g_assert_not_reached(); + } + } + } + /* We have to dissect each packet if: we're printing information about each packet; @@ -2344,8 +2365,7 @@ load_cap_file(capture_file *cf, int out_file_type) goto out; } } else { - write_preamble(cf); - if (ferror(stdout)) { + if (!write_preamble(cf)) { err = errno; show_print_file_io_error(err); goto out; @@ -2407,8 +2427,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 { - write_finale(); - if (ferror(stdout)) { + if (!write_finale()) { err = errno; show_print_file_io_error(err); } @@ -2671,13 +2690,13 @@ show_capture_file_io_error(const char *fname, int err, gboolean is_close) } } -static void +static gboolean write_preamble(capture_file *cf) { switch (output_action) { case WRITE_TEXT: - print_preamble(stdout, print_format, cf->filename); + return print_preamble(print_stream, cf->filename); break; case WRITE_XML: @@ -2685,15 +2704,29 @@ write_preamble(capture_file *cf) write_pdml_preamble(stdout); else write_psml_preamble(stdout); - break; + return !ferror(stdout); + + default: + g_assert_not_reached(); + return FALSE; } } -static void +static gboolean print_columns(capture_file *cf) { + static char *line_bufp = NULL; + static size_t line_buf_len = 0; int i; + size_t buf_offset; + size_t column_len; + if (line_bufp == NULL) { + line_buf_len = 256; + line_bufp = g_malloc(line_buf_len + 1); + } + buf_offset = 0; + *line_bufp = '\0'; for (i = 0; i < cf->cinfo.num_cols; i++) { switch (cf->cinfo.col_fmt[i]) { case COL_NUMBER: @@ -2710,14 +2743,28 @@ print_columns(capture_file *cf) */ if (cf->iface != NULL) continue; - printf("%3s", cf->cinfo.col_data[i]); + column_len = strlen(cf->cinfo.col_data[i]); + if (column_len < 3) + column_len = 3; + if (buf_offset + column_len > line_buf_len) { + line_buf_len *= 2; + line_bufp = g_realloc(line_bufp, line_buf_len + 1); + } + snprintf(line_bufp + buf_offset, COL_MAX_LEN+1, "%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]); + column_len = strlen(cf->cinfo.col_data[i]); + if (column_len < 10) + column_len = 10; + if (buf_offset + column_len > line_buf_len) { + line_buf_len *= 2; + line_bufp = g_realloc(line_bufp, line_buf_len + 1); + } + snprintf(line_bufp + buf_offset, COL_MAX_LEN+1, "%10s", cf->cinfo.col_data[i]); break; case COL_DEF_SRC: @@ -2729,7 +2776,14 @@ print_columns(capture_file *cf) case COL_DEF_NET_SRC: case COL_RES_NET_SRC: case COL_UNRES_NET_SRC: - printf("%12s", cf->cinfo.col_data[i]); + column_len = strlen(cf->cinfo.col_data[i]); + if (column_len < 12) + column_len = 12; + if (buf_offset + column_len > line_buf_len) { + line_buf_len *= 2; + line_bufp = g_realloc(line_bufp, line_buf_len + 1); + } + snprintf(line_bufp + buf_offset, COL_MAX_LEN+1, "%12s", cf->cinfo.col_data[i]); break; case COL_DEF_DST: @@ -2741,13 +2795,26 @@ print_columns(capture_file *cf) case COL_DEF_NET_DST: case COL_RES_NET_DST: case COL_UNRES_NET_DST: - printf("%-12s", cf->cinfo.col_data[i]); + column_len = strlen(cf->cinfo.col_data[i]); + if (column_len < 12) + column_len = 12; + if (buf_offset + column_len > line_buf_len) { + line_buf_len *= 2; + line_bufp = g_realloc(line_bufp, line_buf_len + 1); + } + snprintf(line_bufp + buf_offset, COL_MAX_LEN+1, "%-12s", cf->cinfo.col_data[i]); break; default: - printf("%s", cf->cinfo.col_data[i]); + column_len = strlen(cf->cinfo.col_data[i]); + if (buf_offset + column_len > line_buf_len) { + line_buf_len *= 2; + line_bufp = g_realloc(line_bufp, line_buf_len + 1); + } + strcat(line_bufp + buf_offset, cf->cinfo.col_data[i]); break; } + buf_offset += column_len; if (i != cf->cinfo.num_cols - 1) { /* * This isn't the last column, so we need to print a @@ -2759,7 +2826,14 @@ print_columns(capture_file *cf) * and are printing a network source of the same type * next, separate them with "<-"; otherwise separate them * with a space. + * + * We add enough space to the buffer for " <- " or " -> ", + * even if we're only adding " ". */ + if (buf_offset + 4 > line_buf_len) { + line_buf_len *= 2; + line_bufp = g_realloc(line_bufp, line_buf_len + 1); + } switch (cf->cinfo.col_fmt[i]) { case COL_DEF_SRC: @@ -2770,11 +2844,13 @@ print_columns(capture_file *cf) case COL_DEF_DST: case COL_RES_DST: case COL_UNRES_DST: - printf(" -> "); + strcat(line_bufp + buf_offset, " -> "); + buf_offset += 4; break; default: - putchar(' '); + strcat(line_bufp + buf_offset, " "); + buf_offset += 1; break; } break; @@ -2787,11 +2863,13 @@ print_columns(capture_file *cf) case COL_DEF_DL_DST: case COL_RES_DL_DST: case COL_UNRES_DL_DST: - printf(" -> "); + strcat(line_bufp + buf_offset, " -> "); + buf_offset += 4; break; default: - putchar(' '); + strcat(line_bufp + buf_offset, " "); + buf_offset += 1; break; } break; @@ -2804,11 +2882,13 @@ print_columns(capture_file *cf) case COL_DEF_NET_DST: case COL_RES_NET_DST: case COL_UNRES_NET_DST: - printf(" -> "); + strcat(line_bufp + buf_offset, " -> "); + buf_offset += 4; break; default: - putchar(' '); + strcat(line_bufp + buf_offset, " "); + buf_offset += 1; break; } break; @@ -2821,11 +2901,13 @@ print_columns(capture_file *cf) case COL_DEF_SRC: case COL_RES_SRC: case COL_UNRES_SRC: - printf(" <- "); + strcat(line_bufp + buf_offset, " <- "); + buf_offset += 4; break; default: - putchar(' '); + strcat(line_bufp + buf_offset, " "); + buf_offset += 1; break; } break; @@ -2838,11 +2920,13 @@ print_columns(capture_file *cf) case COL_DEF_DL_SRC: case COL_RES_DL_SRC: case COL_UNRES_DL_SRC: - printf(" <- "); + strcat(line_bufp + buf_offset, " <- "); + buf_offset += 4; break; default: - putchar(' '); + strcat(line_bufp + buf_offset, " "); + buf_offset += 1; break; } break; @@ -2855,25 +2939,28 @@ print_columns(capture_file *cf) case COL_DEF_NET_SRC: case COL_RES_NET_SRC: case COL_UNRES_NET_SRC: - printf(" <- "); + strcat(line_bufp + buf_offset, " <- "); + buf_offset += 4; break; default: - putchar(' '); + strcat(line_bufp + buf_offset, " "); + buf_offset += 1; break; } break; default: - putchar(' '); + strcat(line_bufp + buf_offset, " "); + buf_offset += 1; break; } } } - putchar('\n'); + return print_line(print_stream, 0, line_bufp); } -static void +static gboolean print_packet(capture_file *cf, epan_dissect_t *edt) { print_args_t print_args; @@ -2893,18 +2980,21 @@ print_packet(capture_file *cf, epan_dissect_t *edt) /* init the packet range */ packet_range_init(&print_args.range); - proto_tree_print(&print_args, edt, stdout); + if (!proto_tree_print(&print_args, edt, print_stream)) + return FALSE; + 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. */ + if (!print_line(print_stream, 0, "")) + return FALSE; + } 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"); + return !ferror(stdout); } } else { /* Just fill in the columns. */ @@ -2914,27 +3004,31 @@ print_packet(capture_file *cf, epan_dissect_t *edt) switch (output_action) { case WRITE_TEXT: - print_columns(cf); + if (!print_columns(cf)) + return FALSE; break; case WRITE_XML: proto_tree_write_psml(edt, stdout); - break; + return !ferror(stdout); } } if (print_hex) { - print_hex_data(stdout, print_format, edt); - putchar('\n'); + if (!print_hex_data(print_stream, edt)) + return FALSE; + if (!print_line(print_stream, 0, "")) + return FALSE; } + return TRUE; } -static void +static gboolean write_finale(void) { switch (output_action) { case WRITE_TEXT: - print_finale(stdout, print_format); + return print_finale(print_stream); break; case WRITE_XML: @@ -2942,7 +3036,11 @@ write_finale(void) write_pdml_finale(stdout); else write_psml_finale(stdout); - break; + return !ferror(stdout); + + default: + g_assert_not_reached(); + return FALSE; } } |