"Fossies" - the Fresh Open Source Software Archive 
Member "xombrero-1.6.4/freebsd/freebsd.c" (17 Feb 2015, 6576 Bytes) of package /linux/www/old/xombrero-1.6.4.tgz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "freebsd.c" see the
Fossies "Dox" file reference documentation.
1 /* $OpenBSD: fmt_scaled.c,v 1.10 2009/06/20 15:00:04 martynas Exp $ */
2
3 /*
4 * Copyright (c) 2001, 2002, 2003 Ian F. Darwin. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /*
30 * fmt_scaled: Format numbers scaled for human comprehension
31 * scan_scaled: Scan numbers in this format.
32 *
33 * "Human-readable" output uses 4 digits max, and puts a unit suffix at
34 * the end. Makes output compact and easy-to-read esp. on huge disks.
35 * Formatting code was originally in OpenBSD "df", converted to library routine.
36 * Scanning code written for OpenBSD libutil.
37 */
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <errno.h>
42 #include <string.h>
43 #include <ctype.h>
44 #include <limits.h>
45
46 #include "util.h"
47
48 typedef enum {
49 NONE = 0, KILO = 1, MEGA = 2, GIGA = 3, TERA = 4, PETA = 5, EXA = 6
50 } unit_type;
51
52 /* These three arrays MUST be in sync! XXX make a struct */
53 static unit_type units[] = { NONE, KILO, MEGA, GIGA, TERA, PETA, EXA };
54 static char scale_chars[] = "BKMGTPE";
55 static long long scale_factors[] = {
56 1LL,
57 1024LL,
58 1024LL*1024,
59 1024LL*1024*1024,
60 1024LL*1024*1024*1024,
61 1024LL*1024*1024*1024*1024,
62 1024LL*1024*1024*1024*1024*1024,
63 };
64 #define SCALE_LENGTH (sizeof(units)/sizeof(units[0]))
65
66 #define MAX_DIGITS (SCALE_LENGTH * 3) /* XXX strlen(sprintf("%lld", -1)? */
67
68 /* Convert the given input string "scaled" into numeric in "result".
69 * Return 0 on success, -1 and errno set on error.
70 */
71 int
72 scan_scaled(char *scaled, long long *result)
73 {
74 char *p = scaled;
75 int sign = 0;
76 unsigned int i, ndigits = 0, fract_digits = 0;
77 long long scale_fact = 1, whole = 0, fpart = 0;
78
79 /* Skip leading whitespace */
80 while (isascii(*p) && isspace(*p))
81 ++p;
82
83 /* Then at most one leading + or - */
84 while (*p == '-' || *p == '+') {
85 if (*p == '-') {
86 if (sign) {
87 errno = EINVAL;
88 return -1;
89 }
90 sign = -1;
91 ++p;
92 } else if (*p == '+') {
93 if (sign) {
94 errno = EINVAL;
95 return -1;
96 }
97 sign = +1;
98 ++p;
99 }
100 }
101
102 /* Main loop: Scan digits, find decimal point, if present.
103 * We don't allow exponentials, so no scientific notation
104 * (but note that E for Exa might look like e to some!).
105 * Advance 'p' to end, to get scale factor.
106 */
107 for (; isascii(*p) && (isdigit(*p) || *p=='.'); ++p) {
108 if (*p == '.') {
109 if (fract_digits > 0) { /* oops, more than one '.' */
110 errno = EINVAL;
111 return -1;
112 }
113 fract_digits = 1;
114 continue;
115 }
116
117 i = (*p) - '0'; /* whew! finally a digit we can use */
118 if (fract_digits > 0) {
119 if (fract_digits >= MAX_DIGITS-1)
120 /* ignore extra fractional digits */
121 continue;
122 fract_digits++; /* for later scaling */
123 fpart *= 10;
124 fpart += i;
125 } else { /* normal digit */
126 if (++ndigits >= MAX_DIGITS) {
127 errno = ERANGE;
128 return -1;
129 }
130 whole *= 10;
131 whole += i;
132 }
133 }
134
135 if (sign) {
136 whole *= sign;
137 fpart *= sign;
138 }
139
140 /* If no scale factor given, we're done. fraction is discarded. */
141 if (!*p) {
142 *result = whole;
143 return 0;
144 }
145
146 /* Validate scale factor, and scale whole and fraction by it. */
147 for (i = 0; i < SCALE_LENGTH; i++) {
148
149 /* Are we there yet? */
150 if (*p == scale_chars[i] ||
151 *p == tolower(scale_chars[i])) {
152
153 /* If it ends with alphanumerics after the scale char, bad. */
154 if (isalnum(*(p+1))) {
155 errno = EINVAL;
156 return -1;
157 }
158 scale_fact = scale_factors[i];
159
160 /* scale whole part */
161 whole *= scale_fact;
162
163 /* truncate fpart so it does't overflow.
164 * then scale fractional part.
165 */
166 while (fpart >= LLONG_MAX / scale_fact) {
167 fpart /= 10;
168 fract_digits--;
169 }
170 fpart *= scale_fact;
171 if (fract_digits > 0) {
172 for (i = 0; i < fract_digits -1; i++)
173 fpart /= 10;
174 }
175 whole += fpart;
176 *result = whole;
177 return 0;
178 }
179 }
180 errno = ERANGE;
181 return -1;
182 }
183
184 /* Format the given "number" into human-readable form in "result".
185 * Result must point to an allocated buffer of length FMT_SCALED_STRSIZE.
186 * Return 0 on success, -1 and errno set if error.
187 */
188 int
189 fmt_scaled(long long number, char *result)
190 {
191 long long abval, fract = 0;
192 unsigned int i;
193 unit_type unit = NONE;
194
195 abval = llabs(number);
196
197 /* Not every negative long long has a positive representation.
198 * Also check for numbers that are just too darned big to format
199 */
200 if (abval < 0 || abval / 1024 >= scale_factors[SCALE_LENGTH-1]) {
201 errno = ERANGE;
202 return -1;
203 }
204
205 /* scale whole part; get unscaled fraction */
206 for (i = 0; i < SCALE_LENGTH; i++) {
207 if (abval/1024 < scale_factors[i]) {
208 unit = units[i];
209 fract = (i == 0) ? 0 : abval % scale_factors[i];
210 number /= scale_factors[i];
211 if (i > 0)
212 fract /= scale_factors[i - 1];
213 break;
214 }
215 }
216
217 fract = (10 * fract + 512) / 1024;
218 /* if the result would be >= 10, round main number */
219 if (fract == 10) {
220 if (number >= 0)
221 number++;
222 else
223 number--;
224 fract = 0;
225 }
226
227 if (number == 0)
228 strlcpy(result, "0B", FMT_SCALED_STRSIZE);
229 else if (unit == NONE || number >= 100 || number <= -100) {
230 if (fract >= 5) {
231 if (number >= 0)
232 number++;
233 else
234 number--;
235 }
236 (void)snprintf(result, FMT_SCALED_STRSIZE, "%lld%c",
237 number, scale_chars[unit]);
238 } else
239 (void)snprintf(result, FMT_SCALED_STRSIZE, "%lld.%1lld%c",
240 number, fract, scale_chars[unit]);
241
242 return 0;
243 }