Get rid of -Wshadow warning - I guess we're including something that
[metze/wireshark/wip.git] / ui / cli / tap-iostat.c
index 8d7dbf80ba131bcbf64797374932a00488979f64..b6835946bda86d7cc18645f6f523345fa30f2fed 100644 (file)
@@ -22,9 +22,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
 
 #include <stdio.h>
 
 #include "globals.h"
 
 #define CALC_TYPE_FRAMES 0
-#define CALC_TYPE_BYTES         1
-#define CALC_TYPE_FRAMES_AND_BYTES      2
-#define CALC_TYPE_COUNT         3
-#define CALC_TYPE_SUM   4
-#define CALC_TYPE_MIN   5
-#define CALC_TYPE_MAX   6
-#define CALC_TYPE_AVG   7
-#define CALC_TYPE_LOAD  8
+#define CALC_TYPE_BYTES  1
+#define CALC_TYPE_FRAMES_AND_BYTES 2
+#define CALC_TYPE_COUNT  3
+#define CALC_TYPE_SUM    4
+#define CALC_TYPE_MIN    5
+#define CALC_TYPE_MAX    6
+#define CALC_TYPE_AVG    7
+#define CALC_TYPE_LOAD   8
 
 typedef struct {
     const char *func_name;
@@ -68,7 +66,7 @@ static calc_type_ent_t calc_type_table[] = {
 typedef struct _io_stat_t {
     guint64 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 */
+    int num_cols;         /* The number of columns of stats in the table */
     struct _io_stat_item_t *items;  /* Each item is a single cell in the table */
     time_t start_time;    /* Time of first frame matching the filter */
     const char **filters; /* 'io,stat' cmd strings (e.g., "AVG(smb.time)smb.time") */
@@ -91,7 +89,9 @@ typedef struct _io_stat_item_t {
     gdouble double_counter;
 } io_stat_item_t;
 
-#define NANOSECS_PER_SEC 1000000000
+#define NANOSECS_PER_SEC 1000000000ULL
+
+static guint64 last_relative_time;
 
 static int
 iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *dummy _U_)
@@ -104,25 +104,29 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du
     GPtrArray *gp;
     guint i;
     int ftype;
-    
+
     mit = (io_stat_item_t *) arg;
     parent = mit->parent;
-    relative_time = (guint64)((pinfo->fd->rel_ts.secs*1000000) + ((pinfo->fd->rel_ts.nsecs+500)/1000));
+
+    /* If this frame's relative time is negative, set its relative time to last_relative_time
+       rather than disincluding it from the calculations. */
+    if (pinfo->rel_ts.secs >= 0) {
+        relative_time = ((guint64)pinfo->rel_ts.secs * 1000000ULL) +
+                        ((guint64)((pinfo->rel_ts.nsecs+500)/1000));
+        last_relative_time = relative_time;
+    } else {
+        relative_time = last_relative_time;
+    }
+
     if (mit->parent->start_time == 0) {
-        mit->parent->start_time = pinfo->fd->abs_ts.secs - pinfo->fd->rel_ts.secs;
+        mit->parent->start_time = pinfo->fd->abs_ts.secs - pinfo->rel_ts.secs;
     }
 
-    /* The prev item before the main one is always the last interval we saw packets for */
+    /* The prev item is always the last interval in which we saw packets. */
     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(relative_time < it->time){
-        return FALSE;
-    }
-
     /* 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 
+    *  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) {
@@ -184,15 +188,15 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du
                     it->counter += (gint64)fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
                     break;
                 case FT_FLOAT:
-                    it->float_counter += 
+                    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);
                     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);
+                    new_time = (nstime_t *)fvalue_get(&((field_info *)gp->pdata[i])->value);
+                    val = ((guint64)new_time->secs * NANOSECS_PER_SEC) + (guint64)new_time->nsecs;
                     it->counter  +=  val;
                     break;
                 default:
@@ -244,7 +248,7 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du
                     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);
@@ -256,11 +260,11 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du
                     double_val=fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
                     if((it->frames==1 && i==0) || (double_val < it->double_counter)) {
                         it->double_counter=double_val;
-                    } 
+                    }
                     break;
                 case FT_RELATIVE_TIME:
                     new_time = (nstime_t *)fvalue_get(&((field_info *)gp->pdata[i])->value);
-                    val = (guint64)new_time->secs * NANOSECS_PER_SEC + new_time->nsecs;
+                    val = ((guint64)new_time->secs * NANOSECS_PER_SEC) + (guint64)new_time->nsecs;
                     if((it->frames==1 && i==0) || (val < it->counter)) {
                         it->counter=val;
                     }
@@ -296,7 +300,7 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du
                     break;
                 case FT_UINT64:
                     val = fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
-                    if(val > it->counter) 
+                    if(val > it->counter)
                         it->counter=val;
                     break;
                 case FT_INT8:
@@ -304,12 +308,12 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du
                 case FT_INT24:
                 case FT_INT32:
                     val = fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
-                    if((gint32)val > (gint32)it->counter) 
+                    if((gint32)val > (gint32)it->counter)
                         it->counter=val;
                     break;
                 case FT_INT64:
                     val = fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
-                    if ((gint64)val > (gint64)it->counter) 
+                    if ((gint64)val > (gint64)it->counter)
                         it->counter=val;
                     break;
                 case FT_FLOAT:
@@ -324,7 +328,7 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du
                     break;
                 case FT_RELATIVE_TIME:
                     new_time = (nstime_t *)fvalue_get(&((field_info *)gp->pdata[i])->value);
-                    val = (guint64)((new_time->secs * NANOSECS_PER_SEC) + new_time->nsecs);
+                    val = ((guint64)new_time->secs * NANOSECS_PER_SEC) + (guint64)new_time->nsecs;
                     if (val>it->counter)
                         it->counter=val;
                     break;
@@ -343,7 +347,7 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du
         gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
         if(gp){
             guint64 val;
-        
+
             ftype=proto_registrar_get_ftype(it->hf_index);
             for(i=0;i<gp->len;i++){
                 it->num++;
@@ -375,7 +379,7 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du
                     break;
                 case FT_RELATIVE_TIME:
                     new_time = (nstime_t *)fvalue_get(&((field_info *)gp->pdata[i])->value);
-                    val = (guint64)((new_time->secs * NANOSECS_PER_SEC) + new_time->nsecs);
+                    val = ((guint64)new_time->secs * NANOSECS_PER_SEC) + (guint64)new_time->nsecs;
                     it->counter += val;
                     break;
                 default:
@@ -404,7 +408,7 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du
                 io_stat_item_t *pit;
 
                 new_time = (nstime_t *)fvalue_get(&((field_info *)gp->pdata[i])->value);
-                val = (guint64)((new_time->secs*1000000) + (new_time->nsecs/1000));
+                val = ((guint64)new_time->secs*1000000ULL) + (guint64)(new_time->nsecs/1000);
                 tival = (int)(val % parent->interval);
                 it->counter += tival;
                 val -= tival;
@@ -422,21 +426,21 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du
         }
         break;
     }
-    /* Store the highest value for this item in order to determine the width of each stat column. 
+    /* 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. 
+    *  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_frame[it->colnum] = 
+            parent->max_frame[it->colnum] =
                 MAX(parent->max_frame[it->colnum], it->frames);
             if (it->calc_type==CALC_TYPE_FRAMES_AND_BYTES)
-                parent->max_vals[it->colnum] = 
+                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:
@@ -448,20 +452,20 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du
             ftype=proto_registrar_get_ftype(it->hf_index);
             switch(ftype) {
                 case FT_FLOAT:
-                    parent->max_vals[it->colnum] = 
+                    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] = 
+                    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;                
+                    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] = 
+                    parent->max_vals[it->colnum] =
                         MAX(parent->max_vals[it->colnum], it->counter);
                     break;
             }
@@ -472,20 +476,20 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du
             ftype=proto_registrar_get_ftype(it->hf_index);
             switch(ftype) {
                 case FT_FLOAT:
-                    parent->max_vals[it->colnum] = 
+                    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] = 
+                    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); 
+                    parent->max_vals[it->colnum] =
+                        MAX(parent->max_vals[it->colnum], ((it->counter/(guint64)it->num) + 500000000ULL) / NANOSECS_PER_SEC);
                     break;
                 default:
                     /* UINT16-64 and INT8-64 */
-                    parent->max_vals[it->colnum] = 
+                    parent->max_vals[it->colnum] =
                         MAX(parent->max_vals[it->colnum], it->counter/it->num);
                     break;
             }
@@ -493,21 +497,21 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du
     return TRUE;
 }
 
