xref: /iperf/src/units.c (revision 8d41fbd7)
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 <[email protected]>
49  * and Ajay Tirumalla <[email protected]>
50  * -------------------------------------------------------------------
51  * input and output numbers, converting with kilo, mega, giga
52  * ------------------------------------------------------------------- */
53 
54 #include <stdio.h>
55 #include <assert.h>
56 #include <ctype.h>
57 #include <stdint.h>
58 #include <sys/socket.h>
59 #include <sys/time.h>
60 #include <netinet/tcp.h>
61 
62 
63 #include "iperf.h"
64 
65 #ifdef __cplusplus
66 extern    "C"
67 {
68 #endif
69 
70     const long KILO_UNIT = 1024;
71     const long MEGA_UNIT = 1024 * 1024;
72     const long GIGA_UNIT = 1024 * 1024 * 1024;
73 
74     const long KILO_UNIT_SI = 1000;
75     const long MEGA_UNIT_SI = 1000 * 1000;
76     const long GIGA_UNIT_SI = 1000 * 1000 * 1000;
77 
78 /* -------------------------------------------------------------------
79  * unit_atof
80  *
81  * Given a string of form #x where # is a number and x is a format
82  * character listed below, this returns the interpreted integer.
83  * Gg, Mm, Kk are giga, mega, kilo respectively
84  * ------------------------------------------------------------------- */
85 
86     double    unit_atof(const char *s)
87     {
88 	double    n;
89 	char      suffix = '\0';
90 
91 	          assert(s != NULL);
92 
93 	/* scan the number and any suffices */
94 	          sscanf(s, "%lf%c", &n, &suffix);
95 
96 	/* convert according to [Gg Mm Kk] */
97 	switch    (suffix)
98 	{
99 	case 'G':
100 	    n *= GIGA_UNIT;
101 	    break;
102 	case 'M':
103 	    n *= MEGA_UNIT;
104 	    break;
105 	case 'K':
106 	    n *= KILO_UNIT;
107 	    break;
108 	case 'g':
109 	    n *= GIGA_UNIT_SI;
110 	    break;
111 	case 'm':
112 	    n *= MEGA_UNIT_SI;
113 	    break;
114 	case 'k':
115 	    n *= KILO_UNIT_SI;
116 	    break;
117 	default:
118 	    break;
119 	}
120 	          return n;
121     }				/* end unit_atof */
122 
123 /* -------------------------------------------------------------------
124  * unit_atoi
125  *
126  * Given a string of form #x where # is a number and x is a format
127  * character listed below, this returns the interpreted integer.
128  * Gg, Mm, Kk are giga, mega, kilo respectively
129  * ------------------------------------------------------------------- */
130 
131     iperf_size_t unit_atoi(const char *s)
132     {
133 	double    n;
134 	char      suffix = '\0';
135 
136 	          assert(s != NULL);
137 
138 	/* scan the number and any suffices */
139 	          sscanf(s, "%lf%c", &n, &suffix);
140 
141 	/* convert according to [Gg Mm Kk] */
142 	switch    (suffix)
143 	{
144 	case 'G':
145 	    n *= GIGA_UNIT;
146 	    break;
147 	case 'M':
148 	    n *= MEGA_UNIT;
149 	    break;
150 	case 'K':
151 	    n *= KILO_UNIT;
152 	    break;
153 	case 'g':
154 	    n *= GIGA_UNIT_SI;
155 	    break;
156 	case 'm':
157 	    n *= MEGA_UNIT_SI;
158 	    break;
159 	case 'k':
160 	    n *= KILO_UNIT_SI;
161 	    break;
162 	default:
163 	    break;
164 	}
165 	          return (iperf_size_t) n;
166     }				/* end unit_atof */
167 
168 /* -------------------------------------------------------------------
169  * constants for byte_printf
170  * ------------------------------------------------------------------- */
171 
172 /* used as indices into conversion_bytes[], label_byte[], and label_bit[] */
173     enum
174     {
175 	UNIT_CONV,
176 	KILO_CONV,
177 	MEGA_CONV,
178 	GIGA_CONV
179     };
180 
181 /* factor to multiply the number by */
182     const double conversion_bytes[] =
183     {
184 	1.0,			/* unit */
185 	1.0 / 1024,		/* kilo */
186 	1.0 / 1024 / 1024,	/* mega */
187 	1.0 / 1024 / 1024 / 1024/* giga */
188     };
189 
190 /* factor to multiply the number by for bits*/
191     const double conversion_bits[] =
192     {
193 	1.0,			/* unit */
194 	1.0 / 1000,		/* kilo */
195 	1.0 / 1000 / 1000,	/* mega */
196 	1.0 / 1000 / 1000 / 1000/* giga */
197     };
198 
199 
200 /* labels for Byte formats [KMG] */
201     const char *label_byte[] =
202     {
203 	"Byte",
204 	"KByte",
205 	"MByte",
206 	"GByte"
207     };
208 
209 /* labels for bit formats [kmg] */
210     const char *label_bit[] =
211     {
212 	"bit",
213 	"Kbit",
214 	"Mbit",
215 	"Gbit"
216     };
217 
218 /* -------------------------------------------------------------------
219  * unit_snprintf
220  *
221  * Given a number in bytes and a format, converts the number and
222  * prints it out with a bits or bytes label.
223  *   B, K, M, G, A for Byte, Kbyte, Mbyte, Gbyte, adaptive byte
224  *   b, k, m, g, a for bit,  Kbit,  Mbit,  Gbit,  adaptive bit
225  * adaptive picks the "best" one based on the number.
226  * s should be at least 11 chars long
227  * (4 digits + space + 5 chars max + null)
228  * ------------------------------------------------------------------- */
229 
230     void      unit_snprintf(char *s, int inLen,
231 			              double inNum, char inFormat)
232     {
233 	int       conv;
234 	const char *suffix;
235 	const char *format;
236 
237 	/* convert to bits for [bkmga] */
238 	if        (!isupper((int) inFormat))
239 	{
240 	    inNum *= 8;
241 	}
242 	switch    (toupper(inFormat))
243 	{
244 	case 'B':
245 	    conv = UNIT_CONV;
246 	    break;
247 	case 'K':
248 	    conv = KILO_CONV;
249 	    break;
250 	case 'M':
251 	    conv = MEGA_CONV;
252 	    break;
253 	case 'G':
254 	    conv = GIGA_CONV;
255 	    break;
256 
257 	default:
258 	case 'A':
259 	    {
260 		double    tmpNum = inNum;
261 		conv = UNIT_CONV;
262 
263 		if (isupper((int) inFormat))
264 		{
265 		    while (tmpNum >= 1024.0 && conv <= GIGA_CONV)
266 		    {
267 			tmpNum /= 1024.0;
268 			conv++;
269 		    }
270 		} else
271 		{
272 		    while (tmpNum >= 1000.0 && conv <= GIGA_CONV)
273 		    {
274 			tmpNum /= 1000.0;
275 			conv++;
276 		    }
277 		}
278 		break;
279 	    }
280 	}
281 
282 	if (!isupper((int) inFormat))
283 	{
284 	    inNum *= conversion_bits[conv];
285 	    suffix = label_bit[conv];
286 	} else
287 	{
288 	    inNum *= conversion_bytes[conv];
289 	    suffix = label_byte[conv];
290 	}
291 
292 	/* print such that we always fit in 4 places */
293 	if (inNum < 9.995)
294 	{			/* 9.995 would be rounded to 10.0 */
295 	    format = "%4.2f %s";/* #.## */
296 	} else if (inNum < 99.95)
297 	{			/* 99.95 would be rounded to 100 */
298 	    format = "%4.1f %s";/* ##.# */
299 	} else if (inNum < 999.5)
300 	{			/* 999.5 would be rounded to 1000 */
301 	    format = "%4.0f %s";/* ### */
302 	} else
303 	{			/* 1000-1024 fits in 4 places If not using
304 				 * Adaptive sizes then this code will not
305 				 * control spaces */
306 	    format = "%4.0f %s";/* #### */
307 	}
308 	snprintf(s, inLen, format, inNum, suffix);
309     }				/* end unit_snprintf */
310 
311 #ifdef __cplusplus
312 }				/* end extern "C" */
313 
314 #endif
315