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