Ethereal-dev: [Ethereal-dev] [PATCH] export data as CSV for iostat

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: francesco fondelli <fondelli.francesco@xxxxxxxxxx>
Date: Fri, 29 Oct 2004 11:47:39 +0200
Hi all,

I needed a way to plot rate graph nicer than IO-Stat does, so I
wrote a patch that exports data in a CSV formatted file. So we can now
plot an io graph using gnuplot, Excel...
I tested the patch against the svn version of ethereal, compiled for
GNU/Linux with gtk2. Hope this is useful for someone else.

I tried to follow Ronnie Sahlberg's coding style for names and
indentation.

Please find attached the "svn-diffed" patch.

Ciao
FF

Index: AUTHORS
===================================================================
--- AUTHORS	(revision 12430)
+++ AUTHORS	(working copy)
@@ -2226,6 +2226,7 @@
 
 Francesco Fondelli	<fondelli.francesco [AT] tiscali.it> {
 	ICE protocol support
+	IO-Stat: added support for data export as csv
 }
 
 
Index: gtk/io_stat.c
===================================================================
--- gtk/io_stat.c	(revision 12430)
+++ gtk/io_stat.c	(working copy)
@@ -1,6 +1,8 @@
 /* io_stat.c
  * io_stat   2002 Ronnie Sahlberg
  *
+ * Francesco Fondelli (_FF_), 28-Oct-2004, added support for data export as csv.
+ * 
  * $Id$
  *
  * Ethereal - Network traffic analyzer
@@ -149,6 +151,7 @@
 	GdkPixmap *pixmap;
 	GtkAdjustment *scrollbar_adjustment;
 	GtkWidget *scrollbar;
+	GtkWidget *save_as_w;
 	int pixmap_width;
 	int pixmap_height;
 	int pixels_per_tick;
@@ -1064,6 +1067,7 @@
 	io->pixmap=NULL;
 	io->scrollbar=NULL;
 	io->scrollbar_adjustment=NULL;
+	io->save_as_w=NULL;
 	io->pixmap_width=500;
 	io->pixmap_height=200;
     io->pixels_per_tick=pixels_per_tick[DEFAULT_PIXELS_PER_TICK];
@@ -1864,13 +1868,170 @@
 	return;
 }
 
+/* based on file_dlg.c code */
+static void 
+iostat_save_as_ok_cb(GtkWidget *bt _U_, gpointer data _U_)
+{
+  	io_stat_t *io = (io_stat_t *)data;
+	gchar	*csvf_name;
+	FILE *fp;
+	gint32 i, j; 
+	gint32 lastgraph = -1;
+	gchar *filter;
+	gchar *field;
+	
+#if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
+	csvf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(io->save_as_w)));
+#else
+	csvf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(io->save_as_w)));
+#endif
+	
+	/* check whether the user specified a directory instead of a file */
+	if (test_for_directory(csvf_name) == EISDIR) {
+	  	/* It's a directory - set the file selection box to display that
+		   directory, and leave the selection box displayed. */
+	  	set_last_open_dir(csvf_name);
+		g_free(csvf_name);
+		file_selection_set_current_folder(io->save_as_w, get_last_open_dir());
+		return;
+	}
+	
+	/* it was a file, open it */
+	if ((fp = fopen(csvf_name, "w+")) == NULL) {
+	  	simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+			      "Could not open\n%s\nfor writing: %s.",
+			      csvf_name, strerror(errno));
+		g_free(csvf_name);
+		return;
+	}
+	
+	/* print file header */
+	
+	fprintf(fp, "################################################################################\n");
+	fprintf(fp, "# CSV file exported by Ethereal->Statistics->IO Graphs\n");
+	/* XXX to do: add Start/End time lines, i.e. the abs arrival time of the first and last pkt 
+	   to let the user easily remember when the measure has been taken.
+	   And maybe a line telling which interface the traffic has been sniffed from.
+	*/
+	fprintf(fp, "# Y Unit: %s\n", count_type_names[io->count_type]);
+	fprintf(fp, "# X Tick Interval: %dms\n", io->interval);
+	for( i = 0; i < MAX_GRAPHS; i++ )
+		if(io->graphs[i].display) {
+			
+			filter = (char *)gtk_entry_get_text(GTK_ENTRY(io->graphs[i].filter_field));
+			fprintf(fp, "# Graph%d: %s", i + 1, 
+				((filter==NULL) || (filter[0]==0)) ? "all" : filter);
+			
+			if ( io->count_type == COUNT_TYPE_ADVANCED ) {
+				field = (char *)gtk_entry_get_text(GTK_ENTRY(io->graphs[i].calc_field));
+				fprintf(fp, ", %s on %s\n", calc_type_names[io->graphs[i].calc_type], field);
+			} else
+				fprintf(fp, "\n");
+		}
+	fprintf(fp, "################################################################################\n");
+		
+	/* find the last graph displayed */
+	
+	for( i = (MAX_GRAPHS - 1); i >= 0 ; i-- )
+	  	if(io->graphs[i].display) {
+		  lastgraph = i;
+		  break;
+		}
+		
+	/* save graphs data */
+	
+	for( j = 0; j < (io->num_items - 1); j++ ) {
+	  
+	  	for( i = 0; i < MAX_GRAPHS; i++ ) {
+		  
+		    	/* save only displayed graphs */	        
+		  	
+		  	if(!io->graphs[i].display)
+				continue;
+		  	
+	    		/* save the point in the form it is displayed */
+			
+			if ( i != lastgraph )
+			  fprintf(fp, "%d,", get_it_value(io, i, j));
+			else
+			  fprintf(fp, "%d\n", get_it_value(io, i, j));
+		}
+	}
+	
+	fclose(fp);
+	g_free(csvf_name);
+	window_destroy(GTK_WIDGET(io->save_as_w));
+}
 
 static void 
+iostat_save_as_destroy_cb(GtkWidget *win _U_, gpointer data _U_)
+{
+  	io_stat_t *io = (io_stat_t *)data;
+	io->save_as_w = NULL;
+}
+
+/* based on file_dlg.c code */
+static void 
+iostat_dlg_save_as_cb(GtkWidget *bt_save _U_, gpointer data _U_)
+{
+  	io_stat_t *io = (io_stat_t *)data;
+	gboolean sth_to_save = FALSE;
+	gint32 i;
+	
+	/* check for something to save */
+	
+	for( i = 0; i < MAX_GRAPHS; i++ )
+	  	if(io->graphs[i].display)
+		  	sth_to_save = TRUE;
+	
+	if ( (!sth_to_save) || (io->num_items == 0) ) {
+	  	simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "There is no data to save.");
+		return;
+	}
+	
+	if (io->save_as_w != NULL) {
+	  	/* there is already a Save dialog box; reactivate it. */
+		reactivate_window(io->save_as_w);
+		return;
+	}
+	
+	/* file selection from dlg_util */
+	io->save_as_w = file_selection_new("Ethereal: Save Graphs Data as CSV", FILE_SELECTION_SAVE);
+	
+	SIGNAL_CONNECT(io->save_as_w, "destroy", iostat_save_as_destroy_cb, io);
+	
+#if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
+	if (gtk_dialog_run(GTK_DIALOG(io->save_as_w)) == GTK_RESPONSE_ACCEPT) {
+		iostat_save_as_ok_cb(io->save_as_w, io);
+	} else {
+		window_destroy(io->save_as_w);
+	}
+#else
+	/* Connect the ok_button to iostat_save_as_ok_cb function and pass along a pointer to io */
+	SIGNAL_CONNECT(GTK_FILE_SELECTION(io->save_as_w)->ok_button, "clicked",
+		       iostat_save_as_ok_cb, io);
+	
+	window_set_cancel_button(io->save_as_w, 
+				 GTK_FILE_SELECTION(io->save_as_w)->cancel_button, 
+				 window_cancel_button_cb);
+	
+	SIGNAL_CONNECT(io->save_as_w, "delete_event", window_delete_event_cb, NULL);
+	
+	gtk_file_selection_set_filename(GTK_FILE_SELECTION(io->save_as_w), "");
+	
+	gtk_widget_show(io->save_as_w);
+	window_present(io->save_as_w);
+#endif
+}
+
+
+static void 
 init_io_stat_window(io_stat_t *io)
 {
 	GtkWidget *vbox;
 	GtkWidget *hbox;
-    GtkWidget *bt_close;
+	GtkWidget *bt_close;
+	GtkWidget *bt_save;
 
 	/* create the main window */
 	io->window=window_new(GTK_WINDOW_TOPLEVEL, "I/O Graphs");
@@ -1883,7 +2044,7 @@
 
 	hbox=gtk_hbox_new(FALSE, 3);
 	gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
-    gtk_container_border_width(GTK_CONTAINER(hbox), 3);
+	gtk_container_border_width(GTK_CONTAINER(hbox), 3);
 	gtk_box_set_child_packing(GTK_BOX(vbox), hbox, FALSE, FALSE, 0, GTK_PACK_START);
 	gtk_widget_show(hbox);
 
@@ -1892,17 +2053,20 @@
 
 	io_stat_set_title(io);
 
-    hbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
+	hbox = dlg_button_row_new(GTK_STOCK_SAVE, GTK_STOCK_CLOSE, NULL);
 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
-    gtk_widget_show(hbox);
+	gtk_widget_show(hbox);
+	
+	bt_close = OBJECT_GET_DATA(hbox, GTK_STOCK_CLOSE);
+	window_set_cancel_button(io->window, bt_close, window_cancel_button_cb);
+	
+	bt_save = OBJECT_GET_DATA(hbox, GTK_STOCK_SAVE);
+	SIGNAL_CONNECT(bt_save, "clicked", iostat_dlg_save_as_cb, io);
 
-    bt_close = OBJECT_GET_DATA(hbox, GTK_STOCK_CLOSE);
-    window_set_cancel_button(io->window, bt_close, window_cancel_button_cb);
-
-    SIGNAL_CONNECT(io->window, "delete_event", window_delete_event_cb, NULL);
-
-    gtk_widget_show(io->window);
-    window_present(io->window);
+	SIGNAL_CONNECT(io->window, "delete_event", window_delete_event_cb, NULL);
+	
+	gtk_widget_show(io->window);
+	window_present(io->window);
 }