25f5947512
Avoid walking off the end of an array when trying to format a number larger than 1000T. Motivated by #641, as reported by @shingchuang, but slightly reimplemented.
356 строки
8.9 KiB
C
356 строки
8.9 KiB
C
/*---------------------------------------------------------------
|
|
* Copyright (c) 1999,2000,2001,2002,2003
|
|
* The Board of Trustees of the University of Illinois
|
|
* All Rights Reserved.
|
|
*---------------------------------------------------------------
|
|
* Permission is hereby granted, free of charge, to any person
|
|
* obtaining a copy of this software (Iperf) and associated
|
|
* documentation files (the "Software"), to deal in the Software
|
|
* without restriction, including without limitation the
|
|
* rights to use, copy, modify, merge, publish, distribute,
|
|
* sublicense, and/or sell copies of the Software, and to permit
|
|
* persons to whom the Software is furnished to do
|
|
* so, subject to the following conditions:
|
|
*
|
|
*
|
|
* Redistributions of source code must retain the above
|
|
* copyright notice, this list of conditions and
|
|
* the following disclaimers.
|
|
*
|
|
*
|
|
* Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the following
|
|
* disclaimers in the documentation and/or other materials
|
|
* provided with the distribution.
|
|
*
|
|
*
|
|
* Neither the names of the University of Illinois, NCSA,
|
|
* nor the names of its contributors may be used to endorse
|
|
* or promote products derived from this Software without
|
|
* specific prior written permission.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT
|
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
* ________________________________________________________________
|
|
* National Laboratory for Applied Network Research
|
|
* National Center for Supercomputing Applications
|
|
* University of Illinois at Urbana-Champaign
|
|
* http://www.ncsa.uiuc.edu
|
|
* ________________________________________________________________
|
|
*
|
|
* stdio.c
|
|
* by Mark Gates <mgates@nlanr.net>
|
|
* and Ajay Tirumalla <tirumala@ncsa.uiuc.edu>
|
|
* -------------------------------------------------------------------
|
|
* input and output numbers, converting with kilo, mega, giga, tera
|
|
* ------------------------------------------------------------------- */
|
|
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
#ifdef HAVE_STDINT_H
|
|
#include <stdint.h>
|
|
#endif
|
|
#include <sys/socket.h>
|
|
#include <sys/types.h>
|
|
#include <sys/time.h>
|
|
|
|
|
|
#include "iperf.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C"
|
|
{
|
|
#endif
|
|
|
|
const double KILO_UNIT = 1024.0;
|
|
const double MEGA_UNIT = 1024.0 * 1024.0;
|
|
const double GIGA_UNIT = 1024.0 * 1024.0 * 1024.0;
|
|
const double TERA_UNIT = 1024.0 * 1024.0 * 1024.0 * 1024.0;
|
|
|
|
const double KILO_RATE_UNIT = 1000.0;
|
|
const double MEGA_RATE_UNIT = 1000.0 * 1000.0;
|
|
const double GIGA_RATE_UNIT = 1000.0 * 1000.0 * 1000.0;
|
|
const double TERA_RATE_UNIT = 1000.0 * 1000.0 * 1000.0 * 1000.0;
|
|
|
|
/* -------------------------------------------------------------------
|
|
* unit_atof
|
|
*
|
|
* Given a string of form #x where # is a number and x is a format
|
|
* character listed below, this returns the interpreted integer.
|
|
* Gg, Mm, Kk are giga, mega, kilo respectively
|
|
* ------------------------------------------------------------------- */
|
|
|
|
double unit_atof(const char *s)
|
|
{
|
|
double n;
|
|
char suffix = '\0';
|
|
|
|
assert(s != NULL);
|
|
|
|
/* scan the number and any suffices */
|
|
sscanf(s, "%lf%c", &n, &suffix);
|
|
|
|
/* convert according to [Tt Gg Mm Kk] */
|
|
switch (suffix)
|
|
{
|
|
case 't': case 'T':
|
|
n *= TERA_UNIT;
|
|
break;
|
|
case 'g': case 'G':
|
|
n *= GIGA_UNIT;
|
|
break;
|
|
case 'm': case 'M':
|
|
n *= MEGA_UNIT;
|
|
break;
|
|
case 'k': case 'K':
|
|
n *= KILO_UNIT;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return n;
|
|
} /* end unit_atof */
|
|
|
|
|
|
/* -------------------------------------------------------------------
|
|
* unit_atof_rate
|
|
*
|
|
* Similar to unit_atof, but uses 10-based rather than 2-based
|
|
* suffixes.
|
|
* ------------------------------------------------------------------- */
|
|
|
|
double unit_atof_rate(const char *s)
|
|
{
|
|
double n;
|
|
char suffix = '\0';
|
|
|
|
assert(s != NULL);
|
|
|
|
/* scan the number and any suffices */
|
|
sscanf(s, "%lf%c", &n, &suffix);
|
|
|
|
/* convert according to [Tt Gg Mm Kk] */
|
|
switch (suffix)
|
|
{
|
|
case 't': case 'T':
|
|
n *= TERA_RATE_UNIT;
|
|
break;
|
|
case 'g': case 'G':
|
|
n *= GIGA_RATE_UNIT;
|
|
break;
|
|
case 'm': case 'M':
|
|
n *= MEGA_RATE_UNIT;
|
|
break;
|
|
case 'k': case 'K':
|
|
n *= KILO_RATE_UNIT;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return n;
|
|
} /* end unit_atof_rate */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------
|
|
* unit_atoi
|
|
*
|
|
* Given a string of form #x where # is a number and x is a format
|
|
* character listed below, this returns the interpreted integer.
|
|
* Tt, Gg, Mm, Kk are tera, giga, mega, kilo respectively
|
|
* ------------------------------------------------------------------- */
|
|
|
|
iperf_size_t unit_atoi(const char *s)
|
|
{
|
|
double n;
|
|
char suffix = '\0';
|
|
|
|
assert(s != NULL);
|
|
|
|
/* scan the number and any suffices */
|
|
sscanf(s, "%lf%c", &n, &suffix);
|
|
|
|
/* convert according to [Tt Gg Mm Kk] */
|
|
switch (suffix)
|
|
{
|
|
case 't': case 'T':
|
|
n *= TERA_UNIT;
|
|
break;
|
|
case 'g': case 'G':
|
|
n *= GIGA_UNIT;
|
|
break;
|
|
case 'm': case 'M':
|
|
n *= MEGA_UNIT;
|
|
break;
|
|
case 'k': case 'K':
|
|
n *= KILO_UNIT;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return (iperf_size_t) n;
|
|
} /* end unit_atof */
|
|
|
|
/* -------------------------------------------------------------------
|
|
* constants for byte_printf
|
|
* ------------------------------------------------------------------- */
|
|
|
|
/* used as indices into conversion_bytes[], label_byte[], and label_bit[] */
|
|
enum
|
|
{
|
|
UNIT_CONV,
|
|
KILO_CONV,
|
|
MEGA_CONV,
|
|
GIGA_CONV,
|
|
TERA_CONV
|
|
};
|
|
|
|
/* factor to multiply the number by */
|
|
const double conversion_bytes[] =
|
|
{
|
|
1.0, /* unit */
|
|
1.0 / 1024, /* kilo */
|
|
1.0 / 1024 / 1024, /* mega */
|
|
1.0 / 1024 / 1024 / 1024, /* giga */
|
|
1.0 / 1024 / 1024 / 1024 / 1024 /* tera */
|
|
};
|
|
|
|
/* factor to multiply the number by for bits*/
|
|
const double conversion_bits[] =
|
|
{
|
|
1.0, /* unit */
|
|
1.0 / 1000, /* kilo */
|
|
1.0 / 1000 / 1000, /* mega */
|
|
1.0 / 1000 / 1000 / 1000, /* giga */
|
|
1.0 / 1000 / 1000 / 1000 / 1000 /* tera */
|
|
};
|
|
|
|
|
|
/* labels for Byte formats [KMGT] */
|
|
const char *label_byte[] =
|
|
{
|
|
"Byte",
|
|
"KByte",
|
|
"MByte",
|
|
"GByte",
|
|
"TByte"
|
|
};
|
|
|
|
/* labels for bit formats [kmgt] */
|
|
const char *label_bit[] =
|
|
{
|
|
"bit",
|
|
"Kbit",
|
|
"Mbit",
|
|
"Gbit",
|
|
"Tbit"
|
|
};
|
|
|
|
/* -------------------------------------------------------------------
|
|
* unit_snprintf
|
|
*
|
|
* Given a number in bytes and a format, converts the number and
|
|
* prints it out with a bits or bytes label.
|
|
* B, K, M, G, A for Byte, Kbyte, Mbyte, Gbyte, adaptive byte
|
|
* b, k, m, g, a for bit, Kbit, Mbit, Gbit, adaptive bit
|
|
* adaptive picks the "best" one based on the number.
|
|
* s should be at least 11 chars long
|
|
* (4 digits + space + 5 chars max + null)
|
|
* ------------------------------------------------------------------- */
|
|
|
|
void unit_snprintf(char *s, int inLen,
|
|
double inNum, char inFormat)
|
|
{
|
|
int conv;
|
|
const char *suffix;
|
|
const char *format;
|
|
|
|
/* convert to bits for [bkmga] */
|
|
if (!isupper((int) inFormat))
|
|
{
|
|
inNum *= 8;
|
|
}
|
|
switch (toupper((u_char)inFormat))
|
|
{
|
|
case 'B':
|
|
conv = UNIT_CONV;
|
|
break;
|
|
case 'K':
|
|
conv = KILO_CONV;
|
|
break;
|
|
case 'M':
|
|
conv = MEGA_CONV;
|
|
break;
|
|
case 'G':
|
|
conv = GIGA_CONV;
|
|
break;
|
|
case 'T':
|
|
conv = TERA_CONV;
|
|
break;
|
|
|
|
default:
|
|
case 'A':
|
|
{
|
|
double tmpNum = inNum;
|
|
conv = UNIT_CONV;
|
|
|
|
if (isupper((int) inFormat))
|
|
{
|
|
while (tmpNum >= 1024.0 && conv < TERA_CONV)
|
|
{
|
|
tmpNum /= 1024.0;
|
|
conv++;
|
|
}
|
|
} else
|
|
{
|
|
while (tmpNum >= 1000.0 && conv < TERA_CONV)
|
|
{
|
|
tmpNum /= 1000.0;
|
|
conv++;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!isupper((int) inFormat))
|
|
{
|
|
inNum *= conversion_bits[conv];
|
|
suffix = label_bit[conv];
|
|
} else
|
|
{
|
|
inNum *= conversion_bytes[conv];
|
|
suffix = label_byte[conv];
|
|
}
|
|
|
|
/* print such that we always fit in 4 places */
|
|
if (inNum < 9.995)
|
|
{ /* 9.995 would be rounded to 10.0 */
|
|
format = "%4.2f %s";/* #.## */
|
|
} else if (inNum < 99.95)
|
|
{ /* 99.95 would be rounded to 100 */
|
|
format = "%4.1f %s";/* ##.# */
|
|
} else if (inNum < 999.5)
|
|
{ /* 999.5 would be rounded to 1000 */
|
|
format = "%4.0f %s";/* ### */
|
|
} else
|
|
{ /* 1000-1024 fits in 4 places If not using
|
|
* Adaptive sizes then this code will not
|
|
* control spaces */
|
|
format = "%4.0f %s";/* #### */
|
|
}
|
|
snprintf(s, inLen, format, inNum, suffix);
|
|
} /* end unit_snprintf */
|
|
|
|
#ifdef __cplusplus
|
|
} /* end extern "C" */
|
|
|
|
#endif
|