From 9bdde5216f3ec31d4a02329423708288c57329c3 Mon Sep 17 00:00:00 2001 From: Anders Broman Date: Wed, 29 Feb 2012 05:49:18 +0000 Subject: From Cal Turney:io,stat LOAD error, comma field ignored, zero data intervals not displayed, enhanced output https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6883 svn path=/trunk/; revision=41231 --- ui/cli/tap-iostat.c | 1330 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 805 insertions(+), 525 deletions(-) (limited to 'ui/cli') diff --git a/ui/cli/tap-iostat.c b/ui/cli/tap-iostat.c index 1104edd6d6..d2976313b6 100644 --- a/ui/cli/tap-iostat.c +++ b/ui/cli/tap-iostat.c @@ -38,15 +38,9 @@ #include #include #include +#include "globals.h" -typedef struct _io_stat_t { - gint64 interval; /* unit is us */ - guint32 num_items; - struct _io_stat_item_t *items; - const char **filters; -} io_stat_t; - #define CALC_TYPE_FRAMES 0 #define CALC_TYPE_BYTES 1 #define CALC_TYPE_FRAMES_AND_BYTES 2 @@ -57,16 +51,46 @@ typedef struct _io_stat_t { #define CALC_TYPE_AVG 7 #define CALC_TYPE_LOAD 8 +typedef struct { + const char *func_name; + int calc_type; +} calc_type_ent_t; + +static calc_type_ent_t calc_type_table[] = { + { "FRAMES", CALC_TYPE_FRAMES }, + { "BYTES", CALC_TYPE_BYTES }, + { "FRAMES BYTES", CALC_TYPE_FRAMES_AND_BYTES }, + { "COUNT", CALC_TYPE_COUNT }, + { "SUM", CALC_TYPE_SUM }, + { "MIN", CALC_TYPE_MIN }, + { "MAX", CALC_TYPE_MAX }, + { "AVG", CALC_TYPE_AVG }, + { "LOAD", CALC_TYPE_LOAD }, + { NULL, 0 } +}; + +typedef struct _io_stat_t { + gint64 interval; /* The user-specified time interval (us) */ + guint invl_prec; /* Decimal precision of the time interval (1=10s, 2=100s etc) */ + guint32 num_cols; /* The number of columns of statistics in the table */ + struct _io_stat_item_t + *items; /* Each item is a single cell in the table */ + const char **filters; /* 'io,stat' cmd strings (e.g., "AVG(smb.time)smb.time") */ + guint64 *max_vals; /* The max value sans the decimal or nsecs portion in each stat column */ + guint32 *max_frames; /* The max number of frames in each stat column */ +} io_stat_t; + typedef struct _io_stat_item_t { io_stat_t *parent; - struct _io_stat_item_t *next; + struct _io_stat_item_t *next; struct _io_stat_item_t *prev; - gint64 time; /* unit is us since start of capture */ - int calc_type; + gint64 time; /* Time since start of capture (us)*/ + int calc_type; /* The statistic type */ + int colnum; /* Column number of this stat (0 to n) */ int hf_index; - guint64 frames; - guint64 num; - guint64 counter; + guint32 frames; + guint32 num; /* The sample size of a given statistic (only needed for AVG) */ + guint64 counter; /* The accumulated data for the calculation of that statistic */ gfloat float_counter; gdouble double_counter; } io_stat_item_t; @@ -76,62 +100,69 @@ typedef struct _io_stat_item_t { static int iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *dummy _U_) { - io_stat_item_t *mit = arg; + io_stat_t *parent; + io_stat_item_t *mit; io_stat_item_t *it; - gint64 current_time, ct; - GPtrArray *gp; + gint64 relative_time, rt; + nstime_t *new_time; + GPtrArray *gp; guint i; + int ftype; + + mit = arg; + parent = mit->parent; + relative_time = (gint64)(pinfo->fd->rel_ts.secs*1000000) + (pinfo->fd->rel_ts.nsecs+500)/1000; - current_time = (gint64)(pinfo->fd->rel_ts.secs*1000000) + (pinfo->fd->rel_ts.nsecs+500)/1000; - - /* the prev item before the main one is always the last interval we saw packets for */ - it=mit->prev; + /* The prev item before the main one is always the last interval we saw packets for */ + it = mit->prev; /* XXX for the time being, just ignore all frames that are in the past. should be fixed in the future but hopefully it is uncommon */ - if(current_timetime){ + if(relative_time < it->time){ return FALSE; } - /* we have moved into a new interval, we need to create a new struct */ - ct = current_time; - while(ct >= (it->time + mit->parent->interval)){ - it->next=g_malloc(sizeof(io_stat_item_t)); - it->next->prev=it; - it->next->next=NULL; - it=it->next; - mit->prev=it; - - it->time = it->prev->time + mit->parent->interval; - it->frames = 0; + /* If we have moved into a new interval (row), create a new io_stat_item_t struct for every interval + * between the last struct and this one. If an item was not found in a previous interval, an empty + * struct will be created for it. */ + rt = relative_time; + while (rt >= it->time + parent->interval) { + it->next = g_malloc(sizeof(io_stat_item_t)); + it->next->prev = it; + it->next->next = NULL; + it = it->next; + mit->prev = it; + + it->time = it->prev->time + parent->interval; + it->frames = 0; it->counter = 0; it->float_counter = 0; it->double_counter = 0; - it->num = 0; - it->calc_type=it->prev->calc_type; - it->hf_index=it->prev->hf_index; + it->num = 0; + it->calc_type = it->prev->calc_type; + it->hf_index = it->prev->hf_index; + it->colnum = it->prev->colnum; } - /* it will now give us the current structure to use to store the data in */ + /* Store info in the current structure */ it->frames++; - switch(it->calc_type){ - case CALC_TYPE_BYTES: + switch(it->calc_type) { case CALC_TYPE_FRAMES: + case CALC_TYPE_BYTES: case CALC_TYPE_FRAMES_AND_BYTES: - it->counter+=pinfo->fd->pkt_len; + it->counter += pinfo->fd->pkt_len; break; case CALC_TYPE_COUNT: gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index); if(gp){ - it->counter+=gp->len; + it->counter += gp->len; } break; case CALC_TYPE_SUM: gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index); if(gp){ guint64 val; - nstime_t *new_time; for(i=0;ilen;i++){ switch(proto_registrar_get_ftype(it->hf_index)){ @@ -139,30 +170,31 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du case FT_UINT16: case FT_UINT24: case FT_UINT32: - it->counter+=fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value); + it->counter += fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value); break; case FT_UINT64: - it->counter+=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value); + it->counter += fvalue_get_integer64(&((field_info *)gp->pdata[i])->value); break; case FT_INT8: case FT_INT16: case FT_INT24: case FT_INT32: - it->counter+=fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value); + it->counter += fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value); break; case FT_INT64: - it->counter+=(gint64)fvalue_get_integer64(&((field_info *)gp->pdata[i])->value); + it->counter += (gint64)fvalue_get_integer64(&((field_info *)gp->pdata[i])->value); break; case FT_FLOAT: - it->float_counter+=(gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value); + it->float_counter += + (gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value); break; case FT_DOUBLE: - it->double_counter+=fvalue_get_floating(&((field_info *)gp->pdata[i])->value); + it->double_counter += fvalue_get_floating(&((field_info *)gp->pdata[i])->value); break; case FT_RELATIVE_TIME: new_time = fvalue_get(&((field_info *)gp->pdata[i])->value); val=(guint64)(new_time->secs) * NANOSECS_PER_SEC + new_time->nsecs; - it->counter += val; + it->counter += val; break; } } @@ -171,31 +203,25 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du case CALC_TYPE_MIN: gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index); if(gp){ - int type; guint64 val; gfloat float_val; gdouble double_val; - nstime_t *new_time; - type=proto_registrar_get_ftype(it->hf_index); + ftype=proto_registrar_get_ftype(it->hf_index); for(i=0;ilen;i++){ - switch(type){ + switch(ftype){ case FT_UINT8: case FT_UINT16: case FT_UINT24: case FT_UINT32: - val=fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value); - if((it->frames==1)&&(i==0)){ - it->counter=val; - } else if(valcounter){ + val = fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value); + if ((it->frames==1 && i==0) || (val < it->counter)) { it->counter=val; } break; case FT_UINT64: - val=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value); - if((it->frames==1)&&(i==0)){ - it->counter=val; - } else if(valcounter){ + val = fvalue_get_integer64(&((field_info *)gp->pdata[i])->value); + if((it->frames==1)&&(i==0) || (val < it->counter)){ it->counter=val; } break; @@ -203,43 +229,33 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du case FT_INT16: case FT_INT24: case FT_INT32: - val=fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value); - if((it->frames==1)&&(i==0)){ - it->counter=val; - } else if((gint32)val<(gint32)(it->counter)){ + val = fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value); + if((it->frames==1)&&(i==0) || ((gint32)val < (gint32)(it->counter))) { it->counter=val; } break; case FT_INT64: - val=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value); - if((it->frames==1)&&(i==0)){ - it->counter=val; - } else if((gint64)val<(gint64)(it->counter)){ + val = fvalue_get_integer64(&((field_info *)gp->pdata[i])->value); + if((it->frames==1)&&(i==0) || ((gint64)val < (gint64)(it->counter))) { it->counter=val; - } + } break; case FT_FLOAT: float_val=(gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value); - if((it->frames==1)&&(i==0)){ - it->float_counter=float_val; - } else if(float_valfloat_counter){ + if((it->frames==1)&&(i==0) || (float_val < it->float_counter)) { it->float_counter=float_val; } break; case FT_DOUBLE: double_val=fvalue_get_floating(&((field_info *)gp->pdata[i])->value); - if((it->frames==1)&&(i==0)){ - it->double_counter=double_val; - } else if(double_valdouble_counter){ + if((it->frames==1)&&(i==0) || (double_val < it->double_counter)) { it->double_counter=double_val; - } + } break; case FT_RELATIVE_TIME: new_time=fvalue_get(&((field_info *)gp->pdata[i])->value); - val=(guint64)(new_time->secs) * NANOSECS_PER_SEC + new_time->nsecs; - if((it->frames==1)&&(i==0)){ - it->counter=val; - } else if(valcounter){ + val = (guint64)(new_time->secs) * NANOSECS_PER_SEC + new_time->nsecs; + if((it->frames==1)&&(i==0) || (val < it->counter)) { it->counter=val; } break; @@ -250,78 +266,55 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du case CALC_TYPE_MAX: gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index); if(gp){ - int type; guint64 val; gfloat float_val; gdouble double_val; - nstime_t *new_time; - type=proto_registrar_get_ftype(it->hf_index); + ftype=proto_registrar_get_ftype(it->hf_index); for(i=0;ilen;i++){ - switch(type){ + switch(ftype){ case FT_UINT8: case FT_UINT16: case FT_UINT24: case FT_UINT32: - val=fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value); - if((it->frames==1)&&(i==0)){ - it->counter=val; - } else if(val>it->counter){ + val = fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value); + if(val > it->counter) it->counter=val; - } break; case FT_UINT64: - val=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value); - if((it->frames==1)&&(i==0)){ - it->counter=val; - } else if(val>it->counter){ + val = fvalue_get_integer64(&((field_info *)gp->pdata[i])->value); + if(val > it->counter) it->counter=val; - } break; case FT_INT8: case FT_INT16: case FT_INT24: case FT_INT32: - val=fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value); - if((it->frames==1)&&(i==0)){ + val = fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value); + if((gint32)val > (gint32)it->counter) it->counter=val; - } else if((gint32)val>(gint32)(it->counter)){ - it->counter=val; - } break; case FT_INT64: - val=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value); - if((it->frames==1)&&(i==0)){ - it->counter=val; - } else if((gint64)val>(gint64)(it->counter)){ + val = fvalue_get_integer64(&((field_info *)gp->pdata[i])->value); + if ((gint64)val > (gint64)it->counter) it->counter=val; - } break; case FT_FLOAT: - float_val=(gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value); - if((it->frames==1)&&(i==0)){ - it->float_counter=float_val; - } else if(float_val>it->float_counter){ - it->float_counter=float_val; - } + float_val = (gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value); + if(float_val > it->float_counter) + it->float_counter=float_val; break; case FT_DOUBLE: - double_val=fvalue_get_floating(&((field_info *)gp->pdata[i])->value); - if((it->frames==1)&&(i==0)){ - it->double_counter=double_val; - } else if(double_val>it->double_counter){ - it->double_counter=double_val; - } + double_val = fvalue_get_floating(&((field_info *)gp->pdata[i])->value); + if(double_val > it->double_counter) + it->double_counter=double_val; break; case FT_RELATIVE_TIME: - new_time=fvalue_get(&((field_info *)gp->pdata[i])->value); - val=(guint64)(new_time->secs) * NANOSECS_PER_SEC + new_time->nsecs; - if((it->frames==1)&&(i==0)){ - it->counter=val; - } else if(val>it->counter){ + new_time = fvalue_get(&((field_info *)gp->pdata[i])->value); + val = (guint64)(new_time->secs) * NANOSECS_PER_SEC + new_time->nsecs; + if (val>it->counter) it->counter=val; - } - break; + break; } } } @@ -329,416 +322,686 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du case CALC_TYPE_AVG: gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index); if(gp){ - int type; guint64 val; - nstime_t *new_time; - - type=proto_registrar_get_ftype(it->hf_index); + + ftype=proto_registrar_get_ftype(it->hf_index); for(i=0;ilen;i++){ it->num++; - switch(type){ + switch(ftype) { case FT_UINT8: case FT_UINT16: case FT_UINT24: case FT_UINT32: - val=fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value); - it->counter+=val; + val = fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value); + it->counter += val; break; case FT_UINT64: case FT_INT64: - val=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value); - it->counter+=val; + val = fvalue_get_integer64(&((field_info *)gp->pdata[i])->value); + it->counter += val; break; case FT_INT8: case FT_INT16: case FT_INT24: case FT_INT32: - val=fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value); - it->counter+=val; + val = fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value); + it->counter += val; break; case FT_FLOAT: - it->float_counter+=(gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value); + it->float_counter += (gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value); break; case FT_DOUBLE: - it->double_counter+=fvalue_get_floating(&((field_info *)gp->pdata[i])->value); + it->double_counter += fvalue_get_floating(&((field_info *)gp->pdata[i])->value); break; case FT_RELATIVE_TIME: - new_time=fvalue_get(&((field_info *)gp->pdata[i])->value); - val=(guint64)(new_time->secs) * NANOSECS_PER_SEC + new_time->nsecs; - it->counter+=val; + new_time = fvalue_get(&((field_info *)gp->pdata[i])->value); + val = (guint64)(new_time->secs) * NANOSECS_PER_SEC + new_time->nsecs; + it->counter += val; break; } } } break; case CALC_TYPE_LOAD: - gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index); - if(gp){ - int type; - - type=proto_registrar_get_ftype(it->hf_index); - if (type != FT_RELATIVE_TIME) { + gp = proto_get_finfo_ptr_array(edt->tree, it->hf_index); + if (gp) { + ftype = proto_registrar_get_ftype(it->hf_index); + if (ftype != FT_RELATIVE_TIME) { fprintf(stderr, - "\ntshark: LOAD() is only supported for relative-time fiels such as smb.time\n" - ); + "\ntshark: LOAD() is only supported for relative-time fields such as smb.time\n"); exit(10); } for(i=0;ilen;i++){ guint64 val; int tival; - nstime_t *new_time; io_stat_item_t *pit; - new_time=fvalue_get(&((field_info *)gp->pdata[i])->value); - val=(guint64)(new_time->secs)*1000000 + new_time->nsecs/1000; - tival = (int)(val % mit->parent->interval); + new_time = fvalue_get(&((field_info *)gp->pdata[i])->value); + val = (guint64)(new_time->secs)*1000000 + new_time->nsecs/1000; + tival = (int)(val % parent->interval); it->counter += tival; val -= tival; pit = it->prev; while (val > 0) { - if (val < (guint64)mit->parent->interval) { + if (val < (guint64)parent->interval) { pit->counter += val; val = 0; break; } - - pit->counter += mit->parent->interval; - val -= mit->parent->interval; + pit->counter += parent->interval; + val -= parent->interval; pit = pit->prev; - } } } break; } + /* Store the highest value for this item in order to determine the width of each stat column. + * For real numbers we only need to know its magnitude (the value to the left of the decimal point + * so round it up before storing it as an integer in max_vals. For AVG of RELATIVE_TIME fields, + * calc the average, round it to the next second and store the seconds. For all other calc types + * of RELATIVE_TIME fields, store the counters without modification. + * fields. */ + switch(it->calc_type) { + case CALC_TYPE_FRAMES: + case CALC_TYPE_FRAMES_AND_BYTES: + parent->max_frames[it->colnum] = + max(parent->max_frames[it->colnum], (guint32) it->frames); + if (it->calc_type==CALC_TYPE_FRAMES_AND_BYTES) + parent->max_vals[it->colnum] = + max(parent->max_vals[it->colnum], it->counter); + + case CALC_TYPE_BYTES: + case CALC_TYPE_COUNT: + case CALC_TYPE_LOAD: + parent->max_vals[it->colnum] = max(parent->max_vals[it->colnum], it->counter); + break; + case CALC_TYPE_SUM: + case CALC_TYPE_MIN: + case CALC_TYPE_MAX: + switch(ftype) { + case FT_FLOAT: + parent->max_vals[it->colnum] = + max(parent->max_vals[it->colnum], (guint64)(it->float_counter+0.5)); + break; + case FT_DOUBLE: + parent->max_vals[it->colnum] = + max(parent->max_vals[it->colnum],(guint64)(it->double_counter+0.5)); + break; + case FT_RELATIVE_TIME: + parent->max_vals[it->colnum] = + max(parent->max_vals[it->colnum], it->counter); + break; + default: + /* UINT16-64 and INT8-64 */ + parent->max_vals[it->colnum] = + max(parent->max_vals[it->colnum], it->counter); + break; + } + break; + case CALC_TYPE_AVG: + switch(ftype) { + case FT_FLOAT: + parent->max_vals[it->colnum] = + max(parent->max_vals[it->colnum], (guint64)it->float_counter/it->num); + break; + case FT_DOUBLE: + parent->max_vals[it->colnum] = + max(parent->max_vals[it->colnum],(guint64)it->double_counter/it->num); + break; + case FT_RELATIVE_TIME: + parent->max_vals[it->colnum] = + max(parent->max_vals[it->colnum], ((it->counter/it->num) + 500000000) / NANOSECS_PER_SEC); + break; + default: + /* UINT16-64 and INT8-64 */ + parent->max_vals[it->colnum] = + max(parent->max_vals[it->colnum], it->counter/it->num); + break; + } + } + return TRUE; +} - return TRUE; +static int +magnitude (guint64 val, int max_w) +{ + int i, mag=0; + + for (i=0; iparent; + int lenlab = (int)strlen(label), len; + char *spaces=" ", *spaces_s; + + len = (int)strlen(spaces) - (((lenval-lenlab) / 2) + numpad); + if (len > 0 && len < 6) + spaces_s = &spaces[len]; + if ((lenval-lenlab)%2==0) { + printf("%s%s%s|", spaces_s, label, spaces_s); + } else { + printf("%s%s%s|", spaces_s-1, label, spaces_s); + } +} - printf("\n"); +typedef struct { + int fr; /* Width of this FRAMES column sans padding and border chars */ + int val; /* Width of this non-FRAMES column sans padding and border chars */ +} column_width; - /* Display the table border */ - for(i=0;inum_items;i++){ - if(iot->items[i].calc_type==CALC_TYPE_FRAMES_AND_BYTES) - borderLen+=17; - } - if(iot->interval!=G_MAXINT32) - borderLen+=8; - if(iot->num_items>3) - borderLen+=(iot->num_items-3)*17; - for(i=0;iparent; + num_cols = iot->num_cols; + col_w = g_malloc(sizeof(column_width) * num_cols); + fmts = g_malloc(sizeof(char *) * num_cols); + duration = (gint64)(cfile.elapsed_time.secs*1000000) + (cfile.elapsed_time.nsecs+500)/1000; + + /* Store the pointer to each stat column */ + stat_cols = g_malloc(sizeof(io_stat_item_t *) * num_cols); + for (j=0; jitems[j]; + + /* The following prevents gross inaccuracies when the user specifies an interval that is greater + * than the capture duration. */ + if (iot->interval > duration || iot->interval==G_MAXINT32) { + interval = duration; + iot->interval = G_MAXINT32; + } else { + interval = iot->interval; + } + + /* Calc the capture duration's magnitude (dur_mag) */ + dur_secs = (int)duration/1000000; + dur_mag = magnitude((guint64)dur_secs, 5); + itoa(dur_mag, dur_mag_s, 10); + + /* Calc the interval's magnitude */ + invl_mag = magnitude((guint64)interval/1000000, 5); + + /* Set or get the interval precision */ + if (interval==duration) { + /* + * An interval arg of 0 or an interval size exceeding the capture duration was specified. + * Set the decimal precision of duration based on its magnitude. */ + if (dur_mag >= 2) + invl_prec = 1; + else if (dur_mag==1) + invl_prec = 3; + else + invl_prec = 6; + + borderlen = 30 + dur_mag + (invl_prec==0 ? 0 : invl_prec+1); + } else { + invl_prec = iot->invl_prec; + borderlen = 24 + invl_mag + (invl_prec==0 ? 0 : invl_prec+1); + } + + /* Round the duration according to invl_prec */ + div=1000000; + for (i=0; iinterval==G_MAXINT32) + interval = duration; + + /* Recalc the dur_mag in case rounding has increased its magnitude */ + dur_secs = (int)duration/1000000; + dur_mag = magnitude((guint64)dur_secs, 5); + + /* Calc the width of the time interval column (incl borders and padding). */ + if (invl_prec==0) + invl_col_w = (2*dur_mag) + 8; + else + invl_col_w = (2*dur_mag) + (2*invl_prec) + 10; + invl_col_w = max(invl_col_w, 12); + borderlen = max(borderlen, invl_col_w); + + /* Calc the total width of each row in the stats table and build the printf format string for each + * column based on its field type, width, and name length. + * NOTE: The magnitude of all types including float and double are stored in iot->max_vals which + * is an *integer*. */ + tabrow_w = invl_col_w; + for (j=0; jitems[j].calc_type; + if (type==CALC_TYPE_FRAMES_AND_BYTES) { + namelen = 5; + } else { + namelen = (int)strlen(calc_type_table[type].func_name); + } + if(type==CALC_TYPE_FRAMES + || type==CALC_TYPE_FRAMES_AND_BYTES) { + + fr_mag = magnitude(iot->max_frames[j], 15); + fr_mag = max(6, fr_mag); + col_w[j].fr = fr_mag; + tabrow_w += col_w[j].fr + 3; + itoa(fr_mag, fr_mag_s, 10); + + if (type==CALC_TYPE_FRAMES) { + fmt = g_strconcat(" %", fr_mag_s, "u |", '\0'); + } else { + /* CALC_TYPE_FRAMES_AND_BYTES + */ + val_mag = magnitude(iot->max_vals[j], 15); + val_mag = max(5, val_mag); + col_w[j].val = val_mag; + tabrow_w += (col_w[j].val + 3); + itoa(val_mag, val_mag_s, 10); + fmt = g_strconcat(" %", fr_mag_s, "u |", " %", val_mag_s, G_GINT64_MODIFIER, "u |", '\0'); + } + fmts[j] = fmt; + continue; + } + switch(type) { + case CALC_TYPE_BYTES: + case CALC_TYPE_COUNT: + + val_mag = magnitude(iot->max_vals[j], 15); + val_mag = max(5, val_mag); + col_w[j].val = val_mag; + itoa(val_mag, val_mag_s, 10); + fmt = g_strconcat(" %", val_mag_s, G_GINT64_MODIFIER, "u |", '\0'); + break; + + default: + ftype = proto_registrar_get_ftype(stat_cols[j]->hf_index); + switch (ftype) { + case FT_FLOAT: + case FT_DOUBLE: + val_mag = magnitude(iot->max_vals[j], 15); + itoa(val_mag, val_mag_s, 10); + fmt = g_strconcat(" %", val_mag_s, ".6f |", '\0'); + col_w[j].val = val_mag + 7; + break; + case FT_RELATIVE_TIME: + /* Convert FT_RELATIVE_TIME field to seconds + * CALC_TYPE_LOAD was already converted in iostat_packet() ) */ + if (type==CALC_TYPE_LOAD) { + iot->max_vals[j] /= interval; + } else { + iot->max_vals[j] = (iot->max_vals[j] + 500000000) / NANOSECS_PER_SEC; + } + val_mag = magnitude(iot->max_vals[j], 15); + itoa(val_mag, val_mag_s, 10); + fmt = g_strconcat(" %", val_mag_s, "u.%06u |", '\0'); + col_w[j].val = val_mag + 7; + break; + + default: + val_mag = magnitude(iot->max_vals[j], 15); + val_mag = max(namelen, val_mag); + col_w[j].val = val_mag; + itoa(val_mag, val_mag_s, 10); + + switch (ftype) { + case FT_UINT8: + case FT_UINT16: + case FT_UINT24: + case FT_UINT32: + case FT_UINT64: + fmt = g_strconcat(" %", val_mag_s, G_GINT64_MODIFIER, "u |", '\0'); + break; + case FT_INT8: + case FT_INT16: + case FT_INT24: + case FT_INT32: + case FT_INT64: + fmt = g_strconcat(" %", val_mag_s, G_GINT64_MODIFIER, "d |", '\0'); + break; + } + } /* End of ftype switch */ + } /* End of switch for calc type */ + tabrow_w += col_w[j].val + 3; + fmts[j] = fmt; + } /* End of for loop (columns) */ + + borderlen = max(borderlen, tabrow_w); + + /* Calc the max width of the list of filters. */ + maxfltr_w = 0; + for(j=0; jfilters[j]) { + k = (int)strlen(iot->filters[j]) + 11; + maxfltr_w = max(maxfltr_w, k); + } else { + maxfltr_w = max(maxfltr_w, 26); + } + } + /* The stat table is not wrapped (by tshark) but filter is wrapped at the width of the stats table + * (which currently = borderlen); however, if the filter width exceeds the table width and the + * table width is less than 102 bytes, set borderlen to the lesser of the max filter width and 102. + * The filters will wrap at the lesser of borderlen-2 and the last space in the filter. + * NOTE: 102 is the typical size of a user window when the font is fixed width (e.g., COURIER 10). + * XXX: A pref could be added to change the max width from the default size of 102. */ + if (maxfltr_w > borderlen && borderlen < 102) + borderlen = min(maxfltr_w, 102); + + /* Prevent double right border by adding a space */ + if (borderlen-tabrow_w==1) + borderlen++; + + /* Display the top border */ + printf("\n"); + for (i=0; i 0) { + itoa(invl_prec, invl_prec_s, 10); + invl_fmt = g_strconcat("%", invl_mag_s, "u.%0", invl_prec_s, "u", '\0'); + if (interval==duration) { + full_fmt = g_strconcat("| Interval size: ", invl_fmt, " secs (dur)%s", '\0'); + spaces_s = &spaces[30+invl_mag+invl_prec]; + } else { + full_fmt = g_strconcat("| Interval size: ", invl_fmt, " secs%s", '\0'); + spaces_s = &spaces[24+invl_mag+invl_prec]; + } + printf(full_fmt, (guint32)interval/1000000, + (guint32)((interval%1000000)/div), spaces_s); + } else { + invl_fmt = g_strconcat("%", invl_mag_s, "u", '\0'); + full_fmt = g_strconcat("| Interval size: ", invl_fmt, " secs%s", '\0'); + spaces_s = &spaces[23 + invl_mag]; + printf(full_fmt, (guint32)interval/1000000, spaces_s); + } + g_free(invl_fmt); + g_free(full_fmt); + + if (invl_prec > 0) + invl_fmt = g_strconcat("%", dur_mag_s, "u.%0", invl_prec_s, "u", '\0'); + else + invl_fmt = g_strconcat("%", dur_mag_s, "u", '\0'); + + /* Display the list of filters and their column numbers vertically */ + printf("|\n| Col"); + for(j=0; jfilters[j] || (iot->filters[j]==0)) { + /* + * An empty (no filter) comma field was specified */ + spaces_s = &spaces[16 + 10]; + printf("Frames and bytes%s|\n", spaces_s); + } else { + filter = iot->filters[j]; + len_filt = (int)strlen(filter); + + /* If the width of the widest filter exceeds the width of the stat table, borderlen has + * been set to 102 bytes above and filters wider than 102 will wrap at 91 bytes. */ + if (len_filt+11 <= borderlen) { + printf("%s", filter); + if (len_filt+11 <= borderlen) { + spaces_s = &spaces[len_filt + 10]; + printf("%s", spaces_s); + } + printf("|\n"); + } else { + gchar *sfilter1, *sfilter2; + const char *pos; + int len, next_start, max_w=borderlen-11; + + do { + if (len_filt > max_w) { + sfilter1 = g_strndup(filter, max_w); + /* + * Find the pos of the last space in sfilter1. If a space is found, set + * sfilter2 to the string prior to that space, and print it; otherwise, wrap + * the filter at max_w. */ + pos = strrchr(sfilter1, ' '); + if (pos) { + len = (int)(pos-sfilter1); + next_start = len+1; + } else { + len = (int)strlen(sfilter1); + next_start = len; + } + sfilter2 = g_strndup(sfilter1, len); + printf("%s%s|\n", sfilter2, &spaces[len+10]); + g_free(sfilter1); + g_free(sfilter2); + + printf("| "); + filter = &filter[next_start]; + len_filt = (int)strlen(filter); + } else { + printf("%s%s|\n", filter, &spaces[(strlen(filter))+10]); + break; + } + } while (1); + } + } } - printf("\n"); - - printf("IO Statistics\n"); - if(iot->interval!=G_MAXINT32) - printf("Interval: %3" G_GINT64_MODIFIER "u.%06" G_GINT64_MODIFIER "u secs\n", - iot->interval/1000000, iot->interval%1000000); - - for(i=0;inum_items;i++){ - printf("Column #%u: %s\n",i,iot->filters[i]?iot->filters[i]:""); + printf("|-"); + for(i=0;iinterval==G_MAXINT32){ - printf(" |"); - } else { - printf(" |"); + printf("|\n"); + + /* Display spaces above "Interval (s)" label */ + spaces_s = &spaces[borderlen-(invl_col_w-2)]; + printf("|%s|", spaces_s); + + /* Display column number headers */ + for(j=0; jcalc_type==CALC_TYPE_FRAMES_AND_BYTES) + spaces_s = &spaces[borderlen - (col_w[j].fr + col_w[j].val)] - 3; + else if (item->calc_type==CALC_TYPE_FRAMES) + spaces_s = &spaces[borderlen - col_w[j].fr]; + else + spaces_s = &spaces[borderlen - col_w[j].val]; + + printf("%-2u%s|", j+1, spaces_s); } - for(i=0;inum_items;i++){ - if(iot->items[i].calc_type==CALC_TYPE_FRAMES_AND_BYTES){ - printf(" Column #%-2u |",i); - } else { - printf(" Column #%-2u |",i); - } + if (tabrow_w < borderlen) { + filler_s = &spaces[tabrow_w+1]; + printf("%s|", filler_s); + } + + printf("\n| Interval"); + spaces_s = &spaces[borderlen-(invl_col_w-11)]; + printf("%s|", spaces_s); + + /* Display the stat label in each column */ + for(j=0; jcalc_type; + if(type==CALC_TYPE_FRAMES) { + printcenter (calc_type_table[type].func_name, col_w[j].fr, numpad); + } else if (type==CALC_TYPE_FRAMES_AND_BYTES) { + printcenter ("Frames", col_w[j].fr, numpad); + printcenter ("Bytes", col_w[j].val, numpad); + } else { + printcenter (calc_type_table[type].func_name, col_w[j].val, numpad); + } } - printf("\n"); + if (filler_s > 0) + printf("%s|", filler_s); + printf("\n|-"); - if(iot->interval==G_MAXINT32) { - printf("Time |"); - } else { - printf("Time |"); - } - for(i=0;inum_items;i++){ - switch(iot->items[i].calc_type){ - case CALC_TYPE_FRAMES: - printf(" FRAMES |"); - break; - case CALC_TYPE_BYTES: - printf(" BYTES |"); - break; - case CALC_TYPE_FRAMES_AND_BYTES: - printf(" Frames | Bytes |"); - break; - case CALC_TYPE_COUNT: - printf(" COUNT |"); - break; - case CALC_TYPE_SUM: - printf(" SUM |"); - break; - case CALC_TYPE_MIN: - printf(" MIN |"); - break; - case CALC_TYPE_MAX: - printf(" MAX |"); - break; - case CALC_TYPE_AVG: - printf(" AVG |"); - break; - case CALC_TYPE_LOAD: - printf(" LOAD |"); - break; - } - } - printf("\n"); + for(i=0; inum_items); - frames=g_malloc(sizeof(guint64)*iot->num_items); - counters=g_malloc(sizeof(guint64)*iot->num_items); - float_counters=g_malloc(sizeof(gfloat)*iot->num_items); - double_counters=g_malloc(sizeof(gdouble)*iot->num_items); - num=g_malloc(sizeof(guint64)*iot->num_items); - /* preset all items at the first interval */ - for(i=0;inum_items;i++){ - items[i]=&iot->items[i]; - } + if (tabrow_w < borderlen) + printf("%s|", &spaces[tabrow_w+1]); - /* loop the items until we run out of them all */ + printf("\n"); t=0; - do { - more_items=FALSE; - for(i=0;inum_items;i++){ - frames[i]=0; - counters[i]=0; - float_counters[i]=0; - double_counters[i]=0; - num[i]=0; - } - for(i=0;inum_items;i++){ - if(items[i] && (t>=(items[i]->time+iot->interval))){ - items[i]=items[i]->next; - } - - if(items[i] && (t<(items[i]->time+iot->interval)) && (t>=items[i]->time) ){ - frames[i]=items[i]->frames; - counters[i]=items[i]->counter; - float_counters[i]=items[i]->float_counter; - double_counters[i]=items[i]->double_counter; - num[i]=items[i]->num; - } - - if(items[i]){ - more_items=TRUE; - } - } - - if(more_items){ - if(iot->interval==G_MAXINT32) { - printf("000.000- "); - } else { - printf("%04u.%06u-%04u.%06u ", - (int)(t/1000000),(int)(t%1000000), - (int)((t+iot->interval)/1000000), - (int)((t+iot->interval)%1000000)); - } - for(i=0;inum_items;i++){ - switch(iot->items[i].calc_type){ - case CALC_TYPE_FRAMES: - printf(" %15" G_GINT64_MODIFIER "u ", frames[i]); - break; - case CALC_TYPE_BYTES: - printf(" %15" G_GINT64_MODIFIER "u ", counters[i]); - break; - case CALC_TYPE_FRAMES_AND_BYTES: - printf(" %15" G_GINT64_MODIFIER "u %15" G_GINT64_MODIFIER "u ", frames[i], counters[i]); - break; - case CALC_TYPE_COUNT: - printf(" %15" G_GINT64_MODIFIER "u ", counters[i]); - break; - case CALC_TYPE_SUM: - switch(proto_registrar_get_ftype(iot->items[i].hf_index)){ - case FT_UINT8: - case FT_UINT16: - case FT_UINT24: - case FT_UINT32: - case FT_UINT64: - case FT_INT8: - case FT_INT16: - case FT_INT24: - case FT_INT32: - case FT_INT64: - printf(" %15" G_GINT64_MODIFIER "u ", counters[i]); - break; - case FT_FLOAT: - printf(" %f ", float_counters[i]); - break; - case FT_DOUBLE: - printf(" %f ", double_counters[i]); - break; - case FT_RELATIVE_TIME: - counters[i] = (counters[i]+500)/1000; - printf(" %8u.%06u ", - (int)(counters[i]/1000000), (int)(counters[i]%1000000)); - break; - } - break; - case CALC_TYPE_MIN: - switch(proto_registrar_get_ftype(iot->items[i].hf_index)){ - case FT_UINT8: - case FT_UINT16: - case FT_UINT24: - case FT_UINT32: - case FT_UINT64: - printf(" %15" G_GINT64_MODIFIER "u ", counters[i]); - break; - case FT_INT8: - case FT_INT16: - case FT_INT24: - case FT_INT32: - case FT_INT64: - printf(" %15" G_GINT64_MODIFIER "d ", counters[i]); - break; - case FT_FLOAT: - printf(" %f ", float_counters[i]); - break; - case FT_DOUBLE: - printf(" %f ", double_counters[i]); - break; - case FT_RELATIVE_TIME: - counters[i]=(counters[i]+500)/1000; - printf(" %8u.%06u ", - (int)(counters[i]/1000000), (int)(counters[i]%1000000)); - break; - } - break; - case CALC_TYPE_MAX: - switch(proto_registrar_get_ftype(iot->items[i].hf_index)){ - case FT_UINT8: - case FT_UINT16: - case FT_UINT24: - case FT_UINT32: - case FT_UINT64: - printf(" %15u ", (int)(counters[i])); - break; - case FT_INT8: - case FT_INT16: - case FT_INT24: - case FT_INT32: - case FT_INT64: - printf(" %15" G_GINT64_MODIFIER "d ", counters[i]); - break; - case FT_FLOAT: - printf(" %f ", float_counters[i]); - break; - case FT_DOUBLE: - printf(" %f ", double_counters[i]); - break; - case FT_RELATIVE_TIME: - counters[i]=(counters[i]+500)/1000; - printf(" %8u.%06u ", - (int)(counters[i]/1000000), (int)(counters[i]%1000000)); - break; - } - break; - case CALC_TYPE_AVG: - if(num[i]==0){ - num[i]=1; - } - switch(proto_registrar_get_ftype(iot->items[i].hf_index)){ - case FT_UINT8: - case FT_UINT16: - case FT_UINT24: - case FT_UINT32: - case FT_UINT64: - printf(" %15" G_GINT64_MODIFIER "u ", counters[i]/num[i]); - break; - case FT_INT8: - case FT_INT16: - case FT_INT24: - case FT_INT32: - case FT_INT64: - printf(" %15" G_GINT64_MODIFIER "d ", counters[i]/num[i]); - break; - case FT_FLOAT: - printf(" %f ", float_counters[i]/num[i]); - break; - case FT_DOUBLE: - printf(" %f ", double_counters[i]/num[i]); - break; - case FT_RELATIVE_TIME: - counters[i]=((counters[i]/num[i])+500)/1000; - printf(" %8u.%06u ", - (int)(counters[i]/1000000), (int)(counters[i]%1000000)); - break; - } - break; - - case CALC_TYPE_LOAD: - switch(proto_registrar_get_ftype(iot->items[i].hf_index)){ - case FT_RELATIVE_TIME: - printf("%8u.%06u ", - (int)(counters[i]/iot->interval), (int)((counters[i]%iot->interval)*1000000/iot->interval)); - break; - } - break; - - } - } - printf("\n"); - } - - t+=iot->interval; - } while(more_items); - - for(i=0;i ", invl_fmt, " |", '\0'); + num_rows = (int)(duration/interval) + (((duration%interval+500000)/1000000) > 0 ? 1 : 0); + + /* Display the table values. + * The outer loop is for time interval rows and the inner loop is for stat column items.*/ + for (i=0; inext) + item = item->next; + else + item = NULL; + fmt = fmts[j]; + + if (item) { + switch(item->calc_type) { + case CALC_TYPE_FRAMES: + printf(fmt, item->frames); + break; + case CALC_TYPE_BYTES: + case CALC_TYPE_COUNT: + printf(fmt, item->counter); + break; + case CALC_TYPE_FRAMES_AND_BYTES: + printf(fmt, item->frames, item->counter); + break; + + case CALC_TYPE_SUM: + case CALC_TYPE_MIN: + case CALC_TYPE_MAX: + ftype = proto_registrar_get_ftype(stat_cols[j]->hf_index); + switch(ftype){ + case FT_FLOAT: + printf(fmt, item->float_counter); + break; + case FT_DOUBLE: + printf(fmt, item->double_counter); + break; + case FT_RELATIVE_TIME: + item->counter = (item->counter + 500) / 1000; + printf(fmt, (int)(item->counter/1000000), (int)(item->counter%1000000)); + break; + default: + printf(fmt, item->counter); + break; + } + break; + + case CALC_TYPE_AVG: + num = item->num; + if(num==0) + num=1; + ftype = proto_registrar_get_ftype(stat_cols[j]->hf_index); + switch(ftype){ + case FT_FLOAT: + printf(fmt, item->float_counter/num); + break; + case FT_DOUBLE: + printf(fmt, item->double_counter/num); + break; + case FT_RELATIVE_TIME: + item->counter = ((item->counter/num) + 500) / 1000; + printf(fmt, + (int)(item->counter/1000000), (int)(item->counter%1000000)); + break; + default: + printf(fmt, item->counter/num); + break; + } + break; + + case CALC_TYPE_LOAD: + ftype = proto_registrar_get_ftype(stat_cols[j]->hf_index); + switch(ftype){ + case FT_RELATIVE_TIME: + if (!last_row) { + printf(fmt, + (int) (item->counter/interval), + (int)((item->counter%interval)*1000000 / interval)); + } else { + printf(fmt, + (int) (item->counter/(invl_end-t)), + (int)((item->counter%(invl_end-t))*1000000 / (invl_end-t))); + } + break; + } + break; + } + if (last_row) + g_free(fmt); + + } else { + printf(fmt, (guint64)0); + } + } + if (filler_s > 0) + printf("%s|", filler_s); + printf("\n"); + t += interval; + + } + for(i=0;iitems[i].frames=0; io->items[i].counter=0; io->items[i].num=0; + io->filters[i]=filter; flt=filter; @@ -767,18 +1031,20 @@ register_io_tap(io_stat_t *io, int i, const char *filter) namelen=strlen(calc_type_table[j].func_name); if(filter && strncmp(filter, calc_type_table[j].func_name, namelen) == 0) { io->items[i].calc_type=calc_type_table[j].calc_type; + io->items[i].colnum = i; if(*(filter+namelen)=='(') { p=filter+namelen+1; parenp=strchr(p, ')'); if(!parenp){ - fprintf(stderr, "\ntshark: Closing parenthesis missing from calculated expression.\n"); + fprintf(stderr, + "\ntshark: Closing parenthesis missing from calculated expression.\n"); exit(10); } - if(io->items[i].calc_type==CALC_TYPE_FRAMES || io->items[i].calc_type==CALC_TYPE_BYTES){ if(parenp!=p) { - fprintf(stderr, "\ntshark: %s does require or allow a field name within the parens.\n", + fprintf(stderr, + "\ntshark: %s does not require or allow a field name within the parens.\n", calc_type_table[j].func_name); exit(10); } @@ -811,6 +1077,7 @@ register_io_tap(io_stat_t *io, int i, const char *filter) } else { if (io->items[i].calc_type==CALC_TYPE_FRAMES || io->items[i].calc_type==CALC_TYPE_BYTES) flt=""; + io->items[i].colnum = i; } } if(hfi && !(io->items[i].calc_type==CALC_TYPE_BYTES || @@ -873,7 +1140,8 @@ register_io_tap(io_stat_t *io, int i, const char *filter) */ if(io->items[i].calc_type!=CALC_TYPE_COUNT){ fprintf(stderr, - "\ntshark: %s doesn't have integral values, so %s(*) calculations are not supported on it.\n", + "\ntshark: %s doesn't have integral values, so %s(*) " + "calculations are not supported on it.\n", field, calc_type_table[j].func_name); exit(10); @@ -883,7 +1151,8 @@ register_io_tap(io_stat_t *io, int i, const char *filter) g_free(field); } - error_string=register_tap_listener("frame", &io->items[i], flt, TL_REQUIRES_PROTO_TREE, NULL, iostat_packet, i?NULL:iostat_draw); + error_string=register_tap_listener("frame", &io->items[i], flt, TL_REQUIRES_PROTO_TREE, NULL, + iostat_packet, i?NULL:iostat_draw); if(error_string){ g_free(io->items); g_free(io); @@ -898,80 +1167,91 @@ static void iostat_init(const char *optarg, void* userdata _U_) { gdouble interval_float; - gint64 interval; - int idx=0; + guint32 idx=0, i; io_stat_t *io; - const char *filter=NULL; - - if(sscanf(optarg,"io,stat,%lf,%n",&interval_float,&idx)==1){ - if(idx){ - if(*(optarg+idx)==',') - filter=optarg+idx+1; - else - filter=optarg+idx; - } else { - filter=NULL; - } - } else { + const char *filters=NULL, *str, *pos; + + if (sscanf(optarg, "io,stat,%lf,%n", &interval_float, &idx)==0) { fprintf(stderr, "\ntshark: invalid \"-z io,stat,[,]\" argument\n"); exit(1); } - - /* if interval is 0, calculate statistics over the whole file - * by setting the interval to G_MAXINT32 - */ - if(interval_float==0) { - interval=G_MAXINT32; + + io = g_malloc(sizeof(io_stat_t)); + + /* If interval is 0, calculate statistics over the whole file by setting the interval to + * G_MAXINT32 */ + if (interval_float==0) { + io->interval = G_MAXINT32; + io->invl_prec = 0; } else { - /* make interval be number of us rounded to the nearest integer*/ - interval=(gint64)(interval_float*1000000.0+0.5); + /* Set interval to the number of us rounded to the nearest integer */ + io->interval = (gint64)(interval_float*1000000.0+0.5); + /* + * Determine what interval precision the user has specified */ + io->invl_prec = 6; + for (i=10; i<10000000; i*=10) { + if (io->interval%i > 0) + break; + io->invl_prec--; + } } - - if(interval<1){ + if (io->interval < 1){ fprintf(stderr, "\ntshark: \"-z\" interval must be >=0.000001 seconds or \"0\" for the entire capture duration.\n"); exit(10); } - io=g_malloc(sizeof(io_stat_t)); - io->interval=interval; - if((!filter)||(filter[0]==0)){ - io->num_items=1; - io->items=g_malloc(sizeof(io_stat_item_t)*io->num_items); - io->filters=g_malloc(sizeof(char *)*io->num_items); - - register_io_tap(io, 0, NULL); + /* Find how many ',' separated filters we have */ + io->num_cols = 1; + + if (idx) { + filters = optarg + idx; + if (strlen(filters) > 0 ) { + str = filters; + while((str = strchr(str, ','))) { + io->num_cols++; + str++; + } + } } else { - const char *str,*pos; - char *tmp; - int i; - /* find how many ',' separated filters we have */ - str=filter; - io->num_items=1; - while((str=strchr(str,','))){ - io->num_items++; - str++; - } - - io->items=g_malloc(sizeof(io_stat_item_t)*io->num_items); - io->filters=g_malloc(sizeof(char *)*io->num_items); + filters=NULL; + } - /* for each filter, register a tap listener */ - i=0; - str=filter; - do{ - pos=strchr(str,','); + io->items = g_malloc(sizeof(io_stat_item_t) * io->num_cols); + io->filters = g_malloc(sizeof(char *) * io->num_cols); + io->max_vals = g_malloc(sizeof(guint64) * io->num_cols); + io->max_frames = g_malloc(sizeof(guint64) * io->num_cols); + + for (i=0; inum_cols; i++) { + io->max_vals[i] = 0; + io->max_frames[i] = 0; + } + + /* Register a tap listener for each filter */ + if((!filters) || (filters[0]==0)) { + register_io_tap(io, 0, NULL); + } else { + const char *filter; + i = 0; + str = filters; + do { + pos = strchr(str, ','); if(pos==str){ register_io_tap(io, i, NULL); - } else if(pos==NULL) { - tmp=g_strdup(str); - register_io_tap(io, i, tmp); + } else if (pos==NULL) { + str = g_strstrip((gchar*)str); + filter = g_strdup((gchar*)str); + if (*filter) + register_io_tap(io, i, filter); + else + register_io_tap(io, i, NULL); } else { - tmp=g_malloc((pos-str)+1); - g_strlcpy(tmp,str,(pos-str)+1); - register_io_tap(io, i, tmp); + filter = g_malloc((pos-str)+1); + g_strlcpy((gchar*)filter, str, (pos-str)+1); + filter = g_strstrip((gchar*)filter); + register_io_tap(io, i, filter); } - str=pos+1; + str = pos+1; i++; } while(pos); } -- cgit v1.2.1