[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    koffice/kspread
From:       Brad Hards <bradh () frogmouth ! net>
Date:       2007-01-14 5:09:08
Message-ID: 1168751348.948048.13152.nullmailer () svn ! kde ! org
[Download RAW message or body]

SVN commit 623121 by bhards:

More work on OpenFormula function compliance.

This change updates the following functions:
BIN2OCT, BIN2HEX, DEC2HEX, DEC2BIN, DEC2OCT,
HEX2BIN, HEX2OCT, OCT2BIN, OCT2DEC, OCT2HEX.
The changes are mostly to support an optional
extra argument which specifies a minimum length
of the output string. We also now throw an error
if there is an illegal character in the input
(e.g. binary input, but something other than a
0 or 1) - previously we just returned zero.

We still don't handle negative numbers correctly for
these functions.

This change also modifies the behaviour of BASE
in a subtle and possibly dangerous way - the optional
third argument is no longer precision (i.e. number
of characters after the decimal point), it is now
minimum length (i.e. total number of characters). This 
is the way it is supposed to work according to the 
OpenFormula spec (section 6.17.3).

It also adds a new function - DECIMAL, which
basically turns a text string in any base into
a number in base 10 (roughly the reverse of the
BASE function). This works in accordance with
the OpenFormula spec.



 M  +3 -1      ValueCalc.cpp  
 M  +1 -1      ValueCalc.h  
 M  +158 -13   functions/engineering.cpp  
 M  +32 -5     functions/engineering.xml  


--- trunk/koffice/kspread/ValueCalc.cpp #623120:623121
@@ -784,7 +784,7 @@
   return div (mul (aa, bb), g);
 }
 