-static int 
+static int
 magnitude (guint64 val, int max_w)
 {
     int i, mag=0;
 
     for (i=0; i<max_w; i++) {
         mag++;
-        if ((val /= 10)==0) 
-            break;            
+        if ((val /= 10)==0)
+            break;
     }
     return(mag);
 }
 
-/*  
-*  Print the calc_type_table[] function label centered in the column header. 
+/*
+*  Print the calc_type_table[] function label centered in the column header.
 */
 static void
 printcenter (const char *label, int lenval, int numpad)
@@ -517,11 +521,11 @@ printcenter (const char *label, int lenval, int numpad)
 
     len = (int) (strlen(spaces)) - (((lenval-lenlab) / 2) + numpad);
     if (len > 0 && len < 6) {
-        spaces_ptr = &spaces[len];       
+        spaces_ptr = &spaces[len];
         if ((lenval-lenlab)%2==0) {
             printf("%s%s%s|", spaces_ptr, label, spaces_ptr);
         } else {
-            printf("%s%s%s|", spaces_ptr-1, label, spaces_ptr);             
+            printf("%s%s%s|", spaces_ptr-1, label, spaces_ptr);
         }
     } else if (len > 0 && len <= 15) {
         printf("%s|", label);
@@ -537,18 +541,19 @@ static void
 iostat_draw(void *arg)
 {
     guint32 num;
-    guint64 interval, duration, t, invl_end;
-    int i, j, k, num_cols, num_rows, dv, dur_secs, dur_mag, invl_mag, invl_prec, tabrow_w,
-        borderlen, invl_col_w, numpad=1, namelen, len_filt, type, maxfltr_w, ftype;
+    guint64 interval, duration, t, invl_end, dv;
+    int i, j, k, num_cols, num_rows, dur_secs_orig, dur_nsecs_orig, dur_secs, dur_nsecs, dur_mag,
+        invl_mag, invl_prec, tabrow_w, borderlen, invl_col_w, numpad=1, namelen, len_filt, type,
+        maxfltr_w, ftype;
     int fr_mag;    /* The magnitude of the max frame number in this column */
     int val_mag;   /* The magnitude of the max value in this column */
     char *spaces, *spaces_s, *filler_s=NULL, **fmts, *fmt=NULL;
     const char *filter;
-    static gchar dur_mag_s[3], invl_mag_s[3], invl_prec_s[3], fr_mag_s[3], val_mag_s[3], *invl_fmt, *full_fmt;
+    static gchar dur_mag_s[3], invl_prec_s[3], fr_mag_s[3], val_mag_s[3], *invl_fmt, *full_fmt;
     io_stat_item_t *mit, **stat_cols, *item, **item_in_column;
     gboolean last_row=FALSE;
     io_stat_t *iot;
-    column_width *col_w; 
+    column_width *col_w;
     struct tm * tm_time;
     time_t the_time;
 
@@ -557,7 +562,8 @@ iostat_draw(void *arg)
     num_cols = iot->num_cols;
     col_w = (column_width *)g_malloc(sizeof(column_width) * num_cols);
     fmts = (char **)g_malloc(sizeof(char *) * num_cols);
-    duration = (guint64)((cfile.elapsed_time.secs*1000000) + ((cfile.elapsed_time.nsecs+500)/1000));
+    duration = ((guint64)cfile.elapsed_time.secs * 1000000ULL) +
+                (guint64)((cfile.elapsed_time.nsecs + 500) / 1000);
 
     /* Store the pointer to each stat column */
     stat_cols = (io_stat_item_t **) g_malloc(sizeof(io_stat_item_t *) * num_cols);
@@ -574,21 +580,24 @@ iostat_draw(void *arg)
     }
 
     /* Calc the capture duration's magnitude (dur_mag) */
-    dur_secs = (int)duration/1000000;
+    dur_secs  = (int)(duration/1000000ULL);
+    dur_secs_orig = dur_secs;
+    dur_nsecs = (int)(duration%1000000ULL);
+    dur_nsecs_orig = dur_nsecs;
     dur_mag = magnitude((guint64)dur_secs, 5);
-    g_snprintf(dur_mag_s, 3, "%u", dur_mag);  
+    g_snprintf(dur_mag_s, 3, "%u", dur_mag);
 
     /* Calc the interval's magnitude */
-    invl_mag = magnitude((guint64)interval/1000000, 5); 
+    invl_mag = magnitude(interval/1000000ULL, 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) 
+        else if (dur_mag==1)
             invl_prec = 3;
         else
             invl_prec = 6;
@@ -603,32 +612,30 @@ iostat_draw(void *arg)
     dv=1000000;
     for (i=0; i<invl_prec; i++)
         dv /= 10;
-    duration = duration + (5*(dv/10));
-    if (iot->interval==G_MAXINT32) 
+    if ((duration%dv) > 5*(dv/10)) {
+        duration += 5*(dv/10);
+        duration = (duration/dv) * dv;
+        dur_secs  = (int)(duration/1000000ULL);
+        dur_nsecs = (int)(duration%1000000ULL);
+        /*
+         * Recalc dur_mag in case rounding has increased its magnitude */
+        dur_mag  = magnitude((guint64)dur_secs, 5);
+    }
+    if (iot->interval==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) 
+    if (invl_prec==0)
         invl_col_w = (2*dur_mag) + 8;
     else
         invl_col_w = (2*dur_mag) + (2*invl_prec) + 10;
 
-    /* Update the width of the time interval column (in fact the date) */ 
-    switch (timestamp_get_type()) {
-    case TS_ABSOLUTE:
-      invl_col_w=12;
-      break;
-    case TS_ABSOLUTE_WITH_DATE:
-      invl_col_w=23;
-      break;
-    default:
-      break;
-    }
-    invl_col_w = MAX(invl_col_w, 12);
+    /* Update the width of the time interval column for "-t ad" */
+    if (timestamp_get_type()==TS_ABSOLUTE_WITH_DATE)
+        invl_col_w = MAX(invl_col_w, 23);
+    else
+        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
@@ -653,9 +660,9 @@ iostat_draw(void *arg)
             g_snprintf(fr_mag_s, 3, "%u", fr_mag);
 
             if (type==CALC_TYPE_FRAMES) {
-                fmt = g_strconcat(" %", fr_mag_s, "u |", NULL);                    
-            } else { 
-                /* CALC_TYPE_FRAMES_AND_BYTES 
+                fmt = g_strconcat(" %", fr_mag_s, "u |", NULL);
+            } else {
+                /* CALC_TYPE_FRAMES_AND_BYTES
                 */
                 val_mag = magnitude(iot->max_vals[j], 15);
                 val_mag = MAX(5, val_mag);
@@ -678,10 +685,10 @@ iostat_draw(void *arg)
             g_snprintf(val_mag_s, 3, "%u", val_mag);
             fmt = g_strconcat(" %", val_mag_s, G_GINT64_MODIFIER, "u |", NULL);
             break;
-            
+
         default:
             ftype = proto_registrar_get_ftype(stat_cols[j]->hf_index);
-            switch (ftype) {    
+            switch (ftype) {
                 case FT_FLOAT:
                 case FT_DOUBLE:
                     val_mag = magnitude(iot->max_vals[j], 15);
@@ -690,25 +697,25 @@ iostat_draw(void *arg)
                     col_w[j].val = val_mag + 7;
                     break;
                 case FT_RELATIVE_TIME:
-                    /* Convert FT_RELATIVE_TIME field to seconds 
+                    /* 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;
+                    } else if (type != CALC_TYPE_AVG) {
+                        iot->max_vals[j] = (iot->max_vals[j] + 500000000ULL) / NANOSECS_PER_SEC;
                     }
                     val_mag = magnitude(iot->max_vals[j], 15);
                     g_snprintf(val_mag_s, 3, "%u", val_mag);
                     fmt = g_strconcat(" %", val_mag_s, "u.%06u |", NULL);
                     col_w[j].val = val_mag + 7;
-                   break;    
-                
+                   break;
+
                 default:
                     val_mag = magnitude(iot->max_vals[j], 15);
                     val_mag = MAX(namelen, val_mag);
                     col_w[j].val = val_mag;
                     g_snprintf(val_mag_s, 3, "%u", val_mag);
-                    
+
                     switch (ftype) {
                     case FT_UINT8:
                     case FT_UINT16:
@@ -716,7 +723,7 @@ iostat_draw(void *arg)
                     case FT_UINT32:
                     case FT_UINT64:
                         fmt = g_strconcat(" %", val_mag_s, G_GINT64_MODIFIER, "u |", NULL);
-                        break;            
+                        break;
                     case FT_INT8:
                     case FT_INT16:
                     case FT_INT24:
@@ -728,11 +735,11 @@ iostat_draw(void *arg)
             } /* End of ftype switch */
         } /* End of calc_type switch */
         tabrow_w += col_w[j].val + 3;
-        if (fmt) 
+        if (fmt)
             fmts[j] = fmt;
     } /* End of for loop (columns) */
 
-    borderlen = MAX(borderlen, tabrow_w); 
+    borderlen = MAX(borderlen, tabrow_w);
 
     /* Calc the max width of the list of filters. */
     maxfltr_w = 0;
@@ -747,7 +754,7 @@ iostat_draw(void *arg)
     /* 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. 
+    *  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)
@@ -755,63 +762,63 @@ iostat_draw(void *arg)
 
     /* Prevent double right border by adding a space */
     if (borderlen-tabrow_w==1)
-        borderlen++; 
+        borderlen++;
 
     /* Display the top border */
     printf("\n");
     for (i=0; i<borderlen; i++)
         printf("=");
-    
+
     spaces = (char*) g_malloc(borderlen+1);
-    for (i=0; i<borderlen; i++) 
+    for (i=0; i<borderlen; i++)
         spaces[i] = ' ';
     spaces[borderlen] = '\0';
-    
+
     spaces_s = &spaces[16];
     printf("\n| IO Statistics%s|\n", spaces_s);
     spaces_s = &spaces[2];
     printf("|%s|\n", spaces_s);
-   
-    g_snprintf(invl_mag_s, 3, "%u", invl_mag);
-    if (invl_prec > 0) {
-        g_snprintf(invl_prec_s, 3, "%u", invl_prec);  
-        invl_fmt = g_strconcat("%", invl_mag_s, "u.%0", invl_prec_s, "u", NULL);            
-        if (interval==duration) {
-            full_fmt = g_strconcat("| Interval size: ", invl_fmt, " secs (dur)%s", NULL);
-            spaces_s = &spaces[30+invl_mag+invl_prec];
-        } else {
-            full_fmt = g_strconcat("| Interval size: ", invl_fmt, " secs%s", NULL);
-            spaces_s = &spaces[24+invl_mag+invl_prec];
-        }
-        printf(full_fmt, (guint32)interval/1000000,
-                            (guint32)((interval%1000000)/dv), spaces_s);
+
+    if (invl_prec==0) {
+        invl_fmt = g_strconcat("%", dur_mag_s, "u", NULL);
+        full_fmt = g_strconcat("| Duration: ", invl_fmt, ".%6u secs%s|\n", NULL);
+        spaces_s = &spaces[25 + dur_mag];
+        printf(full_fmt, dur_secs_orig, dur_nsecs_orig, spaces_s);
+        g_free(full_fmt);
+        full_fmt = g_strconcat("| Interval: ", invl_fmt, " secs%s|\n", NULL);
+        spaces_s = &spaces[18 + dur_mag];
+        printf(full_fmt, (guint32)(interval/1000000ULL), spaces_s);
     } else {
-        invl_fmt = g_strconcat("%", invl_mag_s, "u", NULL);
-        full_fmt = g_strconcat("| Interval size: ", invl_fmt, " secs%s", NULL);
-        spaces_s = &spaces[23 + invl_mag];
-        printf(full_fmt, (guint32)interval/1000000, spaces_s);
+        g_snprintf(invl_prec_s, 3, "%u", invl_prec);
+        invl_fmt = g_strconcat("%", dur_mag_s, "u.%0", invl_prec_s, "u", NULL);
+        full_fmt = g_strconcat("| Duration: ", invl_fmt, " secs%s|\n", NULL);
+        spaces_s = &spaces[19 + dur_mag + invl_prec];
+        printf(full_fmt, dur_secs, dur_nsecs/(int)dv, spaces_s);
+        g_free(full_fmt);
+
+        full_fmt = g_strconcat("| Interval: ", invl_fmt, " secs%s|\n", NULL);
+        spaces_s = &spaces[19 + dur_mag + invl_prec];
+        printf(full_fmt, (guint32)(interval/1000000ULL),
+                         (guint32)((interval%1000000ULL)/dv), 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", NULL);
-    else 
-        invl_fmt = g_strconcat("%", dur_mag_s, "u", NULL);
-    
+    spaces_s = &spaces[2];
+    printf("|%s|\n", spaces_s);
+
     /* Display the list of filters and their column numbers vertically */
-    printf("|\n| Col");
+    printf("| Col");
     for(j=0; j<num_cols; j++){
         printf((j==0 ? "%2u: " : "|    %2u: "), j+1);
-        if (!iot->filters[j] || (iot->filters[j]==0)) { 
-            /* 
+        if (!iot->filters[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) {
@@ -826,11 +833,11 @@ iostat_draw(void *arg)
                 const gchar *pos;
                 gsize len;
                 int next_start, max_w=borderlen-11;
-                
+
                 do {
                     if (len_filt > max_w) {
                         sfilter1 = g_strndup( (gchar *) filter, (gsize) 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. */
@@ -854,7 +861,7 @@ iostat_draw(void *arg)
                         printf("%s%s|\n", filter, &spaces[((int)strlen(filter))+10]);
                         break;
                     }
-                } while (1); 
+                } while (1);
             }
         }
     }
@@ -873,11 +880,11 @@ iostat_draw(void *arg)
     for(j=0; j<num_cols; j++) {
         item = stat_cols[j];
         if(item->calc_type==CALC_TYPE_FRAMES_AND_BYTES)
-            spaces_s = &spaces[borderlen - (col_w[j].fr + col_w[j].val)] - 3; 
+            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]; 
+            spaces_s = &spaces[borderlen - col_w[j].fr];
         else
-            spaces_s = &spaces[borderlen - col_w[j].val]; 
+            spaces_s = &spaces[borderlen - col_w[j].val];
 
         printf("%-2u%s|", j+1, spaces_s);
     }
@@ -885,24 +892,25 @@ iostat_draw(void *arg)
         filler_s = &spaces[tabrow_w+1];
         printf("%s|", filler_s);
     }
-    
-    printf("\n| Interval");
+
+    k = 11;
     switch (timestamp_get_type()) {
     case TS_ABSOLUTE:
-      printf("\n| Time    ");
-      break;
+        printf("\n| Time    ");
+        break;
     case TS_ABSOLUTE_WITH_DATE:
-      printf("\n| Date    ");
-      break;
+        printf("\n| Date and time");
+        k = 16;
+        break;
     case TS_RELATIVE:
     case TS_NOT_SET:
-      printf("\n| Interval");
-      break;
+        printf("\n| Interval");
+        break;
     default:
-      break;
+        break;
     }
 
-    spaces_s = &spaces[borderlen-(invl_col_w-11)];
+    spaces_s = &spaces[borderlen-(invl_col_w-k)];
     printf("%s|", spaces_s);
 
     /* Display the stat label in each column */
@@ -930,16 +938,24 @@ iostat_draw(void *arg)
 
     printf("\n");
     t=0;
-    full_fmt = g_strconcat("| ", invl_fmt, " <> ", invl_fmt, " |", NULL);
-    num_rows = (int)(duration/interval) + (((duration%interval+500000)/1000000) > 0 ? 1 : 0);
+    if (invl_prec==0 && dur_mag==1)
+        full_fmt = g_strconcat("|  ", invl_fmt, " <> ", invl_fmt, "  |", NULL);
+    else
+        full_fmt = g_strconcat("| ", invl_fmt, " <> ", invl_fmt, " |", NULL);
+
+    if (interval == 0 || duration == 0) {
+        num_rows = 0;
+    } else {
+        num_rows = (int)(duration/interval) + ((int)(duration%interval) > 0 ? 1 : 0);
+    }
 
     /* Load item_in_column with the first item in each column */
