aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--file.c71
-rw-r--r--file.h9
-rw-r--r--gtk/main.h7
-rw-r--r--gtk/menu.c3
-rw-r--r--gtk/print_dlg.c64
-rw-r--r--print.c31
-rw-r--r--print.h4
7 files changed, 187 insertions, 2 deletions
diff --git a/file.c b/file.c
index 9858f86ecf..d38c2d8973 100644
--- a/file.c
+++ b/file.c
@@ -2115,6 +2115,77 @@ cf_write_psml_packets(capture_file *cf, print_args_t *print_args)
return CF_PRINT_OK;
}
+static gboolean
+write_csv_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);
+ epan_dissect_fill_in_columns(edt);
+
+ /* Write out the information in that tree. */
+ proto_tree_write_csv(edt, fh);
+
+ epan_dissect_free(edt);
+
+ return !ferror(fh);
+}
+
+cf_print_status_t
+cf_write_csv_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 CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
+
+ write_csv_preamble(fh);
+ if (ferror(fh)) {
+ fclose(fh);
+ return CF_PRINT_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 CSV",
+ "selected packets", write_csv_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 CF_PRINT_WRITE_ERROR;
+ }
+
+ write_csv_finale(fh);
+ if (ferror(fh)) {
+ fclose(fh);
+ return CF_PRINT_WRITE_ERROR;
+ }
+
+ /* XXX - check for an error */
+ fclose(fh);
+
+ return CF_PRINT_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 bb120049e7..00c35cf9b1 100644
--- a/file.h
+++ b/file.h
@@ -297,6 +297,15 @@ cf_print_status_t cf_write_pdml_packets(capture_file *cf, print_args_t *print_ar
cf_print_status_t cf_write_psml_packets(capture_file *cf, print_args_t *print_args);
/**
+ * Print (export) the capture file into CSV format.
+ *
+ * @param cf the capture file
+ * @param print_args the arguments what and how to export
+ * @return one of cf_print_status_t
+ */
+cf_print_status_t cf_write_csv_packets(capture_file *cf, print_args_t *print_args);
+
+/**
* Find Packet in protocol tree.
*
* @param cf the capture file
diff --git a/gtk/main.h b/gtk/main.h
index e3a0b2cfb7..21376493d8 100644
--- a/gtk/main.h
+++ b/gtk/main.h
@@ -180,6 +180,13 @@ extern void export_psml_cmd_cb(GtkWidget *widget, gpointer data);
*/
extern void export_pdml_cmd_cb(GtkWidget *widget, gpointer data);
+/** User requested "Export as CSV" by menu.
+ *
+ * @param widget parent widget (unused)
+ * @param data unused
+ */
+extern void export_csv_cmd_cb(GtkWidget *widget, gpointer data);
+
/** User requested "Expand Tree" by menu.
*
* @param widget parent widget (unused)
diff --git a/gtk/menu.c b/gtk/menu.c
index 5ed63c6bab..61bc3a68c8 100644
--- a/gtk/menu.c
+++ b/gtk/menu.c
@@ -182,6 +182,9 @@ static GtkItemFactoryEntry menu_items[] =
0, NULL, NULL),
ITEM_FACTORY_ENTRY("/File/Export/as \"_PostScript\" file...", NULL, export_ps_cmd_cb,
0, NULL, NULL),
+ ITEM_FACTORY_ENTRY("/File/Export/as \"_CSV\" (Comma Separated Values packet summary) file...",
+ NULL, export_csv_cmd_cb, 0, NULL, NULL),
+ ITEM_FACTORY_ENTRY("/File/Export/<separator>", NULL, NULL, 0, "<Separator>", NULL),
ITEM_FACTORY_ENTRY("/File/Export/as XML - \"P_SML\" (packet summary) file...", NULL, export_psml_cmd_cb,
0, NULL, NULL),
ITEM_FACTORY_ENTRY("/File/Export/as XML - \"P_DML\" (packet details) file...", NULL, export_pdml_cmd_cb,
diff --git a/gtk/print_dlg.c b/gtk/print_dlg.c
index 2856bf8cc8..390997d765 100644
--- a/gtk/print_dlg.c
+++ b/gtk/print_dlg.c
@@ -57,7 +57,8 @@ typedef enum {
output_action_export_text, /* export to plain text */
output_action_export_ps, /* export to postscript */
output_action_export_psml, /* export to packet summary markup language */
- output_action_export_pdml /* export to packet data markup language */
+ output_action_export_pdml, /* export to packet data markup language */
+ output_action_export_csv /* export to csv file */
} output_action_e;
@@ -84,6 +85,7 @@ static void print_destroy_cb(GtkWidget *win, gpointer user_data);
#define PRINT_PS_RB_KEY "printer_ps_radio_button"
#define PRINT_PDML_RB_KEY "printer_pdml_radio_button"
#define PRINT_PSML_RB_KEY "printer_psml_radio_button"
+#define PRINT_CSV_RB_KEY "printer_csv_radio_button"
#define PRINT_DEST_CB_KEY "printer_destination_check_button"
#define PRINT_SUMMARY_CB_KEY "printer_summary_check_button"
@@ -333,6 +335,47 @@ export_pdml_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
SIGNAL_CONNECT(export_pdml_win, "destroy", print_destroy_cb, &export_pdml_win);
}
+/*
+ * Keep a static pointer to the current "Export csv" window, if any, so that if
+ * somebody tries to do "File:Export to CSV" while there's already a "Export csv" window
+ * up, we just pop up the existing one, rather than creating a new one.
+ */
+static GtkWidget *export_csv_win = NULL;
+
+static print_args_t export_csv_args;
+
+static gboolean export_csv_prefs_init = FALSE;
+
+void
+export_csv_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
+{
+ print_args_t *args = &export_csv_args;
+
+ if (export_csv_win != NULL) {
+ /* There's already a "Export csv" dialog box; reactivate it. */
+ reactivate_window(export_csv_win);
+ return;
+ }
+
+ /* get settings from preferences (and other initial values) only once */
+ if(export_csv_prefs_init == FALSE) {
+ export_csv_prefs_init = TRUE;
+ args->format = PR_FMT_TEXT; /* XXX */
+ args->to_file = TRUE;
+ args->file = g_strdup("");
+ args->cmd = g_strdup("");
+ args->print_summary = FALSE;
+ args->print_dissections = print_dissections_none;
+ args->print_hex = FALSE;
+ args->print_formfeed = FALSE;
+ }
+
+ /* init the printing range */
+ packet_range_init(&args->range);
+
+ export_csv_win = open_print_dialog("Ethereal: Export as \"Comma Separated Values\" File", output_action_export_csv, args);
+ SIGNAL_CONNECT(export_csv_win, "destroy", print_destroy_cb, &export_csv_win);
+}
static void
print_browse_file_cb(GtkWidget *file_bt, GtkWidget *file_te)
@@ -355,7 +398,7 @@ open_print_dialog(char *title, output_action_e action, print_args_t *args)
GtkWidget *main_vb;
GtkWidget *printer_fr, *printer_vb, *export_format_lb;
- GtkWidget *text_rb, *ps_rb, *pdml_rb, *psml_rb;
+ GtkWidget *text_rb, *ps_rb, *pdml_rb, *psml_rb, *csv_rb;
GtkWidget *printer_tb, *dest_cb;
#ifndef _WIN32
GtkWidget *cmd_lb, *cmd_te;
@@ -448,6 +491,16 @@ open_print_dialog(char *title, output_action_e action, print_args_t *args)
gtk_box_pack_start(GTK_BOX(printer_vb), psml_rb, FALSE, FALSE, 0);
/* gtk_widget_show(psml_rb); */
+ csv_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(text_rb, "_CSV", accel_group);
+ if (action == output_action_export_csv)
+ gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(csv_rb), TRUE);
+ gtk_tooltips_set_tip (tooltips, csv_rb,
+ "Print output in \"Comma Separated Values\" (CSV) format, "
+ "a text format compatible with OpenOffice and Excel. "
+ "One row for each packet, with its timestamp and size.", NULL);
+ gtk_box_pack_start(GTK_BOX(printer_vb), csv_rb, FALSE, FALSE, 0);
+ /* gtk_widget_show(csv_rb); */
+
/* printer table */
#ifndef _WIN32
printer_tb = gtk_table_new(2, 3, FALSE);
@@ -653,6 +706,7 @@ open_print_dialog(char *title, output_action_e action, print_args_t *args)
OBJECT_SET_DATA(ok_bt, PRINT_PS_RB_KEY, ps_rb);
OBJECT_SET_DATA(ok_bt, PRINT_PDML_RB_KEY, pdml_rb);
OBJECT_SET_DATA(ok_bt, PRINT_PSML_RB_KEY, psml_rb);
+ OBJECT_SET_DATA(ok_bt, PRINT_CSV_RB_KEY, csv_rb);
OBJECT_SET_DATA(ok_bt, PRINT_DEST_CB_KEY, dest_cb);
#ifndef _WIN32
OBJECT_SET_DATA(ok_bt, PRINT_CMD_TE_KEY, cmd_te);
@@ -766,6 +820,7 @@ print_ok_cb(GtkWidget *ok_bt, gpointer parent_w)
gchar *f_name;
gchar *dirname;
gboolean export_as_pdml = FALSE, export_as_psml = FALSE;
+ gboolean export_as_csv = FALSE;
#ifdef _WIN32
gboolean win_printer = FALSE;
#endif
@@ -823,6 +878,9 @@ print_ok_cb(GtkWidget *ok_bt, gpointer parent_w)
button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_PSML_RB_KEY);
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button)))
export_as_psml = TRUE;
+ button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_CSV_RB_KEY);
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button)))
+ export_as_csv = TRUE;
button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_SUMMARY_CB_KEY);
args->print_summary = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button));
@@ -860,6 +918,8 @@ print_ok_cb(GtkWidget *ok_bt, gpointer parent_w)
status = cf_write_pdml_packets(&cfile, args);
else if (export_as_psml)
status = cf_write_psml_packets(&cfile, args);
+ else if (export_as_csv)
+ status = cf_write_csv_packets(&cfile, args);
else {
switch (args->format) {
diff --git a/print.c b/print.c
index 9c5f8f0f63..6c45b040d2 100644
--- a/print.c
+++ b/print.c
@@ -513,6 +513,37 @@ write_psml_finale(FILE *fh)
fputs("</psml>\n", fh);
}
+void
+write_csv_preamble(FILE *fh _U_)
+{
+
+}
+
+void
+proto_tree_write_csv(epan_dissect_t *edt, FILE *fh)
+{
+ gint i;
+
+ /* if this is the first packet, we have to write the CSV header */
+ if(edt->pi.fd->num == 1) {
+ for(i=0; i < edt->pi.cinfo->num_cols - 1; i++)
+ fprintf(fh, "\"%s\", ", edt->pi.cinfo->col_title[i]);
+
+ fprintf(fh, "\"%s\"\n", edt->pi.cinfo->col_title[i]);
+ }
+
+ for(i=0; i < edt->pi.cinfo->num_cols - 1; i++)
+ fprintf(fh, "\"%s\", ", edt->pi.cinfo->col_data[i]);
+
+ fprintf(fh, "\"%s\"\n", edt->pi.cinfo->col_data[i]);
+}
+
+void
+write_csv_finale(FILE *fh _U_)
+{
+
+}
+
/*
* 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.
diff --git a/print.h b/print.h
index a0871fb47b..1325e03be7 100644
--- a/print.h
+++ b/print.h
@@ -121,4 +121,8 @@ 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 write_csv_preamble(FILE *fh);
+extern void proto_tree_write_csv(epan_dissect_t *edt, FILE *fh);
+extern void write_csv_finale(FILE *fh);
+
#endif /* print.h */