-Value ValueCalc::base (const Value &val, int base, int prec)
+Value ValueCalc::base (const Value &val, int base, int prec, int minLength)
 {
   if (prec < 0) prec = 2;
   if ((base < 2) || (base > 36))
@@ -792,6 +792,8 @@
 
   double value = converter->asFloat (val).asFloat();
   QString result = QString::number ((int)value, base);
+  if ( result.length() < minLength )
+      result = result.rightJustified( minLength, QChar( '0' ) );
 
   if (prec > 0)
   {
--- trunk/koffice/kspread/ValueCalc.h #623120:623121
@@ -176,7 +176,7 @@
   Value lcm (const Value &a, const Value &b);
 
   /** base conversion 10 -> base */
-  Value base (const Value &val, int base = 16, int prec = 0);
+  Value base (const Value &val, int base = 16, int prec = 0, int minLength = 0);
   /** base conversion base -> 10 */
   Value fromBase (const Value &val, int base = 16);
 
--- trunk/koffice/kspread/functions/engineering.cpp #623120:623121
@@ -58,6 +58,7 @@
 Value func_dec2hex (valVector args, ValueCalc *calc, FuncExtra *);
 Value func_dec2oct (valVector args, ValueCalc *calc, FuncExtra *);
 Value func_dec2bin (valVector args, ValueCalc *calc, FuncExtra *);
+Value func_decimal (valVector args, ValueCalc *calc, FuncExtra *);
 Value func_delta (valVector args, ValueCalc *calc, FuncExtra *);
 Value func_erf (valVector args, ValueCalc *calc, FuncExtra *);
 Value func_erfc (valVector args, ValueCalc *calc, FuncExtra *);
@@ -108,8 +109,10 @@
   f = new Function ("BIN2DEC",     func_bin2dec);
   repo->add (f);
   f = new Function ("BIN2OCT",     func_bin2oct);
+  f->setParamCount (1, 2 );
   repo->add (f);
   f = new Function ("BIN2HEX",     func_bin2hex);
+  f->setParamCount (1, 2 );
   repo->add (f);
   f = new Function ("COMPLEX",     func_complex);
   f->setParamCount (2);
@@ -118,11 +121,17 @@
   f->setParamCount (3);
   repo->add (f);
   f = new Function ("DEC2HEX",     func_dec2hex);
+  f->setParamCount (1, 2);
   repo->add (f);
   f = new Function ("DEC2BIN",     func_dec2bin);
+  f->setParamCount (1, 2);
   repo->add (f);
   f = new Function ("DEC2OCT",     func_dec2oct);
+  f->setParamCount (1, 2);
   repo->add (f);
+  f = new Function ("DECIMAL",     func_decimal);
+  f->setParamCount (2);
+  repo->add (f);
   f = new Function ("DELTA",       func_delta);
   f->setParamCount (1, 2);
   repo->add (f);
@@ -136,10 +145,12 @@
   f->setParamCount (1, 2);
   repo->add (f);
   f = new Function ("HEX2BIN",     func_hex2bin);
+  f->setParamCount (1, 2);
   repo->add (f);
   f = new Function ("HEX2DEC",     func_hex2dec);
   repo->add (f);
   f = new Function ("HEX2OCT",     func_hex2oct);
+  f->setParamCount (1, 2);
   repo->add (f);
   f = new Function ("IMABS",       func_imabs);
   repo->add (f);
@@ -185,10 +196,12 @@
   f->setAcceptArray ();
   repo->add (f);
   f = new Function ("OCT2BIN",     func_oct2bin);
+  f->setParamCount (1, 2);
   repo->add (f);
   f = new Function ("OCT2DEC",     func_oct2dec);
   repo->add (f);
   f = new Function ("OCT2HEX",     func_oct2hex);
+  f->setParamCount (1, 2);
   repo->add (f);
 }
 
@@ -196,17 +209,17 @@
 Value func_base (valVector args, ValueCalc *calc, FuncExtra *)
 {
   int base = 10;
-  int prec = 0;
+  int minLength = 0;
   if (args.count() > 1)
     base = calc->conv()->asInteger (args[1]).asInteger();
   if (args.count() == 3)
-    prec = calc->conv()->asInteger (args[2]).asInteger();
+    minLength = calc->conv()->asInteger (args[2]).asInteger();
 
   if ((base < 2) || (base > 36))
     return Value::errorVALUE();
-  if (prec < 0) prec = 2;
+  if (minLength < 0) minLength = 2;
 
-  return calc->base (args[0], base, prec);
+  return calc->base (args[0], base, 0, minLength);
 }
 
 // Function: BESSELI
@@ -244,19 +257,55 @@
 // Function: DEC2HEX
 Value func_dec2hex (valVector args, ValueCalc *calc, FuncExtra *)
 {
-  return calc->base (args[0], 16);
+    QRegExp rx("[0-9]+");
+    int minLength = 0;
+    if ( args.count() > 1 )
+        // we have the optional "minimum length" argument
+        minLength = calc->conv()->asInteger (args[1]).asInteger();
+
+    if ( rx.exactMatch( calc->conv()->asString( args[0] ).asString() ) )
+    {
+        // this only contains decimal digits.
+        return calc->base (args[0], 16, 0, minLength);
+    } else {
+        return Value::errorVALUE();
+    }
 }
 
 // Function: DEC2OCT
 Value func_dec2oct (valVector args, ValueCalc *calc, FuncExtra *)
 {
-  return calc->base (args[0], 8);
+    QRegExp rx("[0-9]+");
+    int minLength = 0;
+    if ( args.count() > 1 )
+        // we have the optional "minimum length" argument
+        minLength = calc->conv()->asInteger (args[1]).asInteger();
+
+    if ( rx.exactMatch( calc->conv()->asString( args[0] ).asString() ) )
+    {
+        // this only contains decimal digits.
+        return calc->base (args[0], 8, 0, minLength);
+    } else {
+        return Value::errorVALUE();
+    }
 }
 
 // Function: DEC2BIN
 Value func_dec2bin (valVector args, ValueCalc *calc, FuncExtra *)
 {
-  return calc->base (args[0], 2);
+    QRegExp rx("[0-9]+");
+    int minLength = 0;
+    if ( args.count() > 1 )
+        // we have the optional "minimum length" argument
+        minLength = calc->conv()->asInteger (args[1]).asInteger();
+
+    if ( rx.exactMatch( calc->conv()->asString( args[0] ).asString() ) )
+    {
+        // this only contains decimal digits.
+        return calc->base (args[0], 2, 0, minLength);
+    } else {
+        return Value::errorVALUE();
+    }
 }
 
 // Function: BIN2DEC
@@ -268,13 +317,38 @@
 // Function: BIN2OCT
 Value func_bin2oct (valVector args, ValueCalc *calc, FuncExtra *)
 {
-  return calc->base (calc->fromBase (args[0], 2), 8);
+    QRegExp rx("[01]+");
+    int minLength = 0;
+    if ( args.count() > 1 )
+        // we have the optional "minimum length" argument
+        minLength = calc->conv()->asInteger (args[1]).asInteger();
+
+    if ( rx.exactMatch( calc->conv()->asString( args[0] ).asString() ) )
+    {
+        // this only contains 0s and 1s.
+        return calc->base (calc->fromBase( args[0], 2 ), 8, 0, minLength);
+    } else {
+        return Value::errorVALUE();
+    }
 }
 
 // Function: BIN2HEX
 Value func_bin2hex (valVector args, ValueCalc *calc, FuncExtra *)
 {
-  return calc->base (calc->fromBase (args[0], 2), 16);
+    QRegExp rx("[01]+");
+    int minLength = 0;
+    if ( args.count() > 1 )
+        // we have the optional "minimum length" argument
+        minLength = calc->conv()->asInteger (args[1]).asInteger();
+
+    if ( rx.exactMatch( calc->conv()->asString( args[0] ).asString() ) )
+    {
+        // this only contains 0s and 1s.
+        return calc->base (calc->fromBase (args[0], 2), 16, 0, minLength);
+    } else {
+        return Value::errorVALUE();
+    }
+
 }
 
 // Function: OCT2DEC
@@ -286,13 +360,37 @@
 // Function: OCT2BIN
 Value func_oct2bin (valVector args, ValueCalc *calc, FuncExtra *)
 {
-  return calc->base (calc->fromBase (args[0], 8), 2);
+    QRegExp rx("[01234567]+");
+    int minLength = 0;
+    if ( args.count() > 1 )
+        // we have the optional "minimum length" argument
+        minLength = calc->conv()->asInteger (args[1]).asInteger();
+
+    if ( rx.exactMatch( calc->conv()->asString( args[0] ).asString() ) )
+    {
+        // this only contains decimal digits.
+        return calc->base (calc->fromBase( args[0], 8 ), 2, 0, minLength);
+    } else {
+        return Value::errorVALUE();
+    }
 }
 
 // Function: OCT2HEX
 Value func_oct2hex (valVector args, ValueCalc *calc, FuncExtra *)
 {
-  return calc->base (calc->fromBase (args[0], 8), 16);
+    QRegExp rx("[01234567]+");
+    int minLength = 0;
+    if ( args.count() > 1 )
+        // we have the optional "minimum length" argument
+        minLength = calc->conv()->asInteger (args[1]).asInteger();
+
+    if ( rx.exactMatch( calc->conv()->asString( args[0] ).asString() ) )
+    {
+        // this only contains decimal digits.
+        return calc->base (calc->fromBase( args[0], 8 ), 16, 0, minLength);
+    } else {
+        return Value::errorVALUE();
+    }
 }
 
 // Function: HEX2DEC
@@ -304,16 +402,63 @@
 // Function: HEX2BIN
 Value func_hex2bin (valVector args, ValueCalc *calc, FuncExtra *)
 {
-  return calc->base (calc->fromBase (args[0], 16), 2);
+    QRegExp rx("[0123456789ABCDEFabcdef]+");
+    int minLength = 0;
+    if ( args.count() > 1 )
+        // we have the optional "minimum length" argument
+        minLength = calc->conv()->asInteger (args[1]).asInteger();
+
+    if ( rx.exactMatch( calc->conv()->asString( args[0] ).asString() ) )
+    {
+        // this only contains decimal digits.
+        return calc->base (calc->fromBase( args[0], 16 ), 2, 0, minLength);
+    } else {
+        return Value::errorVALUE();
+    }
 }
 
 // Function: HEX2OCT
 Value func_hex2oct (valVector args, ValueCalc *calc, FuncExtra *)
 {
-  return calc->base (calc->fromBase (args[0], 16), 8);
+    QRegExp rx("[0123456789ABCDEFabcdef]+");
+    int minLength = 0;
+    if ( args.count() > 1 )
+        // we have the optional "minimum length" argument
+        minLength = calc->conv()->asInteger (args[1]).asInteger();
+
+    if ( rx.exactMatch( calc->conv()->asString( args[0] ).asString() ) )
+    {
+        // this only contains decimal digits.
+        return calc->base (calc->fromBase( args[0], 16 ), 8, 0, minLength);
+    } else {
+        return Value::errorVALUE();
+    }
 }
 
+// Function: DECIMAL
+Value func_decimal (valVector args, ValueCalc *calc, FuncExtra *)
+{
+    QString text = calc->conv()->asString( args[0] ).asString();
+    text.remove( QChar( ' ' ) );
+    text.remove( QChar( '\t' ) );
+    int radix = calc->conv()->asInteger (args[1]).asInteger();
+    if ( radix == 16 ) {
+        if ( text.startsWith( "0x", Qt::CaseInsensitive ) ) {
+            text = text.mid( 2 );
+        }
+        if ( text.endsWith( "h", Qt::CaseInsensitive ) ) {
+            text = text.left( text.length() -1 ); // all but the last char
+        }
+    }
+    if ( radix == 2 ) {
+        if ( text.endsWith( "b", Qt::CaseInsensitive ) ) {
+            text = text.left( text.length() -1 ); // all but the last char
+        }
+    }
 
+    return calc->fromBase ( Value( text ), radix );
+}
+
 // check if unit may contain prefix, for example "kPa" is "Pa" with
 // return prefix factor found in unit, or 1.0 for no prefix
 // also modify the unit, i.e stripping the prefix from it
--- trunk/koffice/kspread/functions/engineering.xml #623120:623121
@@ -15,15 +15,14 @@
 	<Comment>Base</Comment>
 	<Type>Int</Type>
       </Parameter>
-      <Parameter>
-	<Comment>Precision</Comment>
+      <Parameter optional="true">
+	<Comment>MinLength</Comment>
 	<Type>Int</Type>
       </Parameter>
       <Help>
 	<Text>The BASE() function converts a number from base-10 to a string value in a \
target base from 2 to 36.</Text>  <Syntax>BASE(number;base;prec)</Syntax>
 	<Example>BASE(128;8) returns "200"</Example>
-	<Example>BASE(123.47;16;6) returns "7B.7851EB"</Example>
       </Help>
     </Function>
 
@@ -192,6 +191,10 @@
 	<Comment>The value to convert</Comment>
 	<Type>Int</Type>
       </Parameter>
+      <Parameter optional="true">
+	<Comment>The minimum length of the output</Comment>
+	<Type>Int</Type>
+      </Parameter>
       <Help>
 	<Text>The DEC2BIN() function returns the value formatted as a binary number.</Text>
 	<Syntax>DEC2BIN(value)</Syntax>
@@ -207,6 +210,10 @@
 	<Comment>The value to convert</Comment>
 	<Type>Int</Type>
       </Parameter>
+      <Parameter optional="true">
+	<Comment>The minimum length of the output</Comment>
+	<Type>Int</Type>
+      </Parameter>
       <Help>
 	<Text>The DEC2HEX() function returns the value formatted as a hexadecimal \
number.</Text>  <Syntax>DEC2HEX(value)</Syntax>
@@ -222,6 +229,10 @@
 	<Comment>The value to convert</Comment>
 	<Type>Int</Type>
       </Parameter>
+      <Parameter optional="true">
+	<Comment>The minimum length of the output</Comment>
+	<Type>Int</Type>
+      </Parameter>
       <Help>
 	<Text>The DEC2OCT() function returns the value formatted as an octal number.</Text>
 	<Syntax>DEC2OCT(value)</Syntax>
@@ -237,6 +248,10 @@
 	<Comment>The value to convert</Comment>
 	<Type>String</Type>
       </Parameter>
+      <Parameter optional="true">
+	<Comment>The minimum length of the output</Comment>
+	<Type>Int</Type>
+      </Parameter>
       <Help>
 	<Text>The OCT2BIN() function returns the value formatted as a binary number.</Text>
 	<Syntax>OCT2BIN(value)</Syntax>
@@ -267,11 +282,15 @@
 	<Comment>The value to convert</Comment>
 	<Type>String</Type>
       </Parameter>
+      <Parameter optional="true">
+	<Comment>The minimum length of the output</Comment>
+	<Type>Int</Type>
+      </Parameter>
       <Help>
 	<Text>The OCT2HEX() function returns the value formatted as a hexadecimal \
number.</Text>  <Syntax>OCT2HEX(value)</Syntax>
-	<Example>OCT2HEX("12") returns "a"</Example>
-	<Example>OCT2HEX("55") returns "2d"</Example>
+	<Example>OCT2HEX("12") returns "A"</Example>
+	<Example>OCT2HEX("55") returns "2D"</Example>
       </Help>
     </Function>
 
@@ -297,6 +316,10 @@
 	<Comment>The value to convert</Comment>
 	<Type>String</Type>
       </Parameter>
+      <Parameter optional="true">
+	<Comment>The minimum length of the output</Comment>
+	<Type>Int</Type>
+      </Parameter>
       <Help>
 	<Text>The BIN2OCT() function returns the value formatted as an octal number.</Text>
 	<Syntax>BIN2OCT(value)</Syntax>
@@ -312,6 +335,10 @@
 	<Comment>The value to convert</Comment>
 	<Type>String</Type>
       </Parameter>
+      <Parameter optional="true">
+	<Comment>The minimum length of the output</Comment>
+	<Type>Int</Type>
+      </Parameter>
       <Help>
 	<Text>The BIN2HEX() function returns the value formatted as a hexadecimal \
number.</Text>  <Syntax>BIN2HEX(value)</Syntax>


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic