1 /* This file is part of the KDE project
2    Copyright (C) 1998-2002 The KSpread Team <calligra-devel@kde.org>
3    Copyright (C) 2005 Tomas Mecir <mecirt@gmail.com>
4    Copyright 2007 Sascha Pfau <MrPeacock@gmail.com>
5 
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public
8    License as published by the Free Software Foundation; only
9    version 2 of the License.
10 
11    This library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15 
16    You should have received a copy of the GNU Library General Public License
17    along with this library; see the file COPYING.LIB.  If not, write to
18    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19    Boston, MA 02110-1301, USA.
20 */
21 
22 // built-in engineering functions
23 
24 #include "EngineeringModule.h"
25 
26 #include "Function.h"
27 #include "FunctionModuleRegistry.h"
28 #include "ValueCalc.h"
29 #include "ValueConverter.h"
30 
31 // used by the CONVERT function
32 #include <QMap>
33 
34 // these are needed for complex functions, while we handle them in the old way
35 #include <math.h>
36 
37 #ifndef M_LN2l
38 #define M_LN2l 0.6931471805599453094172321214581766L
39 #endif
40 
41 using namespace Calligra::Sheets;
42 
43 // prototypes (sort alphabetically)
44 Value func_base(valVector args, ValueCalc *calc, FuncExtra *);
45 Value func_besseli(valVector args, ValueCalc *calc, FuncExtra *);
46 Value func_besselj(valVector args, ValueCalc *calc, FuncExtra *);
47 Value func_besselk(valVector args, ValueCalc *calc, FuncExtra *);
48 Value func_bessely(valVector args, ValueCalc *calc, FuncExtra *);
49 Value func_bin2dec(valVector args, ValueCalc *calc, FuncExtra *);
50 Value func_bin2oct(valVector args, ValueCalc *calc, FuncExtra *);
51 Value func_bin2hex(valVector args, ValueCalc *calc, FuncExtra *);
52 Value func_complex(valVector args, ValueCalc *calc, FuncExtra *);
53 Value func_complex_imag(valVector args, ValueCalc *calc, FuncExtra *);
54 Value func_complex_real(valVector args, ValueCalc *calc, FuncExtra *);
55 Value func_convert(valVector args, ValueCalc *calc, FuncExtra *);
56 Value func_dec2hex(valVector args, ValueCalc *calc, FuncExtra *);
57 Value func_dec2oct(valVector args, ValueCalc *calc, FuncExtra *);
58 Value func_dec2bin(valVector args, ValueCalc *calc, FuncExtra *);
59 Value func_decimal(valVector args, ValueCalc *calc, FuncExtra *);
60 Value func_delta(valVector args, ValueCalc *calc, FuncExtra *);
61 Value func_erf(valVector args, ValueCalc *calc, FuncExtra *);
62 Value func_erfc(valVector args, ValueCalc *calc, FuncExtra *);
63 Value func_gestep(valVector args, ValueCalc *calc, FuncExtra *);
64 Value func_hex2dec(valVector args, ValueCalc *calc, FuncExtra *);
65 Value func_hex2bin(valVector args, ValueCalc *calc, FuncExtra *);
66 Value func_hex2oct(valVector args, ValueCalc *calc, FuncExtra *);
67 Value func_imabs(valVector args, ValueCalc *calc, FuncExtra *);
68 Value func_imargument(valVector args, ValueCalc *calc, FuncExtra *);
69 Value func_imconjugate(valVector args, ValueCalc *calc, FuncExtra *);
70 Value func_imcos(valVector args, ValueCalc *calc, FuncExtra *);
71 Value func_imcosh(valVector args, ValueCalc *calc, FuncExtra *);
72 Value func_imcot(valVector args, ValueCalc *calc, FuncExtra *);
73 Value func_imcsc(valVector args, ValueCalc *calc, FuncExtra *);
74 Value func_imcsch(valVector args, ValueCalc *calc, FuncExtra *);
75 Value func_imdiv(valVector args, ValueCalc *calc, FuncExtra *);
76 Value func_imexp(valVector args, ValueCalc *calc, FuncExtra *);
77 Value func_imln(valVector args, ValueCalc *calc, FuncExtra *);
78 Value func_imlog2(valVector args, ValueCalc *calc, FuncExtra *);
79 Value func_imlog10(valVector args, ValueCalc *calc, FuncExtra *);
80 Value func_impower(valVector args, ValueCalc *calc, FuncExtra *);
81 Value func_improduct(valVector args, ValueCalc *calc, FuncExtra *);
82 Value func_imsec(valVector args, ValueCalc *calc, FuncExtra *);
83 Value func_imsech(valVector args, ValueCalc *calc, FuncExtra *);
84 Value func_imsin(valVector args, ValueCalc *calc, FuncExtra *);
85 Value func_imsinh(valVector args, ValueCalc *calc, FuncExtra *);
86 Value func_imsqrt(valVector args, ValueCalc *calc, FuncExtra *);
87 Value func_imsub(valVector args, ValueCalc *calc, FuncExtra *);
88 Value func_imsum(valVector args, ValueCalc *calc, FuncExtra *);
89 Value func_imtan(valVector args, ValueCalc *calc, FuncExtra *);
90 Value func_imtanh(valVector args, ValueCalc *calc, FuncExtra *);
91 Value func_oct2dec(valVector args, ValueCalc *calc, FuncExtra *);
92 Value func_oct2bin(valVector args, ValueCalc *calc, FuncExtra *);
93 Value func_oct2hex(valVector args, ValueCalc *calc, FuncExtra *);
94 
95 
96 CALLIGRA_SHEETS_EXPORT_FUNCTION_MODULE("kspreadengineeringmodule.json", EngineeringModule)
97 
98 
EngineeringModule(QObject * parent,const QVariantList &)99 EngineeringModule::EngineeringModule(QObject* parent, const QVariantList&)
100         : FunctionModule(parent)
101 {
102     Function *f;
103 
104     f = new Function("BASE",        func_base);     // Calligra Sheets-specific, like in Quattro-Pro
105     f->setParamCount(1, 3);
106     add(f);
107     f = new Function("BESSELI",     func_besseli);
108     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETBESSELI");
109     f->setParamCount(2);
110     add(f);
111     f = new Function("BESSELJ",     func_besselj);
112     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETBESSELJ");
113     f->setParamCount(2);
114     add(f);
115     f = new Function("BESSELK",     func_besselk);
116     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETBESSELK");
117     f->setParamCount(2);
118     add(f);
119     f = new Function("BESSELY",     func_bessely);
120     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETBESSELY");
121     f->setParamCount(2);
122     add(f);
123     f = new Function("BIN2DEC",     func_bin2dec);
124     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETBIN2DEC");
125     add(f);
126     f = new Function("BIN2OCT",     func_bin2oct);
127     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETBIN2OCT");
128     f->setParamCount(1, 2);
129     add(f);
130     f = new Function("BIN2HEX",     func_bin2hex);
131     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETBIN2HEX");
132     f->setParamCount(1, 2);
133     add(f);
134     f = new Function("COMPLEX",     func_complex);
135     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETCOMPLEX");
136     f->setParamCount(2, 3);
137     add(f);
138     f = new Function("CONVERT",     func_convert);
139     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETCONVERT");
140     f->setParamCount(3);
141     add(f);
142     f = new Function("DEC2HEX",     func_dec2hex);
143     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETDEC2HEX");
144     f->setParamCount(1, 2);
145     add(f);
146     f = new Function("DEC2BIN",     func_dec2bin);
147     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETDEC2BIN");
148     f->setParamCount(1, 2);
149     add(f);
150     f = new Function("DEC2OCT",     func_dec2oct);
151     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETDEC2OCT");
152     f->setParamCount(1, 2);
153     add(f);
154     f = new Function("DECIMAL",     func_decimal);
155     f->setParamCount(2);
156     add(f);
157     f = new Function("DELTA",       func_delta);
158     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETDELTA");
159     f->setParamCount(1, 2);
160     add(f);
161     f = new Function("ERF",         func_erf);
162     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETERF");
163     f->setParamCount(1, 2);
164     add(f);
165     f = new Function("ERFC",        func_erfc);
166     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETERFC");
167     f->setParamCount(1, 2);
168     add(f);
169     f = new Function("GESTEP",      func_gestep);
170     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETGESTEP");
171     f->setParamCount(1, 2);
172     add(f);
173     f = new Function("HEX2BIN",     func_hex2bin);
174     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETHEX2BIN");
175     f->setParamCount(1, 2);
176     add(f);
177     f = new Function("HEX2DEC",     func_hex2dec);
178     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETHEX2DEC");
179     add(f);
180     f = new Function("HEX2OCT",     func_hex2oct);
181     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETHEX2OCT");
182     f->setParamCount(1, 2);
183     add(f);
184     f = new Function("IMABS",       func_imabs);
185     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMABS");
186     add(f);
187     f = new Function("IMAGINARY",   func_complex_imag);
188     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMAGINARY");
189     add(f);
190     f = new Function("IMARGUMENT",  func_imargument);
191     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMARGUMENT");
192     add(f);
193     f = new Function("IMCONJUGATE", func_imconjugate);
194     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMCONJUGATE");
195     add(f);
196     f = new Function("IMCOS",       func_imcos);
197     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMCOS");
198     add(f);
199     f = new Function("IMCOSH",      func_imcosh);
200     add(f);
201     f = new Function("IMCOT",       func_imcot);
202     add(f);
203     f = new Function("IMCSC",       func_imcsc);
204     add(f);
205     f = new Function("IMCSCH",       func_imcsch);
206     add(f);
207     f = new Function("IMDIV",       func_imdiv);
208     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMDIV");
209     f->setParamCount(2);
210     f->setAcceptArray();
211     add(f);
212     f = new Function("IMEXP",       func_imexp);
213     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMEXP");
214     add(f);
215     f = new Function("IMLN",        func_imln);
216     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMLN");
217     add(f);
218     f = new Function("IMLOG2",      func_imlog2);
219     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMLOG2");
220     add(f);
221     f = new Function("IMLOG10",     func_imlog10);
222     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMLOG10");
223     add(f);
224     f = new Function("IMPOWER",     func_impower);
225     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMPOWER");
226     f->setParamCount(2);
227     add(f);
228     f = new Function("IMPRODUCT",   func_improduct);
229     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMPRODUCT");
230     f->setParamCount(1, -1);
231     f->setAcceptArray();
232     add(f);
233     f = new Function("IMREAL",      func_complex_real);
234     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMREAL");
235     add(f);
236     f = new Function("IMSEC",       func_imsec);
237     add(f);
238     f = new Function("IMSECH",       func_imsech);
239     add(f);
240     f = new Function("IMSIN",       func_imsin);
241     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMSIN");
242     add(f);
243     f = new Function("IMSINH",      func_imsinh);
244     add(f);
245     f = new Function("IMSQRT",      func_imsqrt);
246     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMSQRT");
247     add(f);
248     f = new Function("IMSUB",       func_imsub);
249     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMSUB");
250     f->setParamCount(2);
251     f->setAcceptArray();
252     add(f);
253     f = new Function("IMSUM",       func_imsum);
254     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMSUM");
255     f->setParamCount(1, -1);
256     f->setAcceptArray();
257     add(f);
258     f = new Function("IMTAN",       func_imtan);
259     add(f);
260     f = new Function("IMTANH",      func_imtanh);
261     add(f);
262     f = new Function("OCT2BIN",     func_oct2bin);
263     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETOCT2BIN");
264     f->setParamCount(1, 2);
265     add(f);
266     f = new Function("OCT2DEC",     func_oct2dec);
267     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETOCT2DEC");
268     add(f);
269     f = new Function("OCT2HEX",     func_oct2hex);
270     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETOCT2HEX");
271     f->setParamCount(1, 2);
272     add(f);
273 }
274 
descriptionFileName() const275 QString EngineeringModule::descriptionFileName() const
276 {
277     return QString("engineering.xml");
278 }
279 
280 
281 //
282 // Function: BASE
283 //
func_base(valVector args,ValueCalc * calc,FuncExtra *)284 Value func_base(valVector args, ValueCalc *calc, FuncExtra *)
285 {
286     int base = 10;
287     int minLength = 0;
288     if (args.count() > 1)
289         base = calc->conv()->asInteger(args[1]).asInteger();
290     if (args.count() == 3)
291         minLength = calc->conv()->asInteger(args[2]).asInteger();
292 
293     if ((base < 2) || (base > 36))
294         return Value::errorVALUE();
295     if (minLength < 0) minLength = 2;
296 
297     return calc->base(args[0], base, 0, minLength);
298 }
299 
300 
301 //
302 // Function: BESSELI
303 //
func_besseli(valVector args,ValueCalc * calc,FuncExtra *)304 Value func_besseli(valVector args, ValueCalc *calc, FuncExtra *)
305 {
306     Value x = args[0];
307     Value y = args[1];
308     return calc->besseli(y, x);
309 }
310 
311 
312 //
313 // Function: BESSELJ
314 //
func_besselj(valVector args,ValueCalc * calc,FuncExtra *)315 Value func_besselj(valVector args, ValueCalc *calc, FuncExtra *)
316 {
317     Value x = args[0];
318     Value y = args[1];
319     return calc->besselj(y, x);
320 }
321 
322 
323 //
324 // Function: BESSELK
325 //
func_besselk(valVector args,ValueCalc * calc,FuncExtra *)326 Value func_besselk(valVector args, ValueCalc *calc, FuncExtra *)
327 {
328     Value x = args[0];
329     Value y = args[1];
330     return calc->besselk(y, x);
331 }
332 
333 
334 //
335 // Function: BESSELY
336 //
func_bessely(valVector args,ValueCalc * calc,FuncExtra *)337 Value func_bessely(valVector args, ValueCalc *calc, FuncExtra *)
338 {
339     Value x = args[0];
340     Value y = args[1];
341     return calc->besseln(y, x);
342 }
343 
344 
345 //
346 // Function: DEC2HEX
347 //
func_dec2hex(valVector args,ValueCalc * calc,FuncExtra *)348 Value func_dec2hex(valVector args, ValueCalc *calc, FuncExtra *)
349 {
350     QRegExp rx("[0-9]+");
351     int minLength = 0;
352     if (args.count() > 1)
353         // we have the optional "minimum length" argument
354         minLength = calc->conv()->asInteger(args[1]).asInteger();
355 
356     if (rx.exactMatch(calc->conv()->asString(args[0]).asString())) {
357         // this only contains decimal digits.
358         return calc->base(args[0], 16, 0, minLength);
359     } else {
360         return Value::errorVALUE();
361     }
362 }
363 
364 
365 //
366 // Function: DEC2OCT
367 //
func_dec2oct(valVector args,ValueCalc * calc,FuncExtra *)368 Value func_dec2oct(valVector args, ValueCalc *calc, FuncExtra *)
369 {
370     QRegExp rx("[0-9]+");
371     int minLength = 0;
372     if (args.count() > 1)
373         // we have the optional "minimum length" argument
374         minLength = calc->conv()->asInteger(args[1]).asInteger();
375 
376     if (rx.exactMatch(calc->conv()->asString(args[0]).asString())) {
377         // this only contains decimal digits.
378         return calc->base(args[0], 8, 0, minLength);
379     } else {
380         return Value::errorVALUE();
381     }
382 }
383 
384 
385 //
386 // Function: DEC2BIN
387 //
func_dec2bin(valVector args,ValueCalc * calc,FuncExtra *)388 Value func_dec2bin(valVector args, ValueCalc *calc, FuncExtra *)
389 {
390     QRegExp rx("[0-9]+");
391     int minLength = 0;
392     if (args.count() > 1)
393         // we have the optional "minimum length" argument
394         minLength = calc->conv()->asInteger(args[1]).asInteger();
395 
396     if (rx.exactMatch(calc->conv()->asString(args[0]).asString())) {
397         // this only contains decimal digits.
398         return calc->base(args[0], 2, 0, minLength);
399     } else {
400         return Value::errorVALUE();
401     }
402 }
403 
404 
405 //
406 // Function: BIN2DEC
407 //
func_bin2dec(valVector args,ValueCalc * calc,FuncExtra *)408 Value func_bin2dec(valVector args, ValueCalc *calc, FuncExtra *)
409 {
410     return calc->fromBase(args[0], 2);
411 }
412 
413 
414 //
415 // Function: BIN2OCT
416 //
func_bin2oct(valVector args,ValueCalc * calc,FuncExtra *)417 Value func_bin2oct(valVector args, ValueCalc *calc, FuncExtra *)
418 {
419     QRegExp rx("[01]+");
420     int minLength = 0;
421     if (args.count() > 1)
422         // we have the optional "minimum length" argument
423         minLength = calc->conv()->asInteger(args[1]).asInteger();
424 
425     if (rx.exactMatch(calc->conv()->asString(args[0]).asString())) {
426         // this only contains 0s and 1s.
427         return calc->base(calc->fromBase(args[0], 2), 8, 0, minLength);
428     } else {
429         return Value::errorVALUE();
430     }
431 }
432 
433 
434 //
435 // Function: BIN2HEX
436 //
func_bin2hex(valVector args,ValueCalc * calc,FuncExtra *)437 Value func_bin2hex(valVector args, ValueCalc *calc, FuncExtra *)
438 {
439     QRegExp rx("[01]+");
440     int minLength = 0;
441     if (args.count() > 1)
442         // we have the optional "minimum length" argument
443         minLength = calc->conv()->asInteger(args[1]).asInteger();
444 
445     if (rx.exactMatch(calc->conv()->asString(args[0]).asString())) {
446         // this only contains 0s and 1s.
447         return calc->base(calc->fromBase(args[0], 2), 16, 0, minLength);
448     } else {
449         return Value::errorVALUE();
450     }
451 
452 }
453 
454 
455 //
456 // Function: OCT2DEC
457 //
func_oct2dec(valVector args,ValueCalc * calc,FuncExtra *)458 Value func_oct2dec(valVector args, ValueCalc *calc, FuncExtra *)
459 {
460     return calc->fromBase(args[0], 8);
461 }
462 
463 
464 //
465 // Function: OCT2BIN
466 //
func_oct2bin(valVector args,ValueCalc * calc,FuncExtra *)467 Value func_oct2bin(valVector args, ValueCalc *calc, FuncExtra *)
468 {
469     QRegExp rx("[01234567]+");
470     int minLength = 0;
471     if (args.count() > 1)
472         // we have the optional "minimum length" argument
473         minLength = calc->conv()->asInteger(args[1]).asInteger();
474 
475     if (rx.exactMatch(calc->conv()->asString(args[0]).asString())) {
476         // this only contains decimal digits.
477         return calc->base(calc->fromBase(args[0], 8), 2, 0, minLength);
478     } else {
479         return Value::errorVALUE();
480     }
481 }
482 
483 
484 //
485 // Function: OCT2HEX
486 //
func_oct2hex(valVector args,ValueCalc * calc,FuncExtra *)487 Value func_oct2hex(valVector args, ValueCalc *calc, FuncExtra *)
488 {
489     QRegExp rx("[01234567]+");
490     int minLength = 0;
491     if (args.count() > 1)
492         // we have the optional "minimum length" argument
493         minLength = calc->conv()->asInteger(args[1]).asInteger();
494 
495     if (rx.exactMatch(calc->conv()->asString(args[0]).asString())) {
496         // this only contains decimal digits.
497         return calc->base(calc->fromBase(args[0], 8), 16, 0, minLength);
498     } else {
499         return Value::errorVALUE();
500     }
501 }
502 
503 
504 //
505 // Function: HEX2DEC
506 //
func_hex2dec(valVector args,ValueCalc * calc,FuncExtra *)507 Value func_hex2dec(valVector args, ValueCalc *calc, FuncExtra *)
508 {
509     return calc->fromBase(args[0], 16);
510 }
511 
512 
513 //
514 // Function: HEX2BIN
515 //
func_hex2bin(valVector args,ValueCalc * calc,FuncExtra *)516 Value func_hex2bin(valVector args, ValueCalc *calc, FuncExtra *)
517 {
518     QRegExp rx("[0123456789ABCDEFabcdef]+");
519     int minLength = 0;
520     if (args.count() > 1)
521         // we have the optional "minimum length" argument
522         minLength = calc->conv()->asInteger(args[1]).asInteger();
523 
524     if (rx.exactMatch(calc->conv()->asString(args[0]).asString())) {
525         // this only contains decimal digits.
526         return calc->base(calc->fromBase(args[0], 16), 2, 0, minLength);
527     } else {
528         return Value::errorVALUE();
529     }
530 }
531 
532 
533 //
534 // Function: HEX2OCT
535 //
func_hex2oct(valVector args,ValueCalc * calc,FuncExtra *)536 Value func_hex2oct(valVector args, ValueCalc *calc, FuncExtra *)
537 {
538     QRegExp rx("[0123456789ABCDEFabcdef]+");
539     int minLength = 0;
540     if (args.count() > 1)
541         // we have the optional "minimum length" argument
542         minLength = calc->conv()->asInteger(args[1]).asInteger();
543 
544     if (rx.exactMatch(calc->conv()->asString(args[0]).asString())) {
545         // this only contains decimal digits.
546         return calc->base(calc->fromBase(args[0], 16), 8, 0, minLength);
547     } else {
548         return Value::errorVALUE();
549     }
550 }
551 
552 
553 //
554 // Function: DECIMAL
555 //
func_decimal(valVector args,ValueCalc * calc,FuncExtra *)556 Value func_decimal(valVector args, ValueCalc *calc, FuncExtra *)
557 {
558     QString text = calc->conv()->asString(args[0]).asString();
559     text.remove(QLatin1Char(' '));
560     text.remove(QLatin1Char('\t'));
561     int radix = calc->conv()->asInteger(args[1]).asInteger();
562     if (radix == 16) {
563         if (text.startsWith(QLatin1String("0x"), Qt::CaseInsensitive)) {
564             text.remove(0, 2);
565         }
566         if (text.endsWith(QLatin1Char('h'), Qt::CaseInsensitive)) {
567             text.chop(1);  // all but the last char
568         }
569     }
570     if (radix == 2) {
571         if (text.endsWith(QLatin1Char('b'), Qt::CaseInsensitive)) {
572             text.chop(1);  // all but the last char
573         }
574     }
575 
576     return calc->fromBase(Value(text), radix);
577 }
578 
579 //
580 // convert prefix
581 //
582 
583 // check if unit may contain prefix, for example "kPa" is "Pa" with
584 // return prefix factor found in unit, or 1.0 for no prefix
585 // also modify the unit, i.e stripping the prefix from it
586 // example: "kPa" will return 1e3 and change unit into "Pa"
kspread_convert_prefix(QMap<QString,double> map,QString & unit)587 static double kspread_convert_prefix(QMap<QString, double> map, QString& unit)
588 {
589     if (map.contains(unit))
590         return 1.0;
591 
592     // initialize prefix mapping if necessary
593     static QMap<QString, double> prefixMap;
594     if (prefixMap.isEmpty()) {
595         prefixMap[ "Y" ]  = 1e24;   // yotta
596         prefixMap[ "Z" ]  = 1e21;   // zetta
597         prefixMap[ "E" ]  = 1e18;   // exa
598         prefixMap[ "P" ]  = 1e15;   // peta
599         prefixMap[ "T" ]  = 1e12;   // tera
600         prefixMap[ "G" ]  = 1e9;    // giga
601         prefixMap[ "M" ]  = 1e6;    // mega
602         prefixMap[ "k" ]  = 1e3;    // kilo
603         prefixMap[ "h" ]  = 1e2;    // hecto
604         prefixMap[ "e" ]  = 1e1;    // deka
605         prefixMap[ "da" ] = 1e1;    // deka
606         prefixMap[ "d" ]  = 1e-1;   // deci
607         prefixMap[ "c" ]  = 1e-2;   // centi
608         prefixMap[ "m" ]  = 1e-3;   // milli
609         prefixMap[ "u" ]  = 1e-6;   // micro
610         prefixMap[ "n" ]  = 1e-9;   // nano
611         prefixMap[ "p" ]  = 1e-12;  // pico
612         prefixMap[ "f" ]  = 1e-15;  // femto
613         prefixMap[ "a" ]  = 1e-18;  // atto
614         prefixMap[ "z" ]  = 1e-21;  // zepto
615         prefixMap[ "y" ]  = 1e-24;  // yocto
616 
617         // binary prefixes
618         prefixMap[ "ki" ]  = 1024.0                      ;  // kibi
619         prefixMap[ "Mi" ]  = 1048576.0                   ;  // mebi
620         prefixMap[ "Gi" ]  = 1073741824.0                ;  // gibi
621         prefixMap[ "Ti" ]  = 1099511627776.0             ;  // tebi
622         prefixMap[ "Pi" ]  = 1125899906842624.0          ;  // pebi
623         prefixMap[ "Ei" ]  = 1152921504606846976.0       ;  // exbi
624         prefixMap[ "Zi" ]  = 1180591620717411303424.0    ;  // zebi
625         prefixMap[ "Yi" ]  = 1208925819614629174706176.0 ;  // yobi
626     }
627 
628     // check for possible prefix
629     QString prefix = unit.left(2).toLatin1();
630 
631     if (prefixMap.contains(prefix)) {
632         unit.remove(0, 2);
633         return prefixMap[prefix];
634     } else if (prefixMap.contains(prefix.left(1))) {
635         unit.remove(0, 1);
636         return prefixMap[prefix.left(1)];
637     }
638     // fail miserably
639     return 0.0;
640 }
641 
642 
643 //
644 // convert masses
645 //
kspread_convert_mass(const QString & fromUnit,const QString & toUnit,double value,double & result)646 static bool kspread_convert_mass(const QString& fromUnit,
647                                  const QString& toUnit, double value, double& result)
648 {
649     static QMap<QString, double> massMap;
650 
651     // first-time initialization
652     if (massMap.isEmpty()) {
653         massMap[ "g" ]        = 1.0; // Gram (the reference )
654 
655         massMap[ "sg" ]       = 6.8522050005347800E-05;          // Pieces
656         massMap[ "lbm" ]      = 2.2046229146913400E-03;          // Pound
657         massMap[ "u" ]        = 6.0221370000000000E23;           // U (atomic mass)
658         massMap[ "ozm" ]      = 3.5273971800362700E-02;          // Ounce
659         massMap[ "stone" ]    = 1.574730e-04;                    // Stone
660         massMap[ "ton" ]      = 1.102311e-06;                    // Ton
661         massMap[ "grain" ]    = 1.543236E01;                     // Grain
662         massMap[ "pweight" ]  = 7.054792E-01;                    // Pennyweight
663         massMap[ "hweight" ]  = 1.968413E-05;                    // Hundredweight
664         massMap[ "shweight" ] = 2.204623E-05;                    // Shorthundredweight
665         massMap[ "uk_ton" ]   = 1.0 / 2240 * 2.2046229146913400E-03; // It's long ton or Imperial ton, 2240 lbm.
666     }
667 
668     QString fromU = fromUnit;
669     QString toU = toUnit;
670     double fromPrefix = kspread_convert_prefix(massMap, fromU);
671     double toPrefix = kspread_convert_prefix(massMap, toU);
672     if (fromPrefix == 0.0) return false;
673     if (toPrefix == 0.0) return false;
674     if (!massMap.contains(fromU)) return false;
675     if (!massMap.contains(toU)) return false;
676 
677     result = value * fromPrefix * massMap[toU] / (massMap[fromU] * toPrefix);
678 
679     return true;
680 }
681 
682 
683 //
684 // convert distances
685 //
kspread_convert_distance(const QString & fromUnit,const QString & toUnit,double value,double & result)686 static bool kspread_convert_distance(const QString& fromUnit,
687                                      const QString& toUnit, double value, double& result)
688 {
689     static QMap<QString, double> distanceMap;
690 
691     // first-time initialization
692     if (distanceMap.isEmpty()) {
693         distanceMap[ "m" ]          = 1.0;  // meter (the reference)
694 
695         distanceMap[ "ang" ]        = 1e10;                        // Angstrom
696         distanceMap[ "ell" ]        = 1.0 / (45.0 * 0.0254);       // Ell, exactly 45 international inches
697         distanceMap[ "ft" ]         = 1.0 / (12.0 * 0.0254);       // feet
698         distanceMap[ "in" ]         = 1.0 / 0.0254;                // inch
699         distanceMap[ "lightyear" ]  = 1.057023455773293e-16;       // lightyear
700         distanceMap[ "ly" ]         = 1.057023455773293e-16;       // lightyear
701         distanceMap[ "mi" ]         = 6.2137119223733397e-4;       // mile
702         distanceMap[ "Nmi" ]        = 5.3995680345572354e-04;      // nautical mile
703         distanceMap[ "parsec" ]     = 3.240779e-17;                // Parsec
704         distanceMap[ "pc" ]         = 3.240779e-17;                // Parsec
705         distanceMap[ "Pica" ]       = 1.0 * 72 / 0.0254;           // Pica (1/72) inch
706         distanceMap[ "statute_mi" ] = 1.0 / (6336000.0 / 3937.0);  // U.S. survey mile aka U.S. statute mile
707         distanceMap[ "yd" ]         = 1.0 / (3.0 * 12.0 * 0.0254); // yard
708     }
709 
710     QString fromU = fromUnit;
711     QString toU = toUnit;
712     double fromPrefix = kspread_convert_prefix(distanceMap, fromU);
713     double toPrefix = kspread_convert_prefix(distanceMap, toU);
714     if (fromPrefix == 0.0) return false;
715     if (toPrefix == 0.0) return false;
716     if (!distanceMap.contains(fromU)) return false;
717     if (!distanceMap.contains(toU)) return false;
718 
719     result = value * fromPrefix * distanceMap[toU] / (distanceMap[fromU] * toPrefix);
720 
721     return true;
722 }
723 
724 
725 //
726 // convert pressures
727 //
kspread_convert_pressure(const QString & fromUnit,const QString & toUnit,double value,double & result)728 static bool kspread_convert_pressure(const QString& fromUnit,
729                                      const QString& toUnit, double value, double& result)
730 {
731     static QMap<QString, double> pressureMap;
732 
733     // first-time initialization
734     if (pressureMap.isEmpty()) {
735         pressureMap[ "Pa" ]   = 1.0;
736 
737         pressureMap[ "atm" ]  = 0.9869233e-5;  // Atmosphere
738         pressureMap[ "atm" ]  = 0.9869233e-5;  // Atmosphere
739         pressureMap[ "mmHg" ] = 0.00750061708; // mm of Mercury
740         pressureMap[ "psi" ]  = 1 / 6894.754;  // Pounds per square inch
741         pressureMap[ "Torr" ] = 1 / 133.32237; // Torr, exactly 101325/760 Pa
742     }
743 
744     QString fromU = fromUnit;
745     QString toU = toUnit;
746     double fromPrefix = kspread_convert_prefix(pressureMap, fromU);
747     double toPrefix = kspread_convert_prefix(pressureMap, toU);
748     if (fromPrefix == 0.0) return false;
749     if (toPrefix == 0.0) return false;
750     if (!pressureMap.contains(fromU)) return false;
751     if (!pressureMap.contains(toU)) return false;
752 
753     result = value * fromPrefix * pressureMap[toU] / (pressureMap[fromU] * toPrefix);
754 
755     return true;
756 }
757 
758 
759 //
760 // convert forces
761 //
kspread_convert_force(const QString & fromUnit,const QString & toUnit,double value,double & result)762 static bool kspread_convert_force(const QString& fromUnit,
763                                   const QString& toUnit, double value, double& result)
764 {
765     static QMap<QString, double> forceMap;
766 
767     // first-time initialization
768     if (forceMap.isEmpty()) {
769         forceMap[ "N" ]      = 1.0;          // Newton (reference)
770 
771         forceMap[ "dy" ]     = 1.0e5;        // dyne
772         forceMap[ "dyn" ]    = 1.0e5;        // dyne
773         forceMap[ "lbf" ]    = 1.0 / 4.448222; // Pound force (see "lbm" for pound mass)
774         forceMap[ "pond" ]   = 1.019716e2;   // pond
775     }
776 
777     QString fromU = fromUnit;
778     QString toU = toUnit;
779     double fromPrefix = kspread_convert_prefix(forceMap, fromU);
780     double toPrefix = kspread_convert_prefix(forceMap, toU);
781     if (fromPrefix == 0.0) return false;
782     if (toPrefix == 0.0) return false;
783     if (!forceMap.contains(fromU)) return false;
784     if (!forceMap.contains(toU)) return false;
785 
786     result = value * fromPrefix * forceMap[toU] / (forceMap[fromU] * toPrefix);
787 
788     return true;
789 }
790 
791 
792 //
793 // convert energies
794 //
kspread_convert_energy(const QString & fromUnit,const QString & toUnit,double value,double & result)795 static bool kspread_convert_energy(const QString& fromUnit,
796                                    const QString& toUnit, double value, double& result)
797 {
798     static QMap<QString, double> energyMap;
799 
800     // first-time initialization
801     if (energyMap.isEmpty()) {
802         energyMap[ "J" ]   = 1.0;                 // Joule (the reference)
803 
804         energyMap[ "e" ]   = 1.0e7;               // erg
805         energyMap[ "c" ]   = 0.239006249473467;   // thermodynamical calorie
806         energyMap[ "cal" ] = 0.238846190642017;   // calorie
807         energyMap[ "eV" ]  = 6.241457e+18;        // electronvolt
808         energyMap[ "HPh" ] = 3.72506111e-7;       // horsepower-hour
809         energyMap[ "Wh" ]  = 0.000277778;         // watt-hour
810         energyMap[ "flb" ] = 23.73042222;
811         energyMap[ "BTU" ] = 9.47815067349015e-4; // British Thermal Unit
812     }
813 
814     QString fromU = fromUnit;
815     QString toU = toUnit;
816     double fromPrefix = kspread_convert_prefix(energyMap, fromU);
817     double toPrefix = kspread_convert_prefix(energyMap, toU);
818     if (fromPrefix == 0.0) return false;
819     if (toPrefix == 0.0) return false;
820     if (!energyMap.contains(fromU)) return false;
821     if (!energyMap.contains(toU)) return false;
822 
823     result = value * fromPrefix * energyMap[toU] / (energyMap[fromU] * toPrefix);
824 
825     return true;
826 }
827 
828 
829 //
830 // convert powers
831 //
kspread_convert_power(const QString & fromUnit,const QString & toUnit,double value,double & result)832 static bool kspread_convert_power(const QString& fromUnit,
833                                   const QString& toUnit, double value, double& result)
834 {
835     static QMap<QString, double> powerMap;
836 
837     // first-time initialization
838     if (powerMap.isEmpty()) {
839         powerMap[ "W" ]   = 1.0; // Watt (the reference)
840 
841 //     powerMap[ "HP" ]  = 1.341022e-3; // Horsepower
842         powerMap[ "HP" ]  = 1.0 / 745.701; // Horsepower (UK)
843         powerMap[ "PS" ]  = 1.359622e-3; // Pferdestaerke (German)
844     }
845 
846     QString fromU = fromUnit;
847     QString toU = toUnit;
848     double fromPrefix = kspread_convert_prefix(powerMap, fromU);
849     double toPrefix = kspread_convert_prefix(powerMap, toU);
850     if (fromPrefix == 0.0) return false;
851     if (toPrefix == 0.0) return false;
852     if (!powerMap.contains(fromU)) return false;
853     if (!powerMap.contains(toU)) return false;
854 
855     result = value * fromPrefix * powerMap[toU] / (powerMap[fromU] * toPrefix);
856 
857     return true;
858 }
859 
860 
861 //
862 // convert magnetism
863 //
kspread_convert_magnetism(const QString & fromUnit,const QString & toUnit,double value,double & result)864 static bool kspread_convert_magnetism(const QString& fromUnit,
865                                       const QString& toUnit, double value, double& result)
866 {
867     static QMap<QString, double> magnetismMap;
868 
869     // first-time initialization
870     if (magnetismMap.isEmpty()) {
871         magnetismMap[ "T" ]   = 1.0;    // Tesla (the reference)
872 
873         magnetismMap[ "ga" ]  = 1.0e4;  // Gauss
874     }
875 
876     QString fromU = fromUnit;
877     QString toU = toUnit;
878     double fromPrefix = kspread_convert_prefix(magnetismMap, fromU);
879     double toPrefix = kspread_convert_prefix(magnetismMap, toU);
880     if (fromPrefix == 0.0) return false;
881     if (toPrefix == 0.0) return false;
882     if (!magnetismMap.contains(fromU)) return false;
883     if (!magnetismMap.contains(toU)) return false;
884 
885     result = value * fromPrefix * magnetismMap[toU] / (magnetismMap[fromU] * toPrefix);
886 
887     return true;
888 }
889 
890 
891 //
892 // convert temperatures
893 //
kspread_convert_temperature(const QString & fromUnit,const QString & toUnit,double value,double & result)894 static bool kspread_convert_temperature(const QString& fromUnit,
895                                         const QString& toUnit, double value, double& result)
896 {
897     static QMap<QString, double> tempFactorMap;
898     static QMap<QString, double> tempOffsetMap;
899 
900     // first-time initialization
901     if (tempFactorMap.isEmpty() || tempOffsetMap.isEmpty()) {
902         tempFactorMap[ "C" ] = 1.0; tempOffsetMap[ "C" ] = 0.0;
903         tempFactorMap[ "F" ] = 5.0 / 9.0; tempOffsetMap[ "F" ] = -32.0;
904         tempFactorMap[ "K" ] = 1.0; tempOffsetMap[ "K" ] = -273.15;
905     }
906 
907     if (!tempFactorMap.contains(fromUnit)) return false;
908     if (!tempOffsetMap.contains(fromUnit)) return false;
909     if (!tempFactorMap.contains(toUnit)) return false;
910     if (!tempOffsetMap.contains(toUnit)) return false;
911 
912     result = (value + tempOffsetMap[ fromUnit ]) * tempFactorMap[ fromUnit ];
913     result = (result / tempFactorMap[ toUnit ]) - tempOffsetMap[ toUnit ];
914 
915     return true;
916 }
917 
918 
919 //
920 // convert volumes
921 //
kspread_convert_volume(const QString & fromUnit,const QString & toUnit,double value,double & result)922 static bool kspread_convert_volume(const QString& fromUnit,
923                                    const QString& toUnit, double value, double& result)
924 {
925     static QMap<QString, double> volumeMap;
926 
927     // first-time initialization
928     if (volumeMap.isEmpty()) {
929         volumeMap[ "l" ]      = 1.0;                    // Liter (the reference)
930 
931 //TODO ang3
932         volumeMap[ "barrel" ] = 6.289811E-03;           // barrel
933 //TODO bushel
934         volumeMap[ "cup" ]    = 4.22583333333333;       // cup
935         volumeMap[ "ft3" ]    = 3.5314666721488590e-2;  // cubic foot
936         volumeMap[ "gal" ]    = 0.26411458333333;       // gallone
937         volumeMap[ "in3" ]    = 6.1023744094732284e1;   // cubic inch
938         volumeMap[ "m3" ]     = 1.0e-3;                 // cubic meter
939         volumeMap[ "mi3" ]    = 2.3991275857892772e-13; // cubic mile
940 //TODO MTON
941         volumeMap[ "Nmi3" ]   = 1.5742621468581148e-13; // cubic Nautical mile
942         volumeMap[ "oz" ]     = 33.8066666666667;       // ounce liquid
943 //TODO Pica3
944         volumeMap[ "pt" ]     = 2.11291666666667;       // pint
945         volumeMap[ "qt" ]     = 1.05645833333333;       // quart
946         volumeMap[ "GRT" ]    = 2831.6846592;           // Gross Register Ton
947         volumeMap[ "regton" ] = volumeMap[ "GRT" ];
948         volumeMap[ "tbs" ]    = 67.6133333333333;       // sheetspoon
949         volumeMap[ "tsp" ]    = 202.84;                 // teaspoon
950 //TODO tspm
951 //TODO uk_pt
952         volumeMap[ "yd3" ]    = 1.3079506193143922;     // cubic yard
953 
954     }
955 
956     QString fromU = fromUnit;
957     QString toU = toUnit;
958     double fromPrefix = kspread_convert_prefix(volumeMap, fromU);
959     double toPrefix = kspread_convert_prefix(volumeMap, toU);
960     if (fromPrefix == 0.0) return false;
961     if (toPrefix == 0.0) return false;
962     if (!volumeMap.contains(fromU)) return false;
963     if (!volumeMap.contains(toU)) return false;
964 
965     result = value * fromPrefix * volumeMap[toU] / (volumeMap[fromU] * toPrefix);
966 
967     return true;
968 }
969 
970 
971 //
972 // convert areas
973 //
kspread_convert_area(const QString & fromUnit,const QString & toUnit,double value,double & result)974 static bool kspread_convert_area(const QString& fromUnit,
975                                  const QString& toUnit, double value, double& result)
976 {
977     static QMap<QString, double> areaMap;
978 
979     // first-time initialization
980     if (areaMap.isEmpty()) {
981         areaMap[ "m2" ]    = 1.0; // square meter (the reference)
982         areaMap[ "m^2" ]   = 1.0; // square meter (the reference)
983 
984         areaMap[ "acre" ]  = 4.046856e3;            // acre
985         areaMap[ "ar" ]    = 1.0 / 100;             // are
986         areaMap[ "ft2" ]   = 1.0763910416709722e1;  // square foot
987         areaMap[ "ft^2" ]  = 1.0763910416709722e1;  // square foot
988         areaMap[ "ha" ]    = 1.0e4;                 // hectare
989         areaMap[ "in2" ]   = 1.5500031000062000e3;  // square inch
990         areaMap[ "in^2" ]  = 1.5500031000062000e3;  // square inch
991         areaMap[ "mi2" ]   = 3.8610215854244585e-7; // square mile
992         areaMap[ "mi^2" ]  = 3.8610215854244585e-7; // square mile
993         areaMap[ "Nmi2" ]  = 2.9155334959812286e-7; // square Nautical mile
994         areaMap[ "Nmi^2" ] = 2.9155334959812286e-7; // square Nautical mile
995         areaMap[ "yd2" ]   = 1.0936132983377078;    // square yard
996         areaMap[ "yd^2" ]  = 1.0936132983377078;    // square yard
997     }
998 
999     QString fromU = fromUnit;
1000     QString toU = toUnit;
1001     double fromPrefix = kspread_convert_prefix(areaMap, fromU);
1002     double toPrefix = kspread_convert_prefix(areaMap, toU);
1003     if (fromPrefix == 0.0) return false;
1004     if (toPrefix == 0.0) return false;
1005     if (!areaMap.contains(fromU)) return false;
1006     if (!areaMap.contains(toU)) return false;
1007 
1008     result = value * fromPrefix * areaMap[toU] / (areaMap[fromU] * toPrefix);
1009 
1010     return true;
1011 }
1012 
1013 
1014 //
1015 // convert speeds
1016 //
kspread_convert_speed(const QString & fromUnit,const QString & toUnit,double value,double & result)1017 static bool kspread_convert_speed(const QString& fromUnit,
1018                                   const QString& toUnit, double value, double& result)
1019 {
1020     static QMap<QString, double> speedMap;
1021 
1022     // first-time initialization
1023     if (speedMap.isEmpty()) {
1024         speedMap[ "m/s" ] = 1.0; // meters per second (the reference)
1025 
1026         speedMap[ "m/h" ] = 3.6e3; // meters per hour
1027         speedMap[ "mph" ] = 2.2369362920544023; // miles per hour
1028         speedMap[ "kn" ]  = 1.9438444924406048; // knot
1029     }
1030 
1031     QString fromU = fromUnit;
1032     QString toU = toUnit;
1033     double fromPrefix = kspread_convert_prefix(speedMap, fromU);
1034     double toPrefix = kspread_convert_prefix(speedMap, toU);
1035     if (fromPrefix == 0.0) return false;
1036     if (toPrefix == 0.0) return false;
1037     if (!speedMap.contains(fromU)) return false;
1038     if (!speedMap.contains(toU)) return false;
1039 
1040     result = value * fromPrefix * speedMap[toU] / (speedMap[fromU] * toPrefix);
1041 
1042     return true;
1043 }
1044 
1045 
1046 //
1047 // convert times
1048 //
kspread_convert_time(const QString & fromUnit,const QString & toUnit,double value,double & result)1049 static bool kspread_convert_time(const QString& fromUnit,
1050                                  const QString& toUnit, double value, double& result)
1051 {
1052     static QMap<QString, double> timeMap;
1053 
1054     // first-time initialization
1055     if (timeMap.isEmpty()) {
1056         timeMap[ "s" ]   = 1.0;                          // second (the reference)
1057         timeMap[ "sec" ] = 1.0;                          // second (the reference)
1058 
1059         timeMap[ "mn" ]  = 1.0 / 60;                     // 24 hour per day
1060         timeMap[ "min" ] = 1.0 / 60;                     // 24 hour per day
1061         timeMap[ "hr" ]  = 1.0 / 3600;                   // 3600 seconds per hour
1062         timeMap[ "d" ]   = 1.0 / (3600 * 24);            // 24 hour per day
1063         timeMap[ "day" ] = 1.0 / (3600 * 24);            // 24 hour per day
1064         timeMap[ "yr" ]  = 1.0 / (3600 * 24 * 365.25);   // 24 hour per day
1065     }
1066 
1067     QString fromU = fromUnit;
1068     QString toU = toUnit;
1069     double fromPrefix = kspread_convert_prefix(timeMap, fromU);
1070     double toPrefix = kspread_convert_prefix(timeMap, toU);
1071     if (fromPrefix == 0.0) return false;
1072     if (toPrefix == 0.0) return false;
1073     if (!timeMap.contains(fromU)) return false;
1074     if (!timeMap.contains(toU)) return false;
1075 
1076     result = value * fromPrefix * timeMap[toU] / (timeMap[fromU] * toPrefix);
1077 
1078     return true;
1079 }
1080 
1081 
1082 //
1083 // convert IT
1084 //
kspread_convert_info(const QString & fromUnit,const QString & toUnit,double value,double & result)1085 static bool kspread_convert_info(const QString& fromUnit,
1086                                  const QString& toUnit, double value, double& result)
1087 {
1088     static QMap<QString, double> infoMap;
1089 
1090     // first-time initialization
1091     if (infoMap.isEmpty()) {
1092         infoMap[ "bit" ]  = 1.0;     // bit (the reference)
1093         infoMap[ "byte" ] = 1.0 / 8; // 8 bit per byte
1094     }
1095 
1096     QString fromU = fromUnit;
1097     QString toU = toUnit;
1098     double fromPrefix = kspread_convert_prefix(infoMap, fromU);
1099     double toPrefix = kspread_convert_prefix(infoMap, toU);
1100     if (fromPrefix == 0.0) return false;
1101     if (toPrefix == 0.0) return false;
1102     if (!infoMap.contains(fromU)) return false;
1103     if (!infoMap.contains(toU)) return false;
1104 
1105     result = value * fromPrefix * infoMap[toU] / (infoMap[fromU] * toPrefix);
1106 
1107     return true;
1108 }
1109 
1110 //
1111 // Function: CONVERT
1112 //
func_convert(valVector args,ValueCalc * calc,FuncExtra *)1113 Value func_convert(valVector args, ValueCalc *calc, FuncExtra *)
1114 {
1115     // This function won't support arbitrary precision.
1116 
1117     double value = numToDouble(calc->conv()->toFloat(args[0]));
1118     QString fromUnit = calc->conv()->toString(args[1]);
1119     QString toUnit = calc->conv()->toString(args[2]);
1120 
1121     double result = value;
1122 
1123     if (!kspread_convert_mass(fromUnit, toUnit, value, result))
1124         if (!kspread_convert_distance(fromUnit, toUnit, value, result))
1125             if (!kspread_convert_pressure(fromUnit, toUnit, value, result))
1126                 if (!kspread_convert_force(fromUnit, toUnit, value, result))
1127                     if (!kspread_convert_energy(fromUnit, toUnit, value, result))
1128                         if (!kspread_convert_power(fromUnit, toUnit, value, result))
1129                             if (!kspread_convert_magnetism(fromUnit, toUnit, value, result))
1130                                 if (!kspread_convert_temperature(fromUnit, toUnit, value, result))
1131                                     if (!kspread_convert_volume(fromUnit, toUnit, value, result))
1132                                         if (!kspread_convert_area(fromUnit, toUnit, value, result))
1133                                             if (!kspread_convert_speed(fromUnit, toUnit, value, result))
1134                                                 if (!kspread_convert_time(fromUnit, toUnit, value, result))
1135                                                     if (!kspread_convert_info(fromUnit, toUnit, value, result))
1136                                                         return Value::errorNA();
1137 
1138     return Value(result);
1139 }
1140 
1141 
1142 // functions operating over complex numbers ...
1143 // these may eventually end up being merged into ValueCalc and friends
1144 // then complex numbers will be handled transparently in most functions
1145 
1146 
1147 //
1148 // Function: COMPLEX
1149 //
func_complex(valVector args,ValueCalc * calc,FuncExtra *)1150 Value func_complex(valVector args, ValueCalc *calc, FuncExtra *)
1151 {
1152     const double real = numToDouble(calc->conv()->toFloat(args[0]));
1153     const double imag = numToDouble(calc->conv()->toFloat(args[1]));
1154     return Value(complex<Number>(real, imag));
1155 }
1156 
1157 
1158 //
1159 // Function: IMAGINARY
1160 //
func_complex_imag(valVector args,ValueCalc * calc,FuncExtra *)1161 Value func_complex_imag(valVector args, ValueCalc *calc, FuncExtra *)
1162 {
1163     return Value(calc->conv()->toComplex(args[0]).imag());
1164 }
1165 
1166 
1167 //
1168 // Function: IMREAL
1169 //
func_complex_real(valVector args,ValueCalc * calc,FuncExtra *)1170 Value func_complex_real(valVector args, ValueCalc *calc, FuncExtra *)
1171 {
1172     return Value(calc->conv()->toComplex(args[0]).real());
1173 }
1174 
1175 
1176 //
1177 //
1178 //
awImSum(ValueCalc * c,Value & res,Value val,Value)1179 void awImSum(ValueCalc *c, Value &res, Value val, Value)
1180 {
1181     const complex<Number> c1 = c->conv()->toComplex(res);
1182     const complex<Number> c2 = c->conv()->toComplex(val);
1183     res = Value(c1 + c2);
1184 }
1185 
1186 
1187 //
1188 //
1189 //
awImSub(ValueCalc * c,Value & res,Value val,Value)1190 void awImSub(ValueCalc *c, Value &res, Value val, Value)
1191 {
1192     const complex<Number> c1 = c->conv()->toComplex(res);
1193     const complex<Number> c2 = c->conv()->toComplex(val);
1194     res = Value(c1 - c2);
1195 }
1196 
1197 
1198 //
1199 //
1200 //
awImMul(ValueCalc * c,Value & res,Value val,Value)1201 void awImMul(ValueCalc *c, Value &res, Value val, Value)
1202 {
1203     const complex<Number> c1 = c->conv()->toComplex(res);
1204     const complex<Number> c2 = c->conv()->toComplex(val);
1205     res = Value(c1 * c2);
1206 }
1207 
1208 
1209 //
1210 //
1211 //
awImDiv(ValueCalc * c,Value & res,Value val,Value)1212 void awImDiv(ValueCalc *c, Value &res, Value val, Value)
1213 {
1214     const complex<Number> c1 = c->conv()->toComplex(res);
1215     const complex<Number> c2 = c->conv()->toComplex(val);
1216     res = Value(c1 / c2);
1217 }
1218 
1219 //
1220 // Function: IMSUM
1221 //
func_imsum(valVector args,ValueCalc * calc,FuncExtra *)1222 Value func_imsum(valVector args, ValueCalc *calc, FuncExtra *)
1223 {
1224     Value result;
1225     calc->arrayWalk(args, result, awImSum, Value(0));
1226     return result;
1227 }
1228 
1229 
1230 //
1231 // Function: IMSUB
1232 //
func_imsub(valVector args,ValueCalc * calc,FuncExtra *)1233 Value func_imsub(valVector args, ValueCalc *calc, FuncExtra *)
1234 {
1235     Value result;
1236     if (args.count() == 1)
1237         awImSub(calc, result, args[0], Value(0));
1238     else {
1239         result = args[0];
1240         valVector vector = args.mid(1);
1241         calc->arrayWalk(vector, result, awImSub, Value(0));
1242     }
1243     return result;
1244 }
1245 
1246 
1247 //
1248 // Function: IMPRODUCT
1249 //
func_improduct(valVector args,ValueCalc * calc,FuncExtra *)1250 Value func_improduct(valVector args, ValueCalc *calc, FuncExtra *)
1251 {
1252     Value result;
1253     if (args.count() == 1) {
1254         result = Value(complex<double>(1.0, 0.0));
1255         awImMul(calc, result, args[0], Value(0));
1256     } else {
1257         result = args[0];
1258         valVector vector = args.mid(1);
1259         calc->arrayWalk(vector, result, awImMul, Value(0));
1260     }
1261     return result;
1262 }
1263 
1264 
1265 //
1266 // Function: IMDIV
1267 //
func_imdiv(valVector args,ValueCalc * calc,FuncExtra *)1268 Value func_imdiv(valVector args, ValueCalc *calc, FuncExtra *)
1269 {
1270     Value result;
1271     if (args.count() == 1) {
1272         result = Value(complex<double>(1.0, 0.0));
1273         awImDiv(calc, result, args[0], Value(0));
1274     } else {
1275         result = args[0];
1276         valVector vector = args.mid(1);
1277         calc->arrayWalk(vector, result, awImDiv, Value(0));
1278     }
1279     return result;
1280 }
1281 
1282 
1283 //
1284 // Function: IMCONJUGATE
1285 //
func_imconjugate(valVector args,ValueCalc * calc,FuncExtra *)1286 Value func_imconjugate(valVector args, ValueCalc *calc, FuncExtra *)
1287 {
1288     return Value(std::conj(calc->conv()->asComplex(args[0]).asComplex()));
1289 }
1290 
1291 
1292 //
1293 // Function: IMARGUMENT
1294 //
func_imargument(valVector args,ValueCalc * calc,FuncExtra *)1295 Value func_imargument(valVector args, ValueCalc *calc, FuncExtra *)
1296 {
1297     return Value(std::arg(calc->conv()->asComplex(args[0]).asComplex()));
1298 }
1299 
1300 
1301 //
1302 // Function: IMABS
1303 //
func_imabs(valVector args,ValueCalc * calc,FuncExtra *)1304 Value func_imabs(valVector args, ValueCalc *calc, FuncExtra *)
1305 {
1306     return Value(std::abs(calc->conv()->asComplex(args[0]).asComplex()));
1307 }
1308 
1309 
1310 //
1311 // Function: IMCOS
1312 //
func_imcos(valVector args,ValueCalc * calc,FuncExtra *)1313 Value func_imcos(valVector args, ValueCalc *calc, FuncExtra *)
1314 {
1315     return Value(std::cos(calc->conv()->asComplex(args[0]).asComplex()));
1316 }
1317 
1318 
1319 //
1320 // Function: IMCOT
1321 //
func_imcot(valVector args,ValueCalc * calc,FuncExtra *)1322 Value func_imcot(valVector args, ValueCalc *calc, FuncExtra*)
1323 {
1324     return Value(std::cos(calc->conv()->asComplex(args[0]).asComplex())
1325                  /std::sin(calc->conv()->asComplex(args[0]).asComplex()));
1326 }
1327 
1328 
1329 //
1330 // Function: IMCSC
1331 //
func_imcsc(valVector args,ValueCalc * calc,FuncExtra *)1332 Value func_imcsc(valVector args, ValueCalc *calc, FuncExtra *)
1333 {
1334     return Value(complex<Number>(1)/std::sin(calc->conv()->asComplex(args[0]).asComplex()));
1335 }
1336 
1337 
1338 //
1339 // Function: IMSEC
1340 //
func_imsec(valVector args,ValueCalc * calc,FuncExtra *)1341 Value func_imsec(valVector args, ValueCalc *calc, FuncExtra *)
1342 {
1343     return Value(complex<Number>(1)/std::cos(calc->conv()->asComplex(args[0]).asComplex()));
1344 }
1345 
1346 
1347 //
1348 // Function: IMSIN
1349 //
func_imsin(valVector args,ValueCalc * calc,FuncExtra *)1350 Value func_imsin(valVector args, ValueCalc *calc, FuncExtra *)
1351 {
1352     return Value(std::sin(calc->conv()->asComplex(args[0]).asComplex()));
1353 }
1354 
1355 
1356 //
1357 // Function: IMTAN
1358 //
func_imtan(valVector args,ValueCalc * calc,FuncExtra *)1359 Value func_imtan(valVector args, ValueCalc *calc, FuncExtra*)
1360 {
1361     return Value(std::tan(calc->conv()->asComplex(args[0]).asComplex()));
1362 }
1363 
1364 
1365 //
1366 // Function: IMCOSH
1367 //
func_imcosh(valVector args,ValueCalc * calc,FuncExtra *)1368 Value func_imcosh(valVector args, ValueCalc *calc, FuncExtra*)
1369 {
1370     return Value(std::cosh(calc->conv()->asComplex(args[0]).asComplex()));
1371 }
1372 
1373 
1374 //
1375 // Function: IMCSCH
1376 //
func_imcsch(valVector args,ValueCalc * calc,FuncExtra *)1377 Value func_imcsch(valVector args, ValueCalc *calc, FuncExtra*)
1378 {
1379     return Value(complex<Number>(1)/std::sinh(calc->conv()->asComplex(args[0]).asComplex()));
1380 }
1381 
1382 
1383 //
1384 // Function: IMSECH
1385 //
func_imsech(valVector args,ValueCalc * calc,FuncExtra *)1386 Value func_imsech(valVector args, ValueCalc *calc, FuncExtra *)
1387 {
1388     return Value(complex<Number>(1)/std::cosh(calc->conv()->asComplex(args[0]).asComplex()));
1389 }
1390 
1391 
1392 //
1393 // Function: IMSINH
1394 //
func_imsinh(valVector args,ValueCalc * calc,FuncExtra *)1395 Value func_imsinh(valVector args, ValueCalc *calc, FuncExtra*)
1396 {
1397     return Value(std::sinh(calc->conv()->asComplex(args[0]).asComplex()));
1398 }
1399 
1400 
1401 //
1402 // Function: IMTANH
1403 //
func_imtanh(valVector args,ValueCalc * calc,FuncExtra *)1404 Value func_imtanh(valVector args, ValueCalc *calc, FuncExtra*)
1405 {
1406     return Value(std::tanh(calc->conv()->asComplex(args[0]).asComplex()));
1407 }
1408 
1409 
1410 //
1411 // Function: IMLN
1412 //
func_imln(valVector args,ValueCalc * calc,FuncExtra *)1413 Value func_imln(valVector args, ValueCalc *calc, FuncExtra *)
1414 {
1415     return Value(std::log(calc->conv()->asComplex(args[0]).asComplex()));
1416 }
1417 
1418 
1419 //
1420 // Function: IMLOG2
1421 //
func_imlog2(valVector args,ValueCalc * calc,FuncExtra *)1422 Value func_imlog2(valVector args, ValueCalc *calc, FuncExtra *)
1423 {
1424     return Value(std::log(calc->conv()->toComplex(args[0])) / static_cast<Number>(double(M_LN2l)));
1425 }
1426 
1427 
1428 //
1429 // Function: IMLOG10
1430 //
func_imlog10(valVector args,ValueCalc * calc,FuncExtra *)1431 Value func_imlog10(valVector args, ValueCalc *calc, FuncExtra *)
1432 {
1433     return Value(std::log10(calc->conv()->toComplex(args[0])));
1434 }
1435 
1436 
1437 //
1438 // Function: IMEXP
1439 //
func_imexp(valVector args,ValueCalc * calc,FuncExtra *)1440 Value func_imexp(valVector args, ValueCalc *calc, FuncExtra *)
1441 {
1442     return Value(std::exp(calc->conv()->toComplex(args[0])));
1443 }
1444 
1445 
1446 //
1447 // Function: IMSQRT
1448 //
func_imsqrt(valVector args,ValueCalc * calc,FuncExtra *)1449 Value func_imsqrt(valVector args, ValueCalc *calc, FuncExtra *)
1450 {
1451     return Value(std::sqrt(calc->conv()->toComplex(args[0])));
1452 }
1453 
1454 
1455 //
1456 // Function: IMPOWER
1457 //
func_impower(valVector args,ValueCalc * calc,FuncExtra *)1458 Value func_impower(valVector args, ValueCalc *calc, FuncExtra *)
1459 {
1460     return Value(std::pow(calc->conv()->toComplex(args[0]),
1461                           calc->conv()->toComplex(args[1])));
1462 }
1463 
1464 
1465 //
1466 // Function: DELTA
1467 //
func_delta(valVector args,ValueCalc * calc,FuncExtra *)1468 Value func_delta(valVector args, ValueCalc *calc, FuncExtra *)
1469 {
1470     Value val1 = args[0];
1471     Value val2 = Value(0.0);
1472     if (args.count() == 2)
1473         val2 = args[1];
1474 
1475     return Value(calc->approxEqual(val1, val2) ? 1 : 0);
1476 }
1477 
1478 
1479 //
1480 // Function: ERF
1481 //
func_erf(valVector args,ValueCalc * calc,FuncExtra *)1482 Value func_erf(valVector args, ValueCalc *calc, FuncExtra *)
1483 {
1484     if (args.count() == 2)
1485         return calc->sub(calc->erf(args[1]), calc->erf(args[0]));
1486     return calc->erf(args[0]);
1487 }
1488 
1489 
1490 //
1491 // Function: ERFC
1492 //
func_erfc(valVector args,ValueCalc * calc,FuncExtra *)1493 Value func_erfc(valVector args, ValueCalc *calc, FuncExtra *)
1494 {
1495     if (args.count() == 2)
1496         return calc->sub(calc->erfc(args[1]), calc->erfc(args[0]));
1497     return calc->erfc(args[0]);
1498 }
1499 
1500 
1501 //
1502 // Function: GESTEP
1503 //
func_gestep(valVector args,ValueCalc * calc,FuncExtra *)1504 Value func_gestep(valVector args, ValueCalc *calc, FuncExtra *)
1505 {
1506     Value x = args[0];
1507     Value y = Value(0.0);
1508     if (args.count() == 2)
1509         y = args[1];
1510 
1511     if (x.isString() || y.isString())
1512         return Value::errorNUM();
1513 
1514     int result = 0;
1515     if (calc->greater(x, y) || calc->approxEqual(x, y))
1516         result = 1;
1517 
1518     return Value(result);
1519 }
1520 
1521 #include "engineering.moc"
1522