4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <sys/param.h>
34 #include <sys/types.h>
38 static char PNAME_FMT
[] = "%s: ";
39 static char ERRNO_FMT
[] = ": %s\n";
40 static char EOL_FMT
[] = "\n";
47 char *p
= strrchr(arg0
, '/');
59 warn(const char *format
, ...)
64 (void) fprintf(stderr
, gettext(PNAME_FMT
), pname
);
65 va_start(alist
, format
);
66 (void) vfprintf(stderr
, format
, alist
);
68 if (strchr(format
, '\n') == NULL
)
70 (void) fprintf(stderr
,
71 gettext(ERRNO_FMT
), strerror(err
));
73 (void) fprintf(stderr
, gettext(EOL_FMT
));
78 static char *__metric_modifiers
[] = { "K", "M", "G", "T", "P", "E", NULL
};
79 static uint64_t __metric_scales
[] = {
82 1000LLU * 1000 * 1000,
83 1000LLU * 1000 * 1000 * 1000,
84 1000LLU * 1000 * 1000 * 1000 * 1000,
85 1000LLU * 1000 * 1000 * 1000 * 1000 * 1000
87 static scale_t __metric_scale
= { __metric_modifiers
, __metric_scales
};
89 static char *__binary_modifiers
[] = {"K", "M", "G", "T", "P", "E", NULL
};
90 static uint64_t __binary_scales
[] = {
93 1024LLU * 1024 * 1024,
94 1024LLU * 1024 * 1024 * 1024,
95 1024LLU * 1024 * 1024 * 1024 * 1024,
96 1024LLU * 1024 * 1024 * 1024 * 1024 * 1024
98 static scale_t __binary_scale
= { __binary_modifiers
, __binary_scales
};
100 scale_t
*scale_metric
= &__metric_scale
;
101 scale_t
*scale_binary
= &__binary_scale
;
104 scaledtouint64(char *scaledin
,
106 int *widthout
, char **modifierout
, char **unitout
,
107 scale_t
*scale
, char *unit
, int flags
) {
112 uint64_t multiplier
= 1;
113 char string
[SCALED_STRLEN
];
117 char **modifiers
= scale
->modifers
;
118 uint64_t *scales
= scale
->scales
;
126 * first check for hex value, which cannot be scaled, as
127 * hex letters cannot be disserned from modifier or unit letters
129 if ((strncmp("0x", scaledin
, 2) == 0) ||
130 (strncmp("0X", scaledin
, 2) == 0)) {
132 /* unit cannot be required on hex values */
133 if ((unit
&& *unit
!= '\0') &&
134 !(flags
& SCALED_UNIT_OPTIONAL_FLAG
))
135 return (SCALED_INVALID_UNIT
);
138 *uint64out
= strtoull(scaledin
, &endptr
, 16);
141 return (SCALED_OVERFLOW
);
143 return (SCALED_INVALID_NUMBER
);
146 return (SCALED_INVALID_NUMBER
);
148 /* compute width of decimal equivalent */
151 string
, SCALED_STRLEN
, "%llu", *uint64out
);
152 *widthout
= strlen(string
);
157 /* scan out numeric value */
159 value
= strtod(scaledin
, &endptr
);
162 return (SCALED_OVERFLOW
);
164 return (SCALED_INVALID_NUMBER
);
167 if (endptr
== scaledin
)
168 return (SCALED_INVALID_NUMBER
);
170 /* no negative values */
171 if (strchr(scaledin
, '-'))
172 return (SCALED_INVALID_NUMBER
);
174 return (SCALED_INVALID_NUMBER
);
177 /* compute width of number string */
179 *widthout
= (int)(endptr
- scaledin
);
181 /* check possible modifier */
182 if (*endptr
!= '\0') {
184 while (modifiers
[index
] != NULL
) {
185 if (flags
& SCALED_MODIFIER_CASE_INSENSITIVE_FLAG
)
186 cmp
= strncasecmp(modifiers
[index
], endptr
,
187 strlen(modifiers
[index
]));
189 cmp
= strncmp(modifiers
[index
], endptr
,
190 strlen(modifiers
[index
]));
194 *modifierout
= modifiers
[index
];
195 endptr
+= strlen(modifiers
[index
]);
196 multiplier
= scales
[index
];
197 result
= value
* multiplier
;
198 if (result
> UINT64_MAX
)
199 return (SCALED_OVERFLOW
);
201 *uint64out
= (uint64_t)result
;
208 /* if there is no modifier, value must be an integer */
211 *uint64out
= strtoull(scaledin
, &endptr
, 0);
214 return (SCALED_OVERFLOW
);
216 return (SCALED_INVALID_NUMBER
);
218 if (endptr
== scaledin
)
219 return (SCALED_INVALID_NUMBER
);
222 /* if unit is present when no unit is allowed, fail */
223 if ((unit
== NULL
|| *unit
== '\0') && (*endptr
!= '\0'))
224 return (SCALED_INVALID_UNIT
);
226 /* check for missing unit when unit is required */
227 if ((unit
&& *unit
!= '\0') &&
228 !(flags
& SCALED_UNIT_OPTIONAL_FLAG
) &&
230 return (SCALED_INVALID_UNIT
);
233 if (unit
&& *unit
!= '\0') {
235 /* allow for missing unit if it is optional */
236 if ((flags
& SCALED_UNIT_OPTIONAL_FLAG
) &&
240 if (flags
& SCALED_UNIT_CASE_INSENSITIVE_FLAG
)
241 cmp
= strncasecmp(unit
, endptr
, strlen(unit
));
243 cmp
= strncmp(unit
, endptr
, strlen(unit
));
246 return (SCALED_INVALID_UNIT
);
248 if (*(endptr
+ strlen(unit
)) != '\0')
249 return (SCALED_INVALID_UNIT
);
259 uint64toscaled(uint64_t uint64in
, int widthin
, char *maxmodifierin
,
260 char *scaledout
, int *widthout
, char **modifierout
,
261 scale_t
*scale
, char *unit
, int flags
) {
267 char string
[SCALED_STRLEN
];
269 char **modifiers
= scale
->modifers
;
270 uint64_t *scales
= scale
->scales
;
272 /* don't scale if there is no reason to */
273 if (uint64in
< scales
[0] || maxmodifierin
== NULL
) {
274 if (flags
& SCALED_PAD_WIDTH_FLAG
)
279 (void) snprintf(string
, SCALED_STRLEN
, "%%%dllu", width
);
281 count
= snprintf(scaledout
, SCALED_STRLEN
, string
, uint64in
);
282 if (unit
&& *unit
!= '\0')
283 (void) strcat(scaledout
, unit
);
294 for (index
= 0; modifiers
[index
+ 1] != NULL
; index
++) {
296 if (uint64in
>= scales
[index
] &&
297 uint64in
< scales
[index
+ 1])
300 if ((strncmp(modifiers
[index
], maxmodifierin
,
301 strlen(modifiers
[index
])) == 0) &&
302 (strlen(modifiers
[index
]) == strlen(maxmodifierin
)))
307 value
= ((double)(uint64in
)) / scales
[index
];
309 *modifierout
= modifiers
[index
];
311 count
= snprintf(string
, SCALED_STRLEN
, "%0.0lf", value
);
312 while (count
< widthin
) {
314 (void) snprintf(string
, SCALED_STRLEN
, "%%0.%dlf", decimals
);
316 count
= snprintf(scaledout
, SCALED_STRLEN
, string
, value
);
318 /* reduce decimal places if we've overshot the desired width */
319 if (count
> widthin
) {
325 if (flags
& SCALED_PAD_WIDTH_FLAG
)
330 (void) snprintf(string
, SCALED_STRLEN
, "%%%d.%dlf", width
, decimals
);
332 count
= snprintf(scaledout
, SCALED_STRLEN
, string
, value
);
334 (void) strcat(scaledout
, modifiers
[index
]);
336 if (unit
&& *unit
!= '\0')
337 (void) strcat(scaledout
, unit
);
346 scaledtoscaled(char *scaledin
, int widthin
, char *maxmodifierin
,
347 char *scaledout
, int *widthout
, char **modifierout
,
348 scale_t
*scale
, char *unit
, int flags
) {
353 ret
= scaledtouint64(scaledin
, &val
, NULL
, NULL
, NULL
,
358 ret
= uint64toscaled(val
, widthin
, maxmodifierin
,
359 scaledout
, widthout
, modifierout
,
366 scaledeqscaled(char *scaled1
, char *scaled2
,
367 scale_t
*scale
, char *unit
, int flags
) {
373 char *modifier
= NULL
;
378 char scaledA
[SCALED_STRLEN
];
379 char scaledB
[SCALED_STRLEN
];
380 char **modifiers
= scale
->modifers
;
383 * remove padding flag, so strings to compare will not have
386 flags
= flags
& (~SCALED_PAD_WIDTH_FLAG
);
388 /* determine each number's width and modifier */
389 ret
= scaledtouint64(scaled1
, &uint64
, &width1
, &modifier1
, NULL
,
394 ret
= scaledtouint64(scaled2
, &uint64
, &width2
, &modifier2
, NULL
,
400 * determine the width and modifier to use for comparison.
401 * Use widest width and smallest modifier.
402 * Rescale to new width and modifier
405 if (modifier1
== NULL
|| modifier2
== NULL
)
408 for (i
= 0; modifiers
[i
] != NULL
; i
++) {
410 if (strcmp(modifier1
, modifiers
[i
]) == 0) {
411 modifier
= modifiers
[i
];
414 if (strcmp(modifier2
, modifiers
[i
]) == 0) {
415 modifier
= modifiers
[i
];
427 * Convert first number to width and modifier.
428 * This is done for the following reasons:
429 * 1. In case first number is hecadecimal. This will convert
431 * 2. In case the first number has < the minimum number of
433 * 3. The first number is missing an optional unit string.
434 * 4. Fix casing of modifier and unit.
437 ret
= scaledtoscaled(scaled1
, width
, modifier
,
438 scaledA
, NULL
, NULL
, scale
, unit
, flags
);
442 /* convert second number to width and modifier matching first number */
443 ret
= scaledtoscaled(scaled2
, width
, modifier
,
444 scaledB
, NULL
, NULL
, scale
, unit
, flags
);
448 /* numbers are equal if strings match */
449 return ((strncmp(scaledA
, scaledB
, strlen(scaledA
)) == 0) &&
450 (strlen(scaledA
) == strlen(scaledB
)));
455 scaledequint64(char *scaled
, uint64_t uint64
, int minwidth
,
456 scale_t
*scale
, char *unit
, int flags
) {
463 char scaledA
[SCALED_STRLEN
];
464 char scaledB
[SCALED_STRLEN
];
466 /* determine for number's width and modifier */
467 ret
= scaledtouint64(scaled
, &tmpuint64
, &width
, &modifier
, NULL
,
472 if (width
< minwidth
)
476 * Convert first number to width and modifier.
477 * This is done for the following reasons:
478 * 1. In case first number is hecadecimal. This will convert
480 * 2. In case the first number has < the minimum number of
482 * 3. The first number is missing an optional unit string.
483 * 4. Fix casing of modifier and unit.
486 ret
= scaledtoscaled(scaled
, width
, modifier
,
487 scaledA
, NULL
, NULL
, scale
, unit
, flags
);
491 /* convert second number to width and modifier matching first number */
492 ret
= uint64toscaled(uint64
, width
, modifier
,
493 scaledB
, NULL
, NULL
, scale
, unit
, flags
);
497 /* numbers are equal if strings match */
498 return ((strncmp(scaledA
, scaledB
, strlen(scaledA
)) == 0) &&
499 (strlen(scaledA
) == strlen(scaledB
)));