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