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