-    item_in_column = (io_stat_item_t **) g_malloc(sizeof(io_stat_item_t) * num_cols);
+    item_in_column = (io_stat_item_t **) g_malloc(sizeof(io_stat_item_t *) * num_cols);
     for (j=0; j<num_cols; j++) {
         item_in_column[j] = stat_cols[j];
     }
 
-    /* Display the table values 
+    /* Display the table values
     *
     * The outer loop is for time interval rows and the inner loop is for stat column items.*/
     for (i=0; i<num_rows; i++) {
@@ -955,18 +971,19 @@ iostat_draw(void *arg)
         }
 
         /* Patch for Absolute Time */
-        the_time=iot->start_time+(guint32)(t/1000000);
+        /* XXX - has a Y2.038K problem with 32-bit time_t */
+        the_time = (time_t)(iot->start_time + (t/1000000ULL));
         tm_time = localtime(&the_time);
 
         /* Display the interval for this row */
-        switch (timestamp_get_type()) {          
+        switch (timestamp_get_type()) {
         case TS_ABSOLUTE:
           printf("| %02d:%02d:%02d |",
              tm_time->tm_hour,
              tm_time->tm_min,
              tm_time->tm_sec);
           break;
-          
+
         case TS_ABSOLUTE_WITH_DATE:
           printf("| %04d-%02d-%02d %02d:%02d:%02d |",
              tm_time->tm_year + 1900,
@@ -976,18 +993,29 @@ iostat_draw(void *arg)
              tm_time->tm_min,
              tm_time->tm_sec);
           break;
-          
+
         case TS_RELATIVE:
         case TS_NOT_SET:
 
           if (invl_prec==0) {
-              printf(full_fmt, (guint32)(t/1000000),
-                               (guint32)(invl_end/1000000));
+              if(last_row) {
+                  int maxw;
+                  maxw = dur_mag >= 3 ? dur_mag+1 : 3;
+                  g_free(full_fmt);
+                  g_snprintf(dur_mag_s, 3, "%u", maxw);
+                  full_fmt = g_strconcat( dur_mag==1 ? "|  " : "| ",
+                                          invl_fmt, " <> ", "%-",
+                                          dur_mag_s, "s|", NULL);
+                  printf(full_fmt, (guint32)(t/1000000ULL), "Dur");
+              } else {
+              printf(full_fmt, (guint32)(t/1000000ULL),
+                               (guint32)(invl_end/1000000ULL));
+              }
           } else {
-              printf(full_fmt, (guint32)(t/1000000),
-                               (guint32)(t%1000000) / dv,
-                               (guint32) (invl_end/1000000),
-                               (guint32)((invl_end%1000000) / dv));
+              printf(full_fmt, (guint32)(t/1000000ULL),
+                               (guint32)(t%1000000ULL / dv),
+                               (guint32)(invl_end/1000000ULL),
+                               (guint32)(invl_end%1000000ULL / dv));
           }
           break;
      /* case TS_DELTA:
@@ -1003,7 +1031,7 @@ iostat_draw(void *arg)
         /* Display stat values in each column for this row */
         for (j=0; j<num_cols; j++) {
             fmt = fmts[j];
-            item = item_in_column[j]; 
+            item = item_in_column[j];
 
             if (item) {
                 switch(item->calc_type) {
@@ -1030,8 +1058,8 @@ iostat_draw(void *arg)
                         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));
+                        item->counter = (item->counter + 500ULL) / 1000ULL;
+                        printf(fmt, (int)(item->counter/1000000ULL), (int)(item->counter%1000000ULL));
                         break;
                     default:
                         printf(fmt, item->counter);
@@ -1052,12 +1080,12 @@ iostat_draw(void *arg)
                         printf(fmt, item->double_counter/num);
                         break;
                     case FT_RELATIVE_TIME:
-                        item->counter = ((item->counter/num) + 500) / 1000;
+                        item->counter = ((item->counter / (guint64)num) + 500ULL) / 1000ULL;
                         printf(fmt,
-                            (int)(item->counter/1000000), (int)(item->counter%1000000));
+                            (int)(item->counter/1000000ULL), (int)(item->counter%1000000ULL));
                         break;
                     default:
-                        printf(fmt, item->counter/num);
+                        printf(fmt, item->counter / (guint64)num);
                         break;
                     }
                     break;
@@ -1068,12 +1096,12 @@ iostat_draw(void *arg)
                     case FT_RELATIVE_TIME:
                         if (!last_row) {
                             printf(fmt,
-                                (int) (item->counter/interval), 
-                                (int)((item->counter%interval)*1000000 / interval));                        
+                                (int) (item->counter/interval),
+                                (int)((item->counter%interval)*1000000ULL / interval));
                         } else {
                             printf(fmt,
                                 (int) (item->counter/(invl_end-t)),
-                                (int)((item->counter%(invl_end-t))*1000000 / (invl_end-t)));
+                                (int)((item->counter%(invl_end-t))*1000000ULL / (invl_end-t)));
                         }
                         break;
                     }
