"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 }