Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

Units.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 
00003 // This file is part of Vesta.
00004 
00005 // Vesta is free software; you can redistribute it and/or modify it
00006 // under the terms of the GNU Lesser General Public License as
00007 // published by the Free Software Foundation; either version 2.1 of
00008 // the License, or (at your option) any later version.
00009 
00010 // Vesta is distributed in the hope that it will be useful, but
00011 // WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00018 // USA
00019 
00020 #include <ctype.h>
00021 #include "Units.H"
00022 
00023 // Base 10 international system of units prefixes.  See:
00024 
00025 // http://en.wikipedia.org/wiki/SI_prefix
00026 
00027 #define DEC_ONE_K CONST_UINT_64(1000)
00028 #define DEC_ONE_M CONST_UINT_64(1000000)
00029 #define DEC_ONE_G CONST_UINT_64(1000000000)
00030 #define DEC_ONE_T CONST_UINT_64(1000000000000)
00031 #define DEC_ONE_P CONST_UINT_64(1000000000000000)
00032 #define DEC_ONE_E CONST_UINT_64(1000000000000000000)
00033 
00034 // Binary brefixes for different magnitudes.  See:
00035 
00036 // http://en.wikipedia.org/wiki/Binary_prefix
00037 
00038 #define BIN_ONE_K (CONST_UINT_64(1)<<10)
00039 #define BIN_ONE_M (CONST_UINT_64(1)<<20)
00040 #define BIN_ONE_G (CONST_UINT_64(1)<<30)
00041 #define BIN_ONE_T (CONST_UINT_64(1)<<40)
00042 #define BIN_ONE_P (CONST_UINT_64(1)<<50)
00043 #define BIN_ONE_E (CONST_UINT_64(1)<<60)
00044 
00045 Text Basics::FormatUnitVal(Basics::uint64 val, bool decimal) throw ()
00046 {
00047   const Basics::uint64 OneK = decimal ? DEC_ONE_K : BIN_ONE_K;
00048   const Basics::uint64 OneM = decimal ? DEC_ONE_M : BIN_ONE_M;
00049   const Basics::uint64 OneG = decimal ? DEC_ONE_G : BIN_ONE_G;
00050   const Basics::uint64 OneT = decimal ? DEC_ONE_T : BIN_ONE_T;
00051   const Basics::uint64 OneP = decimal ? DEC_ONE_P : BIN_ONE_P;
00052   const Basics::uint64 OneE = decimal ? DEC_ONE_E : BIN_ONE_E;
00053 
00054     char buff[20];
00055     if (val < OneK) {
00056         sprintf(buff, "%"FORMAT_LENGTH_INT_64"u", val);
00057     } else {
00058       // Lower case k for decimal, as K means Kelin in SI.
00059       char suffix = decimal ? 'k' : 'K';
00060       if (val >= OneE)
00061         {
00062           val /= OneP;
00063           suffix = 'E';
00064         }
00065       else if (val >= OneP)
00066         {
00067           val /= OneT;
00068           suffix = 'P';
00069         }
00070       else if (val >= OneT)
00071         {
00072           val /= OneG;
00073           suffix = 'T';
00074         }
00075       else if (val >= OneG)
00076         {
00077           val /= OneM;
00078           suffix = 'G';
00079         }
00080       else if (val >= OneM)
00081         {
00082           val /= OneK;
00083           suffix = 'M';
00084         }
00085 
00086       float ratio = ((float)val) / ((float)OneK);
00087       if (ratio < 9.95) { // assures won't round up to 10.0
00088         sprintf(buff, "%.1f%c", ratio, suffix);
00089       } else {
00090         val = (val + (OneK / 2)) / OneK; // round
00091         sprintf(buff, "%"FORMAT_LENGTH_INT_64"u%c", val, suffix);
00092       }
00093     }
00094     return Text(buff);
00095 }
00096 
00097 Basics::uint64 Basics::ParseUnitVal(const char *val, bool decimal)
00098   throw (Basics::ParseUnitValFailure)
00099 {
00100   const Basics::uint64 OneK = decimal ? DEC_ONE_K : BIN_ONE_K;
00101   const Basics::uint64 OneM = decimal ? DEC_ONE_M : BIN_ONE_M;
00102   const Basics::uint64 OneG = decimal ? DEC_ONE_G : BIN_ONE_G;
00103   const Basics::uint64 OneT = decimal ? DEC_ONE_T : BIN_ONE_T;
00104   const Basics::uint64 OneP = decimal ? DEC_ONE_P : BIN_ONE_P;
00105   const Basics::uint64 OneE = decimal ? DEC_ONE_E : BIN_ONE_E;
00106 
00107   // If the value doesn't start with a digit, that's an error.
00108   if(!isdigit(*val))
00109     {
00110       ParseUnitValFailure err;
00111       err.val = val;
00112       err.emsg = (Text("Value '") + val + "' doesn't start with a number");
00113       throw err;
00114     }
00115 
00116   char *end;
00117 
00118   unsigned long long result = strtoul(val, &end, 0);
00119   switch(*end)
00120     {
00121     case 'k':
00122     case 'K':
00123       result *= OneK;
00124       break;
00125     case 'm':
00126     case 'M':
00127       result *= OneM;
00128       break;
00129     case 'g':
00130     case 'G':
00131       result *= OneG;
00132       break;
00133     case 't':
00134     case 'T':
00135       result *= OneT;
00136       break;
00137     case 'p':
00138     case 'P':
00139       result *= OneP;
00140       break;
00141     case 'e':
00142     case 'E':
00143       result *= OneE;
00144       break;
00145     default:
00146       // If there's some other character after the number, that's an
00147       // error.
00148       {
00149         ParseUnitValFailure err;
00150         err.val = val;
00151         err.emsg = ("Unknown unit multiplier '" + Text(*end) +
00152                     "' in value '" + val + "'");
00153         throw err;
00154       }
00155     }
00156   end++;
00157   // If there's something after the unit multiplier, that's an error.
00158   if(*end != 0)
00159     {
00160       ParseUnitValFailure err;
00161       err.val = val;
00162       err.emsg = ("Extra characters '" + Text(end) +
00163                   "' after unit multiplier in value '" + val + "'");
00164       throw err;
00165     }
00166   return result;
00167 }

Generated on Mon May 8 00:48:29 2006 for Vesta by  doxygen 1.4.2