1 /*--------------------------------------------------------------- 2 * Copyright (c) 1999,2000,2001,2002,2003 3 * The Board of Trustees of the University of Illinois 4 * All Rights Reserved. 5 *--------------------------------------------------------------- 6 * Permission is hereby granted, free of charge, to any person 7 * obtaining a copy of this software (Iperf) and associated 8 * documentation files (the "Software"), to deal in the Software 9 * without restriction, including without limitation the 10 * rights to use, copy, modify, merge, publish, distribute, 11 * sublicense, and/or sell copies of the Software, and to permit 12 * persons to whom the Software is furnished to do 13 * so, subject to the following conditions: 14 * 15 * 16 * Redistributions of source code must retain the above 17 * copyright notice, this list of conditions and 18 * the following disclaimers. 19 * 20 * 21 * Redistributions in binary form must reproduce the above 22 * copyright notice, this list of conditions and the following 23 * disclaimers in the documentation and/or other materials 24 * provided with the distribution. 25 * 26 * 27 * Neither the names of the University of Illinois, NCSA, 28 * nor the names of its contributors may be used to endorse 29 * or promote products derived from this Software without 30 * specific prior written permission. 31 * 32 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 33 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 34 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 35 * NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT 36 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 37 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 38 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE 39 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 40 * ________________________________________________________________ 41 * National Laboratory for Applied Network Research 42 * National Center for Supercomputing Applications 43 * University of Illinois at Urbana-Champaign 44 * http://www.ncsa.uiuc.edu 45 * ________________________________________________________________ 46 * 47 * stdio.c 48 * by Mark Gates <mgates@nlanr.net> 49 * and Ajay Tirumalla <tirumala@ncsa.uiuc.edu> 50 * ------------------------------------------------------------------- 51 * input and output numbers, converting with kilo, mega, giga, tera 52 * ------------------------------------------------------------------- */ 53 54 #include <stdio.h> 55 #include <assert.h> 56 #include <ctype.h> 57 #ifdef HAVE_STDINT_H 58 #include <stdint.h> 59 #endif 60 #include <sys/socket.h> 61 #include <sys/types.h> 62 #include <sys/time.h> 63 64 65 #include "iperf.h" 66 67 #ifdef __cplusplus 68 extern "C" 69 { 70 #endif 71 72 const double KILO_UNIT = 1024.0; 73 const double MEGA_UNIT = 1024.0 * 1024.0; 74 const double GIGA_UNIT = 1024.0 * 1024.0 * 1024.0; 75 const double TERA_UNIT = 1024.0 * 1024.0 * 1024.0 * 1024.0; 76 77 const double KILO_RATE_UNIT = 1000.0; 78 const double MEGA_RATE_UNIT = 1000.0 * 1000.0; 79 const double GIGA_RATE_UNIT = 1000.0 * 1000.0 * 1000.0; 80 const double TERA_RATE_UNIT = 1000.0 * 1000.0 * 1000.0 * 1000.0; 81 82 /* ------------------------------------------------------------------- 83 * unit_atof 84 * 85 * Given a string of form #x where # is a number and x is a format 86 * character listed below, this returns the interpreted integer. 87 * Gg, Mm, Kk are giga, mega, kilo respectively 88 * ------------------------------------------------------------------- */ 89 unit_atof(const char * s)90 double unit_atof(const char *s) 91 { 92 double n; 93 char suffix = '\0'; 94 95 assert(s != NULL); 96 97 /* scan the number and any suffices */ 98 sscanf(s, "%lf%c", &n, &suffix); 99 100 /* convert according to [Tt Gg Mm Kk] */ 101 switch (suffix) 102 { 103 case 't': case 'T': 104 n *= TERA_UNIT; 105 break; 106 case 'g': case 'G': 107 n *= GIGA_UNIT; 108 break; 109 case 'm': case 'M': 110 n *= MEGA_UNIT; 111 break; 112 case 'k': case 'K': 113 n *= KILO_UNIT; 114 break; 115 default: 116 break; 117 } 118 return n; 119 } /* end unit_atof */ 120 121 122 /* ------------------------------------------------------------------- 123 * unit_atof_rate 124 * 125 * Similar to unit_atof, but uses 10-based rather than 2-based 126 * suffixes. 127 * ------------------------------------------------------------------- */ 128 unit_atof_rate(const char * s)129 double unit_atof_rate(const char *s) 130 { 131 double n; 132 char suffix = '\0'; 133 134 assert(s != NULL); 135 136 /* scan the number and any suffices */ 137 sscanf(s, "%lf%c", &n, &suffix); 138 139 /* convert according to [Tt Gg Mm Kk] */ 140 switch (suffix) 141 { 142 case 't': case 'T': 143 n *= TERA_RATE_UNIT; 144 break; 145 case 'g': case 'G': 146 n *= GIGA_RATE_UNIT; 147 break; 148 case 'm': case 'M': 149 n *= MEGA_RATE_UNIT; 150 break; 151 case 'k': case 'K': 152 n *= KILO_RATE_UNIT; 153 break; 154 default: 155 break; 156 } 157 return n; 158 } /* end unit_atof_rate */ 159 160 161 162 /* ------------------------------------------------------------------- 163 * unit_atoi 164 * 165 * Given a string of form #x where # is a number and x is a format 166 * character listed below, this returns the interpreted integer. 167 * Tt, Gg, Mm, Kk are tera, giga, mega, kilo respectively 168 * ------------------------------------------------------------------- */ 169 unit_atoi(const char * s)170 iperf_size_t unit_atoi(const char *s) 171 { 172 double n; 173 char suffix = '\0'; 174 175 assert(s != NULL); 176 177 /* scan the number and any suffices */ 178 sscanf(s, "%lf%c", &n, &suffix); 179 180 /* convert according to [Tt Gg Mm Kk] */ 181 switch (suffix) 182 { 183 case 't': case 'T': 184 n *= TERA_UNIT; 185 break; 186 case 'g': case 'G': 187 n *= GIGA_UNIT; 188 break; 189 case 'm': case 'M': 190 n *= MEGA_UNIT; 191 break; 192 case 'k': case 'K': 193 n *= KILO_UNIT; 194 break; 195 default: 196 break; 197 } 198 return (iperf_size_t) n; 199 } /* end unit_atof */ 200 201 /* ------------------------------------------------------------------- 202 * constants for byte_printf 203 * ------------------------------------------------------------------- */ 204 205 /* used as indices into conversion_bytes[], label_byte[], and label_bit[] */ 206 enum 207 { 208 UNIT_CONV, 209 KILO_CONV, 210 MEGA_CONV, 211 GIGA_CONV, 212 TERA_CONV 213 }; 214 215 /* factor to multiply the number by */ 216 const double conversion_bytes[] = 217 { 218 1.0, /* unit */ 219 1.0 / 1024, /* kilo */ 220 1.0 / 1024 / 1024, /* mega */ 221 1.0 / 1024 / 1024 / 1024, /* giga */ 222 1.0 / 1024 / 1024 / 1024 / 1024 /* tera */ 223 }; 224 225 /* factor to multiply the number by for bits*/ 226 const double conversion_bits[] = 227 { 228 1.0, /* unit */ 229 1.0 / 1000, /* kilo */ 230 1.0 / 1000 / 1000, /* mega */ 231 1.0 / 1000 / 1000 / 1000, /* giga */ 232 1.0 / 1000 / 1000 / 1000 / 1000 /* tera */ 233 }; 234 235 236 /* labels for Byte formats [KMGT] */ 237 const char *label_byte[] = 238 { 239 "Byte", 240 "KByte", 241 "MByte", 242 "GByte", 243 "TByte" 244 }; 245 246 /* labels for bit formats [kmgt] */ 247 const char *label_bit[] = 248 { 249 "bit", 250 "Kbit", 251 "Mbit", 252 "Gbit", 253 "Tbit" 254 }; 255 256 /* ------------------------------------------------------------------- 257 * unit_snprintf 258 * 259 * Given a number in bytes and a format, converts the number and 260 * prints it out with a bits or bytes label. 261 * B, K, M, G, A for Byte, Kbyte, Mbyte, Gbyte, adaptive byte 262 * b, k, m, g, a for bit, Kbit, Mbit, Gbit, adaptive bit 263 * adaptive picks the "best" one based on the number. 264 * s should be at least 11 chars long 265 * (4 digits + space + 5 chars max + null) 266 * ------------------------------------------------------------------- */ 267 unit_snprintf(char * s,int inLen,double inNum,char inFormat)268 void unit_snprintf(char *s, int inLen, 269 double inNum, char inFormat) 270 { 271 int conv; 272 const char *suffix; 273 const char *format; 274 275 /* convert to bits for [bkmga] */ 276 if (!isupper((int) inFormat)) 277 { 278 inNum *= 8; 279 } 280 switch (toupper((u_char)inFormat)) 281 { 282 case 'B': 283 conv = UNIT_CONV; 284 break; 285 case 'K': 286 conv = KILO_CONV; 287 break; 288 case 'M': 289 conv = MEGA_CONV; 290 break; 291 case 'G': 292 conv = GIGA_CONV; 293 break; 294 case 'T': 295 conv = TERA_CONV; 296 break; 297 298 default: 299 case 'A': 300 { 301 double tmpNum = inNum; 302 conv = UNIT_CONV; 303 304 if (isupper((int) inFormat)) 305 { 306 while (tmpNum >= 1024.0 && conv < TERA_CONV) 307 { 308 tmpNum /= 1024.0; 309 conv++; 310 } 311 } else 312 { 313 while (tmpNum >= 1000.0 && conv < TERA_CONV) 314 { 315 tmpNum /= 1000.0; 316 conv++; 317 } 318 } 319 break; 320 } 321 } 322 323 if (!isupper((int) inFormat)) 324 { 325 inNum *= conversion_bits[conv]; 326 suffix = label_bit[conv]; 327 } else 328 { 329 inNum *= conversion_bytes[conv]; 330 suffix = label_byte[conv]; 331 } 332 333 /* print such that we always fit in 4 places */ 334 if (inNum < 9.995) 335 { /* 9.995 would be rounded to 10.0 */ 336 format = "%4.2f %s";/* #.## */ 337 } else if (inNum < 99.95) 338 { /* 99.95 would be rounded to 100 */ 339 format = "%4.1f %s";/* ##.# */ 340 } else if (inNum < 999.5) 341 { /* 999.5 would be rounded to 1000 */ 342 format = "%4.0f %s";/* ### */ 343 } else 344 { /* 1000-1024 fits in 4 places If not using 345 * Adaptive sizes then this code will not 346 * control spaces */ 347 format = "%4.0f %s";/* #### */ 348 } 349 snprintf(s, inLen, format, inNum, suffix); 350 } /* end unit_snprintf */ 351 352 #ifdef __cplusplus 353 } /* end extern "C" */ 354 355 #endif 356