@@ -1084,17 +1112,17 @@ iostat_draw(void *arg)
                     if (fmt)
                         g_free(fmt);
                 } else {
-                    item_in_column[j] = item_in_column[j]->next; 
+                    item_in_column[j] = item_in_column[j]->next;
                 }
             } else {
-                printf(fmt, (guint64)0);
+                printf(fmt, (guint64)0, (guint64)0);
             }
         }
         if (filler_s)
             printf("%s|", filler_s);
         printf("\n");
         t += interval;
-       
+
     }
     for(i=0;i<borderlen;i++){
         printf("=");
@@ -1148,14 +1176,14 @@ register_io_tap(io_stat_t *io, int i, const char *filter)
                 p=filter+namelen+1;
                 parenp=strchr(p, ')');
                 if(!parenp){
-                    fprintf(stderr, 
+                    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, 
+                        fprintf(stderr,
                             "\ntshark: %s does not require or allow a field name within the parens.\n",
                             calc_type_table[j].func_name);
                         exit(10);
@@ -1276,18 +1304,47 @@ register_io_tap(io_stat_t *io, int i, const char *filter)
 }
 
 static void
-iostat_init(const char *optarg, void* userdata _U_)
+iostat_init(const char *opt_arg, void* userdata _U_)
 {
     gdouble interval_float;
-    guint32 idx=0, i;
+    guint32 idx=0;
+    int i;
     io_stat_t *io;
-    const gchar *filters=NULL, *str, *pos;
+    const gchar *filters, *str, *pos;
 
-    if (sscanf(optarg, "io,stat,%lf,%n", &interval_float, (int *)&idx)==0) {
-        fprintf(stderr, "\ntshark: invalid \"-z io,stat,<interval>[,<filter>]\" argument\n");
+    if ((*(opt_arg+(strlen(opt_arg)-1)) == ',') ||
+        (sscanf(opt_arg, "io,stat,%lf%n", &interval_float, (int *)&idx) != 1) ||
+        (idx < 8)) {
+        fprintf(stderr, "\ntshark: invalid \"-z io,stat,<interval>[,<filter>][,<filter>]...\" argument\n");
         exit(1);
     }
-    
+
+    filters=opt_arg+idx;
+    if (*filters) {
+        if (*filters != ',') {
+            /* For locale's that use ',' instead of '.', the comma might
+             * have been consumed during the floating point conversion. */
+            --filters;
+            if (*filters != ',') {
+                fprintf(stderr, "\ntshark: invalid \"-z io,stat,<interval>[,<filter>][,<filter>]...\" argument\n");
+                exit(1);
+            }
+        }
+    } else
+        filters=NULL;
+
+    switch (timestamp_get_type()) {
+    case TS_DELTA:
+    case TS_DELTA_DIS:
+    case TS_EPOCH:
+    case TS_UTC:
+    case TS_UTC_WITH_DATE:
+        fprintf(stderr, "\ntshark: invalid -t operand. io,stat only supports -t <r|a|ad>\n");
+        exit(1);
+    default:
+        break;
+    }
+
     io = (io_stat_t *) g_malloc(sizeof(io_stat_t));
 
     /* If interval is 0, calculate statistics over the whole file by setting the interval to
@@ -1297,15 +1354,37 @@ iostat_init(const char *optarg, void* userdata _U_)
         io->invl_prec = 0;
     } else {
         /* Set interval to the number of us rounded to the nearest integer */
-        io->interval = (gint64)(interval_float*1000000.0+0.5);
+        io->interval = (guint64)(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) { 
+        for (i=10; i<10000000; i*=10) {
             if (io->interval%i > 0)
                 break;
             io->invl_prec--;
         }
+        if (io->invl_prec==0) {
+            /* The precision is zero but if the user specified one of more zeros after the decimal point,
+               they want that many decimal places shown in the table for all time intervals except
+               response time values such as smb.time which always have 6 decimal places of precision.
+               This feature is useful in cases where for example the duration is 9.1, you specify an
+               interval of 1 and the last interval becomes "9 <> 9". If the interval is instead set to
+               1.1, the last interval becomes
+               last interval is rounded up to value that is greater than the duration. */
+            const gchar *invl_start = opt_arg+8;
+            gchar *intv_end;
+            int invl_len;
+
+            intv_end = g_strstr_len(invl_start, -1, ",");
+            invl_len = (int)(intv_end - invl_start);
+            invl_start = g_strstr_len(invl_start, invl_len, ".");
+
+            if (invl_start != NULL) {
+                invl_len = (int)(intv_end - invl_start - 1);
+                if (invl_len)
+                    io->invl_prec = MIN(invl_len, 6);
+            }
+        }
     }
     if (io->interval < 1){
         fprintf(stderr,
@@ -1317,28 +1396,25 @@ iostat_init(const char *optarg, void* userdata _U_)
     io->num_cols = 1;
     io->start_time=0;
 
-    if (idx) {
-        filters = optarg + idx;
-        if (strlen(filters) > 0 ) {
-            str = filters;
-            while((str = strchr(str, ','))) {
-                io->num_cols++;
-                str++;
-            }
+    if (filters && (*filters != '\0')) {
+        /* Eliminate the first comma. */
+        filters++;
+        str = filters;
+        while((str = strchr(str, ','))) {
+            io->num_cols++;
+            str++;
         }
-    } else {
-        filters=NULL;
     }
 
     io->items = (io_stat_item_t *) g_malloc(sizeof(io_stat_item_t) * io->num_cols);
-    io->filters = g_malloc(sizeof(char *) * io->num_cols);
+    io->filters = (const char **)g_malloc(sizeof(char *) * io->num_cols);
     io->max_vals = (guint64 *) g_malloc(sizeof(guint64) * io->num_cols);
     io->max_frame = (guint32 *) g_malloc(sizeof(guint32) * io->num_cols);
 
     for (i=0; i<io->num_cols; i++) {
         io->max_vals[i] = 0;
         io->max_frame[i] = 0;
-    } 
+    }
 
     /* Register a tap listener for each filter */
     if((!filters) || (filters[0]==0)) {
@@ -1352,14 +1428,14 @@ iostat_init(const char *optarg, void* userdata _U_)
             if(pos==str){
                 register_io_tap(io, i, NULL);
             } else if (pos==NULL) {
-                str = (char*) g_strstrip((gchar*)str);
+                str = (const char*) 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 {
-                filter = g_malloc((pos-str)+1);
+                filter = (gchar *)g_malloc((pos-str)+1);
                 g_strlcpy( filter, str, (gsize) ((pos-str)+1));
                 filter = g_strstrip(filter);
                 register_io_tap(io, i, (char *) filter);
@@ -1375,3 +1451,16 @@ register_tap_listener_iostat(void)
 {
     register_stat_cmd_arg("io,stat,", iostat_init, NULL);
 }
+
+/*
+ * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=4 expandtab:
+ * :indentSize=4:tabSize=4:noTabs=true:
+ */