From Francisco Alcoba

Very cool ASCII art version of viop graphs


svn path=/trunk/; revision=14023
This commit is contained in:
Ronnie Sahlberg 2005-04-07 09:14:35 +00:00
parent 3fbcc50513
commit 6ac7c99cc5
3 changed files with 392 additions and 6 deletions

View File

@ -2327,6 +2327,10 @@ Olivier Jacques <olivier.jacques [AT] hp.com> {
Support for the Camel protocol.
}
Francisco Alcoba <francisco.alcoba [AT] ericsson.com> {
ASCII art version of VOIP call analysis
}
And assorted fixes and enhancements by the people listed above
and by:
@ -2393,7 +2397,6 @@ Marco van den Bovenkamp <marco [AT] linuxgoeroe.dhs.org>
Ming Zhang <mingz [AT] ele.uri.edu>
Neil Piercy <Neil.Piercy [AT] ipaccess.com>
Rémi Denis-Courmont <courmisch [AT] via.ecp.fr>
Francisco Alcoba <francisco.alcoba [AT] ericsson.com>
Thomas Palmer <tpalmer [AT] elmore.rr.com>
Mårten Svantesson <f95-msv [AT] f.kth.se>
Thomas Boehne <TBoehne [AT] ADwin.de>

View File

@ -52,6 +52,7 @@
#include "main.h"
#include "compat_macros.h"
#include "../color.h"
#include "epan/filesystem.h"
#include <string.h>
@ -59,6 +60,8 @@
#include <unistd.h>
#endif
#include "simple_dialog.h"
/****************************************************************************/
@ -71,6 +74,9 @@ GtkRcStyle *rc_style;
GdkColormap *colormap;
#endif
GtkWidget *write_to_file_w = NULL;
/****************************************************************************/
/* Reset the user_data structure */
static void graph_analysis_reset(graph_analysis_data_t* user_data)
@ -138,6 +144,7 @@ static void graph_analysis_init_dlg(graph_analysis_data_t* user_data)
static void on_destroy(GtkWidget *win _U_, graph_analysis_data_t *user_data _U_)
{
int i;
for (i=0; i<MAX_NUM_NODES; i++){
user_data->nodes[i].type = AT_NONE;
user_data->nodes[i].len = 0;
@ -193,6 +200,366 @@ static void draw_arrow(GdkDrawable *pixmap, GdkGC *gc, gint x, gint y, gboolean
#define BOTTOM_Y_BORDER 0
#define COMMENT_WIDTH 400
#define NODE_CHARS_WIDTH 20
#define CONV_TIME_HEADER "Conv.| Time "
#define EMPTY_HEADER " | "
#define HEADER_LENGTH 16
/****************************************************************************/
/* adds trailing characters to complete the requested length */
/* NB: does not allocate new memory for the string, there must be enough */
/****************************************************************************/
static void enlarge_string(char *string, guint32 length, char pad){
guint32 i,l;
l = strlen(string);
if (l>=length){
return;
}
for (i=l;i<length;i++){
string[i]=pad;
}
string[length]='\0';
}
/****************************************************************************/
/* overwrites the characters in a string, between positions p1 and p2, with */
/* the characters of text_to_insert */
/* NB: it does not check that p1 and p2 fit into string */
/****************************************************************************/
static void overwrite (char *string, char *text_to_insert, guint32 p1, guint32 p2){
guint32 first, last, i;
if (p1 == p2)
return;
if (p1 > p2){
first = p2;
last = p1;
}
else{
first = p1;
last = p2;
}
if ((unsigned int)(last - first)>strlen(text_to_insert)){
last = first + strlen(text_to_insert);
}
for (i=first;i<last;i++){
string[i]=text_to_insert[i-first];
}
return;
}
/****************************************************************************/
gboolean dialog_graph_dump_to_file(graph_analysis_data_t* user_data)
{
guint32 i, first_item, first_node, display_items, display_nodes;
guint32 start_position, end_position, item_width;
guint32 current_item;
graph_analysis_item_t *gai;
guint16 old_conv_num = 0;
char label_string[MAX_COMMENT];
char *empty_line,* separator_line,*tmp_str, *tmp_str2;
char src_port[8],dst_port[8];
GList* list;
FILE *of;
of = fopen(user_data->dlg.write_file,"w");
if (of==NULL){
return FALSE;
}
first_item = user_data->dlg.first_item;
/* get the items to display and fill the matrix array */
list = g_list_first(user_data->graph_info->list);
current_item = 0;
i = 0;
while (list)
{
gai = list->data;
if (gai->display){
if (i>=first_item){
user_data->dlg.items[current_item].frame_num = gai->frame_num;
user_data->dlg.items[current_item].time = gai->time;
user_data->dlg.items[current_item].port_src = gai->port_src;
user_data->dlg.items[current_item].port_dst = gai->port_dst;
user_data->dlg.items[current_item].frame_label = gai->frame_label;
user_data->dlg.items[current_item].comment = gai->comment;
user_data->dlg.items[current_item].conv_num = gai->conv_num;
user_data->dlg.items[current_item].src_node = gai->src_node;
user_data->dlg.items[current_item].dst_node = gai->dst_node;
current_item++;
}
i++;
}
list = g_list_next(list);
}
display_items = current_item;
/* if not items to display */
if (display_items == 0) return TRUE;
display_nodes=user_data->num_nodes;
first_node = user_data->dlg.first_node;
/* Write the conv. and time headers */
fprintf (of, CONV_TIME_HEADER);
empty_line = g_strdup("");
/* Write the node names on top */
for (i=0; i<display_nodes; i++){
/* print the node identifiers */
g_snprintf(label_string, NODE_CHARS_WIDTH, "| %s",
get_addr_name(&(user_data->nodes[i+first_node])));
enlarge_string(label_string,NODE_CHARS_WIDTH,' ');
fprintf(of,label_string);
strcpy(label_string,"| ");
enlarge_string(label_string,NODE_CHARS_WIDTH,' ');
tmp_str = g_strdup(empty_line);
g_free(empty_line);
empty_line = g_strdup_printf("%s%s",tmp_str,label_string);
g_free(tmp_str);
}
tmp_str = g_strdup(empty_line);
g_free(empty_line);
empty_line = g_strdup_printf("%s|",tmp_str);
g_free(tmp_str);
separator_line = g_malloc(strlen(empty_line)+HEADER_LENGTH+1);
separator_line[0]='\0';
enlarge_string(separator_line,strlen(empty_line)+HEADER_LENGTH,'-');
separator_line[strlen(separator_line)-1]='\n';
fprintf(of,"|\n");
/*
* Draw the items
*/
for (current_item=0; current_item<display_items; current_item++){
start_position = (user_data->dlg.items[current_item].src_node-first_node)*NODE_CHARS_WIDTH+NODE_CHARS_WIDTH/2;
end_position = (user_data->dlg.items[current_item].dst_node-first_node)*NODE_CHARS_WIDTH+NODE_CHARS_WIDTH/2;
if (start_position > end_position){
item_width=start_position-end_position;
}
else if (start_position < end_position){
item_width=end_position-start_position;
}
else{ /* same origin and destination address */
end_position = start_position+NODE_CHARS_WIDTH;
item_width = NODE_CHARS_WIDTH;
}
/* separator between conversations */
if (user_data->dlg.items[current_item].conv_num != old_conv_num){
fprintf(of,separator_line);
old_conv_num=user_data->dlg.items[current_item].conv_num;
}
/* write the conversation number */
g_snprintf(label_string, 5, "%i", user_data->dlg.items[current_item].conv_num);
enlarge_string(label_string,5,' ');
fprintf(of,"%s",label_string);
/* write the time */
g_snprintf(label_string, 11, "|%.3f", user_data->dlg.items[current_item].time);
enlarge_string(label_string,11,' ');
fprintf(of,"%s",label_string);
/* write the frame label */
tmp_str = g_strdup(empty_line);
overwrite(tmp_str,user_data->dlg.items[current_item].frame_label,
start_position,
end_position
);
fprintf(of,tmp_str);
/* write the comments */
g_snprintf(label_string, MAX_COMMENT, "%s", user_data->dlg.items[current_item].comment);
fprintf(of,"%s\n",label_string);
/* write draw the arrow and frame label*/
fprintf(of,EMPTY_HEADER);
tmp_str = g_strdup(empty_line);
tmp_str2 = g_malloc(item_width);
tmp_str2[0]='\0';
enlarge_string(tmp_str2,item_width-1,'-');
if (start_position<end_position){
tmp_str2[item_width-1]='>';
}
else{
tmp_str2[0]='<';
}
overwrite(tmp_str,tmp_str2,
start_position,
end_position
);
g_snprintf(src_port,7,"(%i)", user_data->dlg.items[current_item].port_src);
g_snprintf(dst_port,7,"(%i)", user_data->dlg.items[current_item].port_dst);
if (start_position<end_position){
overwrite(tmp_str,src_port,start_position-9,start_position-1);
overwrite(tmp_str,dst_port,end_position+1,end_position+9);
}
else{
overwrite(tmp_str,src_port,start_position+1,start_position+9);
overwrite(tmp_str,dst_port,end_position-9,end_position+1);
}
fprintf(of,"%s\n",tmp_str);
g_free(tmp_str);
g_free(tmp_str2);
}
fclose (of);
return TRUE;
}
/****************************************************************************/
static void write_to_file_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
{
/* Note that we no longer have a Write to file dialog box. */
write_to_file_w = NULL;
}
/****************************************************************************/
/* save in a file */
/* first an auxiliary function in case we need an overwrite confirmation dialog */
static void overwrite_existing_file_cb(gpointer dialog _U_, gint btn, gpointer user_data _U_)
{
graph_analysis_data_t *user_data_p;
user_data_p = user_data;
switch(btn) {
case(ESD_BTN_YES):
/* overwrite the file*/
dialog_graph_dump_to_file(user_data);
break;
case(ESD_BTN_NO):
break;
default:
g_assert_not_reached();
}
}
/* and then the save in a file dialog itself */
static void write_to_file_ok_cb(GtkWidget *ok_bt _U_, gpointer user_data _U_)
{
FILE *file_test;
gpointer dialog;
graph_analysis_data_t *user_data_p;
user_data_p = user_data;
user_data_p->dlg.write_file = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (write_to_file_w)));
/* Perhaps the user specified a directory instead of a file.
Check whether they did. */
if (test_for_directory(user_data_p->dlg.write_file) == EISDIR) {
/* It's a directory - set the file selection box to display it. */
set_last_open_dir(user_data_p->dlg.write_file);
g_free(user_data_p->dlg.write_file);
file_selection_set_current_folder(write_to_file_w, get_last_open_dir());
return;
}
/* check whether the file exists */
file_test = fopen(user_data_p->dlg.write_file,"r");
if (file_test!=NULL){
dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_YES_NO,
"%sFile: \"%s\" already exists!%s\n\n"
"Do you want to overwrite it?",
simple_dialog_primary_start(),user_data_p->dlg.write_file, simple_dialog_primary_end());
simple_dialog_set_cb(dialog, overwrite_existing_file_cb, user_data);
fclose(file_test);
}
else{
if (!dialog_graph_dump_to_file(user_data))
return;
}
window_destroy(GTK_WIDGET(write_to_file_w));
}
/****************************************************************************/
static void
on_write_bt_clicked (GtkButton *button _U_,
gpointer user_data _U_)
{
GtkWidget *vertb;
GtkWidget *ok_bt;
if (write_to_file_w != NULL) {
/* There's already a Write to file dialog box; reactivate it. */
reactivate_window(write_to_file_w);
return;
}
write_to_file_w = file_selection_new("Ethereal: Write graph to file", FILE_SELECTION_SAVE);
/* Container for each row of widgets */
vertb = gtk_vbox_new(FALSE, 0);
gtk_container_border_width(GTK_CONTAINER(vertb), 5);
gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(write_to_file_w)->action_area),
vertb, FALSE, FALSE, 0);
gtk_widget_show (vertb);
ok_bt = GTK_FILE_SELECTION(write_to_file_w)->ok_button;
SIGNAL_CONNECT(ok_bt, "clicked", write_to_file_ok_cb, user_data);
window_set_cancel_button(write_to_file_w,
GTK_FILE_SELECTION(write_to_file_w)->cancel_button, window_cancel_button_cb);
SIGNAL_CONNECT(write_to_file_w, "delete_event", window_delete_event_cb, NULL);
SIGNAL_CONNECT(write_to_file_w, "destroy", write_to_file_destroy_cb,
NULL);
gtk_widget_show(write_to_file_w);
window_present(write_to_file_w);
}
/****************************************************************************/
static void dialog_graph_draw(graph_analysis_data_t* user_data)
{
@ -1019,8 +1386,10 @@ static void create_draw_area(graph_analysis_data_t* user_data, GtkWidget *box)
static void dialog_graph_create_window(graph_analysis_data_t* user_data)
{
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *hbuttonbox;
GtkWidget *bt_close;
GtkWidget *bt_write;
GtkTooltips *tooltips = gtk_tooltips_new();
/* create the main window */
user_data->dlg.window=window_new(GTK_WINDOW_TOPLEVEL, "Graph Analysis");
@ -1032,11 +1401,24 @@ static void dialog_graph_create_window(graph_analysis_data_t* user_data)
create_draw_area(user_data, vbox);
hbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show(hbox);
/* button row */
hbuttonbox = gtk_hbutton_box_new ();
gtk_box_pack_start (GTK_BOX (vbox), hbuttonbox, FALSE, FALSE, 0);
gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), GTK_BUTTONBOX_SPREAD);
gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbuttonbox), 30);
gtk_widget_show(hbuttonbox);
bt_close = OBJECT_GET_DATA(hbox, GTK_STOCK_CLOSE);
bt_write = gtk_button_new_with_label("Write to file");
gtk_container_add(GTK_CONTAINER(hbuttonbox), bt_write);
gtk_widget_show(bt_write);
SIGNAL_CONNECT(bt_write, "clicked", on_write_bt_clicked, user_data);
gtk_tooltips_set_tip (tooltips, bt_write, "Write an ASCII representation of the graph to a file", NULL);
bt_close = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLOSE);
gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_close);
GTK_WIDGET_SET_FLAGS(bt_close, GTK_CAN_DEFAULT);
gtk_widget_show(bt_close);
gtk_tooltips_set_tip (tooltips, bt_close, "Close this dialog", NULL);
window_set_cancel_button(user_data->dlg.window, bt_close, window_cancel_button_cb);
SIGNAL_CONNECT(user_data->dlg.window, "delete_event", window_delete_event_cb, NULL);

View File

@ -100,6 +100,7 @@ typedef struct _dialog_data_t {
guint32 selected_item; /* the selected item */
display_items_t items[NUM_DISPLAY_ITEMS];
guint32 left_x_border;
char *write_file;
} dialog_data_t;