ILIAS  eassessment Revision 61809
 All Data Structures Namespaces Files Functions Variables Groups Pages
Calculation.php
Go to the documentation of this file.
1 <?php
30 if (!defined('PHPEXCEL_ROOT')) {
34  define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../');
35  require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
36 }
37 
38 
39 if (!defined('CALCULATION_REGEXP_CELLREF')) {
40  // Test for support of \P (multibyte options) in PCRE
41  if(defined('PREG_BAD_UTF8_ERROR')) {
42  // Cell reference (cell or range of cells, with or without a sheet reference)
43  define('CALCULATION_REGEXP_CELLREF','((([^\s,!&%^\/\*\+<>=-]*)|(\'[^\']*\')|(\"[^\"]*\"))!)?\$?([a-z]{1,3})\$?(\d{1,7})');
44  // Named Range of cells
45  define('CALCULATION_REGEXP_NAMEDRANGE','((([^\s,!&%^\/\*\+<>=-]*)|(\'[^\']*\')|(\"[^\"]*\"))!)?([_A-Z][_A-Z0-9\.]*)');
46  } else {
47  // Cell reference (cell or range of cells, with or without a sheet reference)
48  define('CALCULATION_REGEXP_CELLREF','(((\w*)|(\'[^\']*\')|(\"[^\"]*\"))!)?\$?([a-z]{1,3})\$?(\d+)');
49  // Named Range of cells
50  define('CALCULATION_REGEXP_NAMEDRANGE','(((\w*)|(\'.*\')|(\".*\"))!)?([_A-Z][_A-Z0-9\.]*)');
51  }
52 }
53 
54 
63 
66  // Numeric operand
67  const CALCULATION_REGEXP_NUMBER = '[-+]?\d*\.?\d+(e[-+]?\d+)?';
68  // String operand
69  const CALCULATION_REGEXP_STRING = '"(?:[^"]|"")*"';
70  // Opening bracket
72  // Function (allow for the old @ symbol that could be used to prefix a function, but we'll ignore it)
73  const CALCULATION_REGEXP_FUNCTION = '@?([A-Z][A-Z0-9\.]*)[\s]*\(';
74  // Cell reference (cell or range of cells, with or without a sheet reference)
76  // Named Range of cells
78  // Error
79  const CALCULATION_REGEXP_ERROR = '\#[A-Z][A-Z0_\/]*[!\?]?';
80 
81 
83  const RETURN_ARRAY_AS_ERROR = 'error';
84  const RETURN_ARRAY_AS_VALUE = 'value';
85  const RETURN_ARRAY_AS_ARRAY = 'array';
86 
88 
89 
96  private static $_instance;
97 
98 
105  private static $_calculationCache = array ();
106 
107 
114  private static $_calculationCacheEnabled = true;
115 
116 
123  private static $_calculationCacheExpirationTime = 15;
124 
125 
133  private static $_operators = array('+' => true, '-' => true, '*' => true, '/' => true,
134  '^' => true, '&' => true, '%' => false, '~' => false,
135  '>' => true, '<' => true, '=' => true, '>=' => true,
136  '<=' => true, '<>' => true, '|' => true, ':' => true
137  );
138 
139 
146  private static $_binaryOperators = array('+' => true, '-' => true, '*' => true, '/' => true,
147  '^' => true, '&' => true, '>' => true, '<' => true,
148  '=' => true, '>=' => true, '<=' => true, '<>' => true,
149  '|' => true, ':' => true
150  );
151 
161  public $suppressFormulaErrors = false;
162 
170  public $formulaError = null;
171 
181  public $writeDebugLog = false;
182 
193  public $echoDebugLog = false;
194 
195 
203  private $debugLogStack = array();
204 
212  public $debugLog = array();
213  private $_cyclicFormulaCount = 0;
214  private $_cyclicFormulaCell = '';
216 
217 
218  private $_savedPrecision = 12;
219 
220 
221  private static $_localeLanguage = 'en_us'; // US English (default locale)
222  private static $_validLocaleLanguages = array( 'en' // English (default language)
223  );
224  private static $_localeArgumentSeparator = ',';
225  private static $_localeFunctions = array();
226  public static $_localeBoolean = array( 'TRUE' => 'TRUE',
227  'FALSE' => 'FALSE',
228  'NULL' => 'NULL'
229  );
230 
231 
232  // Constant conversion from text name/value to actual (datatyped) value
233  private static $_ExcelConstants = array('TRUE' => true,
234  'FALSE' => false,
235  'NULL' => null
236  );
237 
238  // PHPExcel functions
239  private static $_PHPExcelFunctions = array( // PHPExcel functions
240  'ABS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
241  'functionCall' => 'abs',
242  'argumentCount' => '1'
243  ),
244  'ACCRINT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
245  'functionCall' => 'PHPExcel_Calculation_Financial::ACCRINT',
246  'argumentCount' => '4-7'
247  ),
248  'ACCRINTM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
249  'functionCall' => 'PHPExcel_Calculation_Financial::ACCRINTM',
250  'argumentCount' => '3-5'
251  ),
252  'ACOS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
253  'functionCall' => 'acos',
254  'argumentCount' => '1'
255  ),
256  'ACOSH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
257  'functionCall' => 'acosh',
258  'argumentCount' => '1'
259  ),
260  'ADDRESS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
261  'functionCall' => 'PHPExcel_Calculation_LookupRef::CELL_ADDRESS',
262  'argumentCount' => '2-5'
263  ),
264  'AMORDEGRC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
265  'functionCall' => 'PHPExcel_Calculation_Financial::AMORDEGRC',
266  'argumentCount' => '6,7'
267  ),
268  'AMORLINC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
269  'functionCall' => 'PHPExcel_Calculation_Financial::AMORLINC',
270  'argumentCount' => '6,7'
271  ),
272  'AND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
273  'functionCall' => 'PHPExcel_Calculation_Logical::LOGICAL_AND',
274  'argumentCount' => '1+'
275  ),
277  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
278  'argumentCount' => '1'
279  ),
280  'ASC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
281  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
282  'argumentCount' => '1'
283  ),
284  'ASIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
285  'functionCall' => 'asin',
286  'argumentCount' => '1'
287  ),
288  'ASINH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
289  'functionCall' => 'asinh',
290  'argumentCount' => '1'
291  ),
292  'ATAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
293  'functionCall' => 'atan',
294  'argumentCount' => '1'
295  ),
296  'ATAN2' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
297  'functionCall' => 'PHPExcel_Calculation_MathTrig::ATAN2',
298  'argumentCount' => '2'
299  ),
300  'ATANH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
301  'functionCall' => 'atanh',
302  'argumentCount' => '1'
303  ),
304  'AVEDEV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
305  'functionCall' => 'PHPExcel_Calculation_Statistical::AVEDEV',
306  'argumentCount' => '1+'
307  ),
308  'AVERAGE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
309  'functionCall' => 'PHPExcel_Calculation_Statistical::AVERAGE',
310  'argumentCount' => '1+'
311  ),
312  'AVERAGEA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
313  'functionCall' => 'PHPExcel_Calculation_Statistical::AVERAGEA',
314  'argumentCount' => '1+'
315  ),
316  'AVERAGEIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
317  'functionCall' => 'PHPExcel_Calculation_Statistical::AVERAGEIF',
318  'argumentCount' => '2,3'
319  ),
320  'AVERAGEIFS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
321  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
322  'argumentCount' => '3+'
323  ),
324  'BAHTTEXT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
325  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
326  'argumentCount' => '1'
327  ),
328  'BESSELI' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
329  'functionCall' => 'PHPExcel_Calculation_Engineering::BESSELI',
330  'argumentCount' => '2'
331  ),
332  'BESSELJ' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
333  'functionCall' => 'PHPExcel_Calculation_Engineering::BESSELJ',
334  'argumentCount' => '2'
335  ),
336  'BESSELK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
337  'functionCall' => 'PHPExcel_Calculation_Engineering::BESSELK',
338  'argumentCount' => '2'
339  ),
340  'BESSELY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
341  'functionCall' => 'PHPExcel_Calculation_Engineering::BESSELY',
342  'argumentCount' => '2'
343  ),
344  'BETADIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
345  'functionCall' => 'PHPExcel_Calculation_Statistical::BETADIST',
346  'argumentCount' => '3-5'
347  ),
348  'BETAINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
349  'functionCall' => 'PHPExcel_Calculation_Statistical::BETAINV',
350  'argumentCount' => '3-5'
351  ),
352  'BIN2DEC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
353  'functionCall' => 'PHPExcel_Calculation_Engineering::BINTODEC',
354  'argumentCount' => '1'
355  ),
356  'BIN2HEX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
357  'functionCall' => 'PHPExcel_Calculation_Engineering::BINTOHEX',
358  'argumentCount' => '1,2'
359  ),
360  'BIN2OCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
361  'functionCall' => 'PHPExcel_Calculation_Engineering::BINTOOCT',
362  'argumentCount' => '1,2'
363  ),
364  'BINOMDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
365  'functionCall' => 'PHPExcel_Calculation_Statistical::BINOMDIST',
366  'argumentCount' => '4'
367  ),
368  'CEILING' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
369  'functionCall' => 'PHPExcel_Calculation_MathTrig::CEILING',
370  'argumentCount' => '2'
371  ),
372  'CELL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
373  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
374  'argumentCount' => '1,2'
375  ),
376  'CHAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
377  'functionCall' => 'PHPExcel_Calculation_TextData::CHARACTER',
378  'argumentCount' => '1'
379  ),
380  'CHIDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
381  'functionCall' => 'PHPExcel_Calculation_Statistical::CHIDIST',
382  'argumentCount' => '2'
383  ),
384  'CHIINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
385  'functionCall' => 'PHPExcel_Calculation_Statistical::CHIINV',
386  'argumentCount' => '2'
387  ),
388  'CHITEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
389  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
390  'argumentCount' => '2'
391  ),
392  'CHOOSE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
393  'functionCall' => 'PHPExcel_Calculation_LookupRef::CHOOSE',
394  'argumentCount' => '2+'
395  ),
396  'CLEAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
397  'functionCall' => 'PHPExcel_Calculation_TextData::TRIMNONPRINTABLE',
398  'argumentCount' => '1'
399  ),
400  'CODE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
401  'functionCall' => 'PHPExcel_Calculation_TextData::ASCIICODE',
402  'argumentCount' => '1'
403  ),
404  'COLUMN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
405  'functionCall' => 'PHPExcel_Calculation_LookupRef::COLUMN',
406  'argumentCount' => '-1',
407  'passByReference' => array(true)
408  ),
409  'COLUMNS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
410  'functionCall' => 'PHPExcel_Calculation_LookupRef::COLUMNS',
411  'argumentCount' => '1'
412  ),
413  'COMBIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
414  'functionCall' => 'PHPExcel_Calculation_MathTrig::COMBIN',
415  'argumentCount' => '2'
416  ),
417  'COMPLEX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
418  'functionCall' => 'PHPExcel_Calculation_Engineering::COMPLEX',
419  'argumentCount' => '2,3'
420  ),
421  'CONCATENATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
422  'functionCall' => 'PHPExcel_Calculation_TextData::CONCATENATE',
423  'argumentCount' => '1+'
424  ),
425  'CONFIDENCE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
426  'functionCall' => 'PHPExcel_Calculation_Statistical::CONFIDENCE',
427  'argumentCount' => '3'
428  ),
429  'CONVERT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
430  'functionCall' => 'PHPExcel_Calculation_Engineering::CONVERTUOM',
431  'argumentCount' => '3'
432  ),
433  'CORREL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
434  'functionCall' => 'PHPExcel_Calculation_Statistical::CORREL',
435  'argumentCount' => '2'
436  ),
437  'COS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
438  'functionCall' => 'cos',
439  'argumentCount' => '1'
440  ),
441  'COSH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
442  'functionCall' => 'cosh',
443  'argumentCount' => '1'
444  ),
445  'COUNT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
446  'functionCall' => 'PHPExcel_Calculation_Statistical::COUNT',
447  'argumentCount' => '1+'
448  ),
449  'COUNTA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
450  'functionCall' => 'PHPExcel_Calculation_Statistical::COUNTA',
451  'argumentCount' => '1+'
452  ),
453  'COUNTBLANK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
454  'functionCall' => 'PHPExcel_Calculation_Statistical::COUNTBLANK',
455  'argumentCount' => '1'
456  ),
457  'COUNTIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
458  'functionCall' => 'PHPExcel_Calculation_Statistical::COUNTIF',
459  'argumentCount' => '2'
460  ),
461  'COUNTIFS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
462  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
463  'argumentCount' => '2'
464  ),
465  'COUPDAYBS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
466  'functionCall' => 'PHPExcel_Calculation_Financial::COUPDAYBS',
467  'argumentCount' => '3,4'
468  ),
469  'COUPDAYS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
470  'functionCall' => 'PHPExcel_Calculation_Financial::COUPDAYS',
471  'argumentCount' => '3,4'
472  ),
473  'COUPDAYSNC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
474  'functionCall' => 'PHPExcel_Calculation_Financial::COUPDAYSNC',
475  'argumentCount' => '3,4'
476  ),
477  'COUPNCD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
478  'functionCall' => 'PHPExcel_Calculation_Financial::COUPNCD',
479  'argumentCount' => '3,4'
480  ),
481  'COUPNUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
482  'functionCall' => 'PHPExcel_Calculation_Financial::COUPNUM',
483  'argumentCount' => '3,4'
484  ),
485  'COUPPCD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
486  'functionCall' => 'PHPExcel_Calculation_Financial::COUPPCD',
487  'argumentCount' => '3,4'
488  ),
489  'COVAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
490  'functionCall' => 'PHPExcel_Calculation_Statistical::COVAR',
491  'argumentCount' => '2'
492  ),
493  'CRITBINOM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
494  'functionCall' => 'PHPExcel_Calculation_Statistical::CRITBINOM',
495  'argumentCount' => '3'
496  ),
497  'CUBEKPIMEMBER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_CUBE,
498  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
499  'argumentCount' => '?'
500  ),
501  'CUBEMEMBER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_CUBE,
502  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
503  'argumentCount' => '?'
504  ),
505  'CUBEMEMBERPROPERTY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_CUBE,
506  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
507  'argumentCount' => '?'
508  ),
509  'CUBERANKEDMEMBER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_CUBE,
510  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
511  'argumentCount' => '?'
512  ),
513  'CUBESET' => array('category' => PHPExcel_Calculation_Function::CATEGORY_CUBE,
514  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
515  'argumentCount' => '?'
516  ),
517  'CUBESETCOUNT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_CUBE,
518  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
519  'argumentCount' => '?'
520  ),
521  'CUBEVALUE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_CUBE,
522  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
523  'argumentCount' => '?'
524  ),
525  'CUMIPMT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
526  'functionCall' => 'PHPExcel_Calculation_Financial::CUMIPMT',
527  'argumentCount' => '6'
528  ),
529  'CUMPRINC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
530  'functionCall' => 'PHPExcel_Calculation_Financial::CUMPRINC',
531  'argumentCount' => '6'
532  ),
533  'DATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
534  'functionCall' => 'PHPExcel_Calculation_DateTime::DATE',
535  'argumentCount' => '3'
536  ),
537  'DATEDIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
538  'functionCall' => 'PHPExcel_Calculation_DateTime::DATEDIF',
539  'argumentCount' => '2,3'
540  ),
541  'DATEVALUE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
542  'functionCall' => 'PHPExcel_Calculation_DateTime::DATEVALUE',
543  'argumentCount' => '1'
544  ),
545  'DAVERAGE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
546  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
547  'argumentCount' => '3'
548  ),
549  'DAY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
550  'functionCall' => 'PHPExcel_Calculation_DateTime::DAYOFMONTH',
551  'argumentCount' => '1'
552  ),
553  'DAYS360' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
554  'functionCall' => 'PHPExcel_Calculation_DateTime::DAYS360',
555  'argumentCount' => '2,3'
556  ),
557  'DB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
558  'functionCall' => 'PHPExcel_Calculation_Financial::DB',
559  'argumentCount' => '4,5'
560  ),
561  'DCOUNT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
562  'functionCall' => 'PHPExcel_Calculation_Database::DCOUNT',
563  'argumentCount' => '3'
564  ),
565  'DCOUNTA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
566  'functionCall' => 'PHPExcel_Calculation_Database::DCOUNTA',
567  'argumentCount' => '3'
568  ),
569  'DDB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
570  'functionCall' => 'PHPExcel_Calculation_Financial::DDB',
571  'argumentCount' => '4,5'
572  ),
573  'DEC2BIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
574  'functionCall' => 'PHPExcel_Calculation_Engineering::DECTOBIN',
575  'argumentCount' => '1,2'
576  ),
577  'DEC2HEX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
578  'functionCall' => 'PHPExcel_Calculation_Engineering::DECTOHEX',
579  'argumentCount' => '1,2'
580  ),
581  'DEC2OCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
582  'functionCall' => 'PHPExcel_Calculation_Engineering::DECTOOCT',
583  'argumentCount' => '1,2'
584  ),
585  'DEGREES' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
586  'functionCall' => 'rad2deg',
587  'argumentCount' => '1'
588  ),
589  'DELTA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
590  'functionCall' => 'PHPExcel_Calculation_Engineering::DELTA',
591  'argumentCount' => '1,2'
592  ),
593  'DEVSQ' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
594  'functionCall' => 'PHPExcel_Calculation_Statistical::DEVSQ',
595  'argumentCount' => '1+'
596  ),
597  'DGET' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
598  'functionCall' => 'PHPExcel_Calculation_Database::DGET',
599  'argumentCount' => '3'
600  ),
601  'DISC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
602  'functionCall' => 'PHPExcel_Calculation_Financial::DISC',
603  'argumentCount' => '4,5'
604  ),
605  'DMAX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
606  'functionCall' => 'PHPExcel_Calculation_Database::DMAX',
607  'argumentCount' => '3'
608  ),
609  'DMIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
610  'functionCall' => 'PHPExcel_Calculation_Database::DMIN',
611  'argumentCount' => '3'
612  ),
613  'DOLLAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
614  'functionCall' => 'PHPExcel_Calculation_TextData::DOLLAR',
615  'argumentCount' => '1,2'
616  ),
617  'DOLLARDE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
618  'functionCall' => 'PHPExcel_Calculation_Financial::DOLLARDE',
619  'argumentCount' => '2'
620  ),
621  'DOLLARFR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
622  'functionCall' => 'PHPExcel_Calculation_Financial::DOLLARFR',
623  'argumentCount' => '2'
624  ),
625  'DPRODUCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
626  'functionCall' => 'PHPExcel_Calculation_Database::DPRODUCT',
627  'argumentCount' => '3'
628  ),
629  'DSTDEV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
630  'functionCall' => 'PHPExcel_Calculation_Database::DSTDEV',
631  'argumentCount' => '3'
632  ),
633  'DSTDEVP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
634  'functionCall' => 'PHPExcel_Calculation_Database::DSTDEVP',
635  'argumentCount' => '3'
636  ),
637  'DSUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
638  'functionCall' => 'PHPExcel_Calculation_Database::DSUM',
639  'argumentCount' => '3'
640  ),
641  'DURATION' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
642  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
643  'argumentCount' => '5,6'
644  ),
645  'DVAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
646  'functionCall' => 'PHPExcel_Calculation_Database::DVAR',
647  'argumentCount' => '3'
648  ),
649  'DVARP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
650  'functionCall' => 'PHPExcel_Calculation_Database::DVARP',
651  'argumentCount' => '3'
652  ),
653  'EDATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
654  'functionCall' => 'PHPExcel_Calculation_DateTime::EDATE',
655  'argumentCount' => '2'
656  ),
657  'EFFECT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
658  'functionCall' => 'PHPExcel_Calculation_Financial::EFFECT',
659  'argumentCount' => '2'
660  ),
661  'EOMONTH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
662  'functionCall' => 'PHPExcel_Calculation_DateTime::EOMONTH',
663  'argumentCount' => '2'
664  ),
665  'ERF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
666  'functionCall' => 'PHPExcel_Calculation_Engineering::ERF',
667  'argumentCount' => '1,2'
668  ),
669  'ERFC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
670  'functionCall' => 'PHPExcel_Calculation_Engineering::ERFC',
671  'argumentCount' => '1'
672  ),
673  'ERROR.TYPE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
674  'functionCall' => 'PHPExcel_Calculation_Functions::ERROR_TYPE',
675  'argumentCount' => '1'
676  ),
677  'EVEN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
678  'functionCall' => 'PHPExcel_Calculation_MathTrig::EVEN',
679  'argumentCount' => '1'
680  ),
681  'EXACT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
682  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
683  'argumentCount' => '2'
684  ),
685  'EXP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
686  'functionCall' => 'exp',
687  'argumentCount' => '1'
688  ),
689  'EXPONDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
690  'functionCall' => 'PHPExcel_Calculation_Statistical::EXPONDIST',
691  'argumentCount' => '3'
692  ),
693  'FACT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
694  'functionCall' => 'PHPExcel_Calculation_MathTrig::FACT',
695  'argumentCount' => '1'
696  ),
697  'FACTDOUBLE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
698  'functionCall' => 'PHPExcel_Calculation_MathTrig::FACTDOUBLE',
699  'argumentCount' => '1'
700  ),
701  'FALSE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
702  'functionCall' => 'PHPExcel_Calculation_Logical::FALSE',
703  'argumentCount' => '0'
704  ),
705  'FDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
706  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
707  'argumentCount' => '3'
708  ),
709  'FIND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
710  'functionCall' => 'PHPExcel_Calculation_TextData::SEARCHSENSITIVE',
711  'argumentCount' => '2,3'
712  ),
713  'FINDB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
714  'functionCall' => 'PHPExcel_Calculation_TextData::SEARCHSENSITIVE',
715  'argumentCount' => '2,3'
716  ),
717  'FINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
718  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
719  'argumentCount' => '3'
720  ),
721  'FISHER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
722  'functionCall' => 'PHPExcel_Calculation_Statistical::FISHER',
723  'argumentCount' => '1'
724  ),
725  'FISHERINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
726  'functionCall' => 'PHPExcel_Calculation_Statistical::FISHERINV',
727  'argumentCount' => '1'
728  ),
729  'FIXED' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
730  'functionCall' => 'PHPExcel_Calculation_TextData::FIXEDFORMAT',
731  'argumentCount' => '1-3'
732  ),
733  'FLOOR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
734  'functionCall' => 'PHPExcel_Calculation_MathTrig::FLOOR',
735  'argumentCount' => '2'
736  ),
737  'FORECAST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
738  'functionCall' => 'PHPExcel_Calculation_Statistical::FORECAST',
739  'argumentCount' => '3'
740  ),
741  'FREQUENCY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
742  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
743  'argumentCount' => '2'
744  ),
745  'FTEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
746  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
747  'argumentCount' => '2'
748  ),
749  'FV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
750  'functionCall' => 'PHPExcel_Calculation_Financial::FV',
751  'argumentCount' => '3-5'
752  ),
753  'FVSCHEDULE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
754  'functionCall' => 'PHPExcel_Calculation_Financial::FVSCHEDULE',
755  'argumentCount' => '2'
756  ),
757  'GAMMADIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
758  'functionCall' => 'PHPExcel_Calculation_Statistical::GAMMADIST',
759  'argumentCount' => '4'
760  ),
761  'GAMMAINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
762  'functionCall' => 'PHPExcel_Calculation_Statistical::GAMMAINV',
763  'argumentCount' => '3'
764  ),
765  'GAMMALN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
766  'functionCall' => 'PHPExcel_Calculation_Statistical::GAMMALN',
767  'argumentCount' => '1'
768  ),
769  'GCD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
770  'functionCall' => 'PHPExcel_Calculation_MathTrig::GCD',
771  'argumentCount' => '1+'
772  ),
773  'GEOMEAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
774  'functionCall' => 'PHPExcel_Calculation_Statistical::GEOMEAN',
775  'argumentCount' => '1+'
776  ),
777  'GESTEP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
778  'functionCall' => 'PHPExcel_Calculation_Engineering::GESTEP',
779  'argumentCount' => '1,2'
780  ),
781  'GETPIVOTDATA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
782  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
783  'argumentCount' => '2+'
784  ),
785  'GROWTH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
786  'functionCall' => 'PHPExcel_Calculation_Statistical::GROWTH',
787  'argumentCount' => '1-4'
788  ),
789  'HARMEAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
790  'functionCall' => 'PHPExcel_Calculation_Statistical::HARMEAN',
791  'argumentCount' => '1+'
792  ),
793  'HEX2BIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
794  'functionCall' => 'PHPExcel_Calculation_Engineering::HEXTOBIN',
795  'argumentCount' => '1,2'
796  ),
797  'HEX2DEC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
798  'functionCall' => 'PHPExcel_Calculation_Engineering::HEXTODEC',
799  'argumentCount' => '1'
800  ),
801  'HEX2OCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
802  'functionCall' => 'PHPExcel_Calculation_Engineering::HEXTOOCT',
803  'argumentCount' => '1,2'
804  ),
805  'HLOOKUP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
806  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
807  'argumentCount' => '3,4'
808  ),
809  'HOUR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
810  'functionCall' => 'PHPExcel_Calculation_DateTime::HOUROFDAY',
811  'argumentCount' => '1'
812  ),
813  'HYPERLINK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
814  'functionCall' => 'PHPExcel_Calculation_LookupRef::HYPERLINK',
815  'argumentCount' => '1,2',
816  'passCellReference'=> true
817  ),
818  'HYPGEOMDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
819  'functionCall' => 'PHPExcel_Calculation_Statistical::HYPGEOMDIST',
820  'argumentCount' => '4'
821  ),
822  'IF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
823  'functionCall' => 'PHPExcel_Calculation_Logical::STATEMENT_IF',
824  'argumentCount' => '1-3'
825  ),
826  'IFERROR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
827  'functionCall' => 'PHPExcel_Calculation_Logical::IFERROR',
828  'argumentCount' => '2'
829  ),
830  'IMABS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
831  'functionCall' => 'PHPExcel_Calculation_Engineering::IMABS',
832  'argumentCount' => '1'
833  ),
834  'IMAGINARY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
835  'functionCall' => 'PHPExcel_Calculation_Engineering::IMAGINARY',
836  'argumentCount' => '1'
837  ),
838  'IMARGUMENT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
839  'functionCall' => 'PHPExcel_Calculation_Engineering::IMARGUMENT',
840  'argumentCount' => '1'
841  ),
842  'IMCONJUGATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
843  'functionCall' => 'PHPExcel_Calculation_Engineering::IMCONJUGATE',
844  'argumentCount' => '1'
845  ),
846  'IMCOS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
847  'functionCall' => 'PHPExcel_Calculation_Engineering::IMCOS',
848  'argumentCount' => '1'
849  ),
850  'IMDIV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
851  'functionCall' => 'PHPExcel_Calculation_Engineering::IMDIV',
852  'argumentCount' => '2'
853  ),
854  'IMEXP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
855  'functionCall' => 'PHPExcel_Calculation_Engineering::IMEXP',
856  'argumentCount' => '1'
857  ),
858  'IMLN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
859  'functionCall' => 'PHPExcel_Calculation_Engineering::IMLN',
860  'argumentCount' => '1'
861  ),
862  'IMLOG10' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
863  'functionCall' => 'PHPExcel_Calculation_Engineering::IMLOG10',
864  'argumentCount' => '1'
865  ),
866  'IMLOG2' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
867  'functionCall' => 'PHPExcel_Calculation_Engineering::IMLOG2',
868  'argumentCount' => '1'
869  ),
870  'IMPOWER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
871  'functionCall' => 'PHPExcel_Calculation_Engineering::IMPOWER',
872  'argumentCount' => '2'
873  ),
874  'IMPRODUCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
875  'functionCall' => 'PHPExcel_Calculation_Engineering::IMPRODUCT',
876  'argumentCount' => '1+'
877  ),
878  'IMREAL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
879  'functionCall' => 'PHPExcel_Calculation_Engineering::IMREAL',
880  'argumentCount' => '1'
881  ),
882  'IMSIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
883  'functionCall' => 'PHPExcel_Calculation_Engineering::IMSIN',
884  'argumentCount' => '1'
885  ),
886  'IMSQRT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
887  'functionCall' => 'PHPExcel_Calculation_Engineering::IMSQRT',
888  'argumentCount' => '1'
889  ),
890  'IMSUB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
891  'functionCall' => 'PHPExcel_Calculation_Engineering::IMSUB',
892  'argumentCount' => '2'
893  ),
894  'IMSUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
895  'functionCall' => 'PHPExcel_Calculation_Engineering::IMSUM',
896  'argumentCount' => '1+'
897  ),
899  'functionCall' => 'PHPExcel_Calculation_LookupRef::INDEX',
900  'argumentCount' => '1-4'
901  ),
902  'INDIRECT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
903  'functionCall' => 'PHPExcel_Calculation_LookupRef::INDIRECT',
904  'argumentCount' => '1,2',
905  'passCellReference'=> true
906  ),
907  'INFO' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
908  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
909  'argumentCount' => '1'
910  ),
911  'INT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
912  'functionCall' => 'PHPExcel_Calculation_MathTrig::INT',
913  'argumentCount' => '1'
914  ),
915  'INTERCEPT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
916  'functionCall' => 'PHPExcel_Calculation_Statistical::INTERCEPT',
917  'argumentCount' => '2'
918  ),
919  'INTRATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
920  'functionCall' => 'PHPExcel_Calculation_Financial::INTRATE',
921  'argumentCount' => '4,5'
922  ),
923  'IPMT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
924  'functionCall' => 'PHPExcel_Calculation_Financial::IPMT',
925  'argumentCount' => '4-6'
926  ),
927  'IRR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
928  'functionCall' => 'PHPExcel_Calculation_Financial::IRR',
929  'argumentCount' => '1,2'
930  ),
931  'ISBLANK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
932  'functionCall' => 'PHPExcel_Calculation_Functions::IS_BLANK',
933  'argumentCount' => '1'
934  ),
935  'ISERR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
936  'functionCall' => 'PHPExcel_Calculation_Functions::IS_ERR',
937  'argumentCount' => '1'
938  ),
939  'ISERROR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
940  'functionCall' => 'PHPExcel_Calculation_Functions::IS_ERROR',
941  'argumentCount' => '1'
942  ),
943  'ISEVEN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
944  'functionCall' => 'PHPExcel_Calculation_Functions::IS_EVEN',
945  'argumentCount' => '1'
946  ),
947  'ISLOGICAL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
948  'functionCall' => 'PHPExcel_Calculation_Functions::IS_LOGICAL',
949  'argumentCount' => '1'
950  ),
951  'ISNA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
952  'functionCall' => 'PHPExcel_Calculation_Functions::IS_NA',
953  'argumentCount' => '1'
954  ),
955  'ISNONTEXT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
956  'functionCall' => 'PHPExcel_Calculation_Functions::IS_NONTEXT',
957  'argumentCount' => '1'
958  ),
959  'ISNUMBER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
960  'functionCall' => 'PHPExcel_Calculation_Functions::IS_NUMBER',
961  'argumentCount' => '1'
962  ),
963  'ISODD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
964  'functionCall' => 'PHPExcel_Calculation_Functions::IS_ODD',
965  'argumentCount' => '1'
966  ),
967  'ISPMT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
968  'functionCall' => 'PHPExcel_Calculation_Financial::ISPMT',
969  'argumentCount' => '4'
970  ),
971  'ISREF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
972  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
973  'argumentCount' => '1'
974  ),
975  'ISTEXT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
976  'functionCall' => 'PHPExcel_Calculation_Functions::IS_TEXT',
977  'argumentCount' => '1'
978  ),
979  'JIS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
980  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
981  'argumentCount' => '1'
982  ),
983  'KURT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
984  'functionCall' => 'PHPExcel_Calculation_Statistical::KURT',
985  'argumentCount' => '1+'
986  ),
987  'LARGE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
988  'functionCall' => 'PHPExcel_Calculation_Statistical::LARGE',
989  'argumentCount' => '2'
990  ),
991  'LCM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
992  'functionCall' => 'PHPExcel_Calculation_MathTrig::LCM',
993  'argumentCount' => '1+'
994  ),
995  'LEFT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
996  'functionCall' => 'PHPExcel_Calculation_TextData::LEFT',
997  'argumentCount' => '1,2'
998  ),
999  'LEFTB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1000  'functionCall' => 'PHPExcel_Calculation_TextData::LEFT',
1001  'argumentCount' => '1,2'
1002  ),
1003  'LEN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1004  'functionCall' => 'PHPExcel_Calculation_TextData::STRINGLENGTH',
1005  'argumentCount' => '1'
1006  ),
1007  'LENB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1008  'functionCall' => 'PHPExcel_Calculation_TextData::STRINGLENGTH',
1009  'argumentCount' => '1'
1010  ),
1011  'LINEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1012  'functionCall' => 'PHPExcel_Calculation_Statistical::LINEST',
1013  'argumentCount' => '1-4'
1014  ),
1015  'LN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1016  'functionCall' => 'log',
1017  'argumentCount' => '1'
1018  ),
1019  'LOG' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1020  'functionCall' => 'PHPExcel_Calculation_MathTrig::LOG_BASE',
1021  'argumentCount' => '1,2'
1022  ),
1023  'LOG10' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1024  'functionCall' => 'log10',
1025  'argumentCount' => '1'
1026  ),
1027  'LOGEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1028  'functionCall' => 'PHPExcel_Calculation_Statistical::LOGEST',
1029  'argumentCount' => '1-4'
1030  ),
1031  'LOGINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1032  'functionCall' => 'PHPExcel_Calculation_Statistical::LOGINV',
1033  'argumentCount' => '3'
1034  ),
1035  'LOGNORMDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1036  'functionCall' => 'PHPExcel_Calculation_Statistical::LOGNORMDIST',
1037  'argumentCount' => '3'
1038  ),
1039  'LOOKUP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
1040  'functionCall' => 'PHPExcel_Calculation_LookupRef::LOOKUP',
1041  'argumentCount' => '2,3'
1042  ),
1043  'LOWER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1044  'functionCall' => 'PHPExcel_Calculation_TextData::LOWERCASE',
1045  'argumentCount' => '1'
1046  ),
1047  'MATCH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
1048  'functionCall' => 'PHPExcel_Calculation_LookupRef::MATCH',
1049  'argumentCount' => '2,3'
1050  ),
1051  'MAX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1052  'functionCall' => 'PHPExcel_Calculation_Statistical::MAX',
1053  'argumentCount' => '1+'
1054  ),
1055  'MAXA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1056  'functionCall' => 'PHPExcel_Calculation_Statistical::MAXA',
1057  'argumentCount' => '1+'
1058  ),
1059  'MAXIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1060  'functionCall' => 'PHPExcel_Calculation_Statistical::MAXIF',
1061  'argumentCount' => '2+'
1062  ),
1063  'MDETERM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1064  'functionCall' => 'PHPExcel_Calculation_MathTrig::MDETERM',
1065  'argumentCount' => '1'
1066  ),
1067  'MDURATION' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1068  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1069  'argumentCount' => '5,6'
1070  ),
1071  'MEDIAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1072  'functionCall' => 'PHPExcel_Calculation_Statistical::MEDIAN',
1073  'argumentCount' => '1+'
1074  ),
1075  'MEDIANIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1076  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1077  'argumentCount' => '2+'
1078  ),
1079  'MID' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1080  'functionCall' => 'PHPExcel_Calculation_TextData::MID',
1081  'argumentCount' => '3'
1082  ),
1083  'MIDB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1084  'functionCall' => 'PHPExcel_Calculation_TextData::MID',
1085  'argumentCount' => '3'
1086  ),
1087  'MIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1088  'functionCall' => 'PHPExcel_Calculation_Statistical::MIN',
1089  'argumentCount' => '1+'
1090  ),
1091  'MINA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1092  'functionCall' => 'PHPExcel_Calculation_Statistical::MINA',
1093  'argumentCount' => '1+'
1094  ),
1095  'MINIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1096  'functionCall' => 'PHPExcel_Calculation_Statistical::MINIF',
1097  'argumentCount' => '2+'
1098  ),
1099  'MINUTE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1100  'functionCall' => 'PHPExcel_Calculation_DateTime::MINUTEOFHOUR',
1101  'argumentCount' => '1'
1102  ),
1103  'MINVERSE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1104  'functionCall' => 'PHPExcel_Calculation_MathTrig::MINVERSE',
1105  'argumentCount' => '1'
1106  ),
1107  'MIRR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1108  'functionCall' => 'PHPExcel_Calculation_Financial::MIRR',
1109  'argumentCount' => '3'
1110  ),
1111  'MMULT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1112  'functionCall' => 'PHPExcel_Calculation_MathTrig::MMULT',
1113  'argumentCount' => '2'
1114  ),
1115  'MOD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1116  'functionCall' => 'PHPExcel_Calculation_MathTrig::MOD',
1117  'argumentCount' => '2'
1118  ),
1119  'MODE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1120  'functionCall' => 'PHPExcel_Calculation_Statistical::MODE',
1121  'argumentCount' => '1+'
1122  ),
1123  'MONTH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1124  'functionCall' => 'PHPExcel_Calculation_DateTime::MONTHOFYEAR',
1125  'argumentCount' => '1'
1126  ),
1127  'MROUND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1128  'functionCall' => 'PHPExcel_Calculation_MathTrig::MROUND',
1129  'argumentCount' => '2'
1130  ),
1131  'MULTINOMIAL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1132  'functionCall' => 'PHPExcel_Calculation_MathTrig::MULTINOMIAL',
1133  'argumentCount' => '1+'
1134  ),
1135  'N' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
1136  'functionCall' => 'PHPExcel_Calculation_Functions::N',
1137  'argumentCount' => '1'
1138  ),
1139  'NA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
1140  'functionCall' => 'PHPExcel_Calculation_Functions::NA',
1141  'argumentCount' => '0'
1142  ),
1143  'NEGBINOMDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1144  'functionCall' => 'PHPExcel_Calculation_Statistical::NEGBINOMDIST',
1145  'argumentCount' => '3'
1146  ),
1147  'NETWORKDAYS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1148  'functionCall' => 'PHPExcel_Calculation_DateTime::NETWORKDAYS',
1149  'argumentCount' => '2+'
1150  ),
1151  'NOMINAL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1152  'functionCall' => 'PHPExcel_Calculation_Financial::NOMINAL',
1153  'argumentCount' => '2'
1154  ),
1155  'NORMDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1156  'functionCall' => 'PHPExcel_Calculation_Statistical::NORMDIST',
1157  'argumentCount' => '4'
1158  ),
1159  'NORMINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1160  'functionCall' => 'PHPExcel_Calculation_Statistical::NORMINV',
1161  'argumentCount' => '3'
1162  ),
1163  'NORMSDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1164  'functionCall' => 'PHPExcel_Calculation_Statistical::NORMSDIST',
1165  'argumentCount' => '1'
1166  ),
1167  'NORMSINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1168  'functionCall' => 'PHPExcel_Calculation_Statistical::NORMSINV',
1169  'argumentCount' => '1'
1170  ),
1171  'NOT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
1172  'functionCall' => 'PHPExcel_Calculation_Logical::NOT',
1173  'argumentCount' => '1'
1174  ),
1175  'NOW' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1176  'functionCall' => 'PHPExcel_Calculation_DateTime::DATETIMENOW',
1177  'argumentCount' => '0'
1178  ),
1179  'NPER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1180  'functionCall' => 'PHPExcel_Calculation_Financial::NPER',
1181  'argumentCount' => '3-5'
1182  ),
1183  'NPV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1184  'functionCall' => 'PHPExcel_Calculation_Financial::NPV',
1185  'argumentCount' => '2+'
1186  ),
1187  'OCT2BIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
1188  'functionCall' => 'PHPExcel_Calculation_Engineering::OCTTOBIN',
1189  'argumentCount' => '1,2'
1190  ),
1191  'OCT2DEC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
1192  'functionCall' => 'PHPExcel_Calculation_Engineering::OCTTODEC',
1193  'argumentCount' => '1'
1194  ),
1195  'OCT2HEX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
1196  'functionCall' => 'PHPExcel_Calculation_Engineering::OCTTOHEX',
1197  'argumentCount' => '1,2'
1198  ),
1199  'ODD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1200  'functionCall' => 'PHPExcel_Calculation_MathTrig::ODD',
1201  'argumentCount' => '1'
1202  ),
1203  'ODDFPRICE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1204  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1205  'argumentCount' => '8,9'
1206  ),
1207  'ODDFYIELD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1208  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1209  'argumentCount' => '8,9'
1210  ),
1211  'ODDLPRICE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1212  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1213  'argumentCount' => '7,8'
1214  ),
1215  'ODDLYIELD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1216  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1217  'argumentCount' => '7,8'
1218  ),
1219  'OFFSET' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
1220  'functionCall' => 'PHPExcel_Calculation_LookupRef::OFFSET',
1221  'argumentCount' => '3,5',
1222  'passCellReference'=> true,
1223  'passByReference' => array(true)
1224  ),
1225  'OR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
1226  'functionCall' => 'PHPExcel_Calculation_Logical::LOGICAL_OR',
1227  'argumentCount' => '1+'
1228  ),
1229  'PEARSON' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1230  'functionCall' => 'PHPExcel_Calculation_Statistical::CORREL',
1231  'argumentCount' => '2'
1232  ),
1233  'PERCENTILE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1234  'functionCall' => 'PHPExcel_Calculation_Statistical::PERCENTILE',
1235  'argumentCount' => '2'
1236  ),
1237  'PERCENTRANK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1238  'functionCall' => 'PHPExcel_Calculation_Statistical::PERCENTRANK',
1239  'argumentCount' => '2,3'
1240  ),
1241  'PERMUT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1242  'functionCall' => 'PHPExcel_Calculation_Statistical::PERMUT',
1243  'argumentCount' => '2'
1244  ),
1245  'PHONETIC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1246  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1247  'argumentCount' => '1'
1248  ),
1249  'PI' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1250  'functionCall' => 'pi',
1251  'argumentCount' => '0'
1252  ),
1253  'PMT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1254  'functionCall' => 'PHPExcel_Calculation_Financial::PMT',
1255  'argumentCount' => '3-5'
1256  ),
1257  'POISSON' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1258  'functionCall' => 'PHPExcel_Calculation_Statistical::POISSON',
1259  'argumentCount' => '3'
1260  ),
1261  'POWER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1262  'functionCall' => 'PHPExcel_Calculation_MathTrig::POWER',
1263  'argumentCount' => '2'
1264  ),
1265  'PPMT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1266  'functionCall' => 'PHPExcel_Calculation_Financial::PPMT',
1267  'argumentCount' => '4-6'
1268  ),
1269  'PRICE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1270  'functionCall' => 'PHPExcel_Calculation_Financial::PRICE',
1271  'argumentCount' => '6,7'
1272  ),
1273  'PRICEDISC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1274  'functionCall' => 'PHPExcel_Calculation_Financial::PRICEDISC',
1275  'argumentCount' => '4,5'
1276  ),
1277  'PRICEMAT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1278  'functionCall' => 'PHPExcel_Calculation_Financial::PRICEMAT',
1279  'argumentCount' => '5,6'
1280  ),
1281  'PROB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1282  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1283  'argumentCount' => '3,4'
1284  ),
1285  'PRODUCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1286  'functionCall' => 'PHPExcel_Calculation_MathTrig::PRODUCT',
1287  'argumentCount' => '1+'
1288  ),
1289  'PROPER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1290  'functionCall' => 'PHPExcel_Calculation_TextData::PROPERCASE',
1291  'argumentCount' => '1'
1292  ),
1293  'PV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1294  'functionCall' => 'PHPExcel_Calculation_Financial::PV',
1295  'argumentCount' => '3-5'
1296  ),
1297  'QUARTILE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1298  'functionCall' => 'PHPExcel_Calculation_Statistical::QUARTILE',
1299  'argumentCount' => '2'
1300  ),
1301  'QUOTIENT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1302  'functionCall' => 'PHPExcel_Calculation_MathTrig::QUOTIENT',
1303  'argumentCount' => '2'
1304  ),
1305  'RADIANS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1306  'functionCall' => 'deg2rad',
1307  'argumentCount' => '1'
1308  ),
1309  'RAND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1310  'functionCall' => 'PHPExcel_Calculation_MathTrig::RAND',
1311  'argumentCount' => '0'
1312  ),
1313  'RANDBETWEEN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1314  'functionCall' => 'PHPExcel_Calculation_MathTrig::RAND',
1315  'argumentCount' => '2'
1316  ),
1317  'RANK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1318  'functionCall' => 'PHPExcel_Calculation_Statistical::RANK',
1319  'argumentCount' => '2,3'
1320  ),
1321  'RATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1322  'functionCall' => 'PHPExcel_Calculation_Financial::RATE',
1323  'argumentCount' => '3-6'
1324  ),
1325  'RECEIVED' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1326  'functionCall' => 'PHPExcel_Calculation_Financial::RECEIVED',
1327  'argumentCount' => '4-5'
1328  ),
1329  'REPLACE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1330  'functionCall' => 'PHPExcel_Calculation_TextData::REPLACE',
1331  'argumentCount' => '4'
1332  ),
1333  'REPLACEB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1334  'functionCall' => 'PHPExcel_Calculation_TextData::REPLACE',
1335  'argumentCount' => '4'
1336  ),
1337  'REPT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1338  'functionCall' => 'str_repeat',
1339  'argumentCount' => '2'
1340  ),
1341  'RIGHT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1342  'functionCall' => 'PHPExcel_Calculation_TextData::RIGHT',
1343  'argumentCount' => '1,2'
1344  ),
1345  'RIGHTB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1346  'functionCall' => 'PHPExcel_Calculation_TextData::RIGHT',
1347  'argumentCount' => '1,2'
1348  ),
1349  'ROMAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1350  'functionCall' => 'PHPExcel_Calculation_MathTrig::ROMAN',
1351  'argumentCount' => '1,2'
1352  ),
1353  'ROUND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1354  'functionCall' => 'round',
1355  'argumentCount' => '2'
1356  ),
1357  'ROUNDDOWN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1358  'functionCall' => 'PHPExcel_Calculation_MathTrig::ROUNDDOWN',
1359  'argumentCount' => '2'
1360  ),
1361  'ROUNDUP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1362  'functionCall' => 'PHPExcel_Calculation_MathTrig::ROUNDUP',
1363  'argumentCount' => '2'
1364  ),
1366  'functionCall' => 'PHPExcel_Calculation_LookupRef::ROW',
1367  'argumentCount' => '-1',
1368  'passByReference' => array(true)
1369  ),
1371  'functionCall' => 'PHPExcel_Calculation_LookupRef::ROWS',
1372  'argumentCount' => '1'
1373  ),
1374  'RSQ' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1375  'functionCall' => 'PHPExcel_Calculation_Statistical::RSQ',
1376  'argumentCount' => '2'
1377  ),
1379  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1380  'argumentCount' => '1+'
1381  ),
1382  'SEARCH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1383  'functionCall' => 'PHPExcel_Calculation_TextData::SEARCHINSENSITIVE',
1384  'argumentCount' => '2,3'
1385  ),
1386  'SEARCHB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1387  'functionCall' => 'PHPExcel_Calculation_TextData::SEARCHINSENSITIVE',
1388  'argumentCount' => '2,3'
1389  ),
1390  'SECOND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1391  'functionCall' => 'PHPExcel_Calculation_DateTime::SECONDOFMINUTE',
1392  'argumentCount' => '1'
1393  ),
1394  'SERIESSUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1395  'functionCall' => 'PHPExcel_Calculation_MathTrig::SERIESSUM',
1396  'argumentCount' => '4'
1397  ),
1398  'SIGN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1399  'functionCall' => 'PHPExcel_Calculation_MathTrig::SIGN',
1400  'argumentCount' => '1'
1401  ),
1402  'SIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1403  'functionCall' => 'sin',
1404  'argumentCount' => '1'
1405  ),
1406  'SINH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1407  'functionCall' => 'sinh',
1408  'argumentCount' => '1'
1409  ),
1410  'SKEW' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1411  'functionCall' => 'PHPExcel_Calculation_Statistical::SKEW',
1412  'argumentCount' => '1+'
1413  ),
1414  'SLN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1415  'functionCall' => 'PHPExcel_Calculation_Financial::SLN',
1416  'argumentCount' => '3'
1417  ),
1418  'SLOPE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1419  'functionCall' => 'PHPExcel_Calculation_Statistical::SLOPE',
1420  'argumentCount' => '2'
1421  ),
1422  'SMALL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1423  'functionCall' => 'PHPExcel_Calculation_Statistical::SMALL',
1424  'argumentCount' => '2'
1425  ),
1426  'SQRT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1427  'functionCall' => 'sqrt',
1428  'argumentCount' => '1'
1429  ),
1430  'SQRTPI' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1431  'functionCall' => 'PHPExcel_Calculation_MathTrig::SQRTPI',
1432  'argumentCount' => '1'
1433  ),
1434  'STANDARDIZE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1435  'functionCall' => 'PHPExcel_Calculation_Statistical::STANDARDIZE',
1436  'argumentCount' => '3'
1437  ),
1438  'STDEV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1439  'functionCall' => 'PHPExcel_Calculation_Statistical::STDEV',
1440  'argumentCount' => '1+'
1441  ),
1442  'STDEVA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1443  'functionCall' => 'PHPExcel_Calculation_Statistical::STDEVA',
1444  'argumentCount' => '1+'
1445  ),
1446  'STDEVP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1447  'functionCall' => 'PHPExcel_Calculation_Statistical::STDEVP',
1448  'argumentCount' => '1+'
1449  ),
1450  'STDEVPA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1451  'functionCall' => 'PHPExcel_Calculation_Statistical::STDEVPA',
1452  'argumentCount' => '1+'
1453  ),
1454  'STEYX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1455  'functionCall' => 'PHPExcel_Calculation_Statistical::STEYX',
1456  'argumentCount' => '2'
1457  ),
1458  'SUBSTITUTE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1459  'functionCall' => 'PHPExcel_Calculation_TextData::SUBSTITUTE',
1460  'argumentCount' => '3,4'
1461  ),
1462  'SUBTOTAL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1463  'functionCall' => 'PHPExcel_Calculation_MathTrig::SUBTOTAL',
1464  'argumentCount' => '2+'
1465  ),
1466  'SUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1467  'functionCall' => 'PHPExcel_Calculation_MathTrig::SUM',
1468  'argumentCount' => '1+'
1469  ),
1470  'SUMIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1471  'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMIF',
1472  'argumentCount' => '2,3'
1473  ),
1474  'SUMIFS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1475  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1476  'argumentCount' => '?'
1477  ),
1478  'SUMPRODUCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1479  'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMPRODUCT',
1480  'argumentCount' => '1+'
1481  ),
1482  'SUMSQ' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1483  'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMSQ',
1484  'argumentCount' => '1+'
1485  ),
1486  'SUMX2MY2' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1487  'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMX2MY2',
1488  'argumentCount' => '2'
1489  ),
1490  'SUMX2PY2' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1491  'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMX2PY2',
1492  'argumentCount' => '2'
1493  ),
1494  'SUMXMY2' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1495  'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMXMY2',
1496  'argumentCount' => '2'
1497  ),
1498  'SYD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1499  'functionCall' => 'PHPExcel_Calculation_Financial::SYD',
1500  'argumentCount' => '4'
1501  ),
1502  'T' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1503  'functionCall' => 'PHPExcel_Calculation_TextData::RETURNSTRING',
1504  'argumentCount' => '1'
1505  ),
1506  'TAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1507  'functionCall' => 'tan',
1508  'argumentCount' => '1'
1509  ),
1510  'TANH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1511  'functionCall' => 'tanh',
1512  'argumentCount' => '1'
1513  ),
1514  'TBILLEQ' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1515  'functionCall' => 'PHPExcel_Calculation_Financial::TBILLEQ',
1516  'argumentCount' => '3'
1517  ),
1518  'TBILLPRICE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1519  'functionCall' => 'PHPExcel_Calculation_Financial::TBILLPRICE',
1520  'argumentCount' => '3'
1521  ),
1522  'TBILLYIELD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1523  'functionCall' => 'PHPExcel_Calculation_Financial::TBILLYIELD',
1524  'argumentCount' => '3'
1525  ),
1526  'TDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1527  'functionCall' => 'PHPExcel_Calculation_Statistical::TDIST',
1528  'argumentCount' => '3'
1529  ),
1530  'TEXT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1531  'functionCall' => 'PHPExcel_Calculation_TextData::TEXTFORMAT',
1532  'argumentCount' => '2'
1533  ),
1534  'TIME' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1535  'functionCall' => 'PHPExcel_Calculation_DateTime::TIME',
1536  'argumentCount' => '3'
1537  ),
1538  'TIMEVALUE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1539  'functionCall' => 'PHPExcel_Calculation_DateTime::TIMEVALUE',
1540  'argumentCount' => '1'
1541  ),
1542  'TINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1543  'functionCall' => 'PHPExcel_Calculation_Statistical::TINV',
1544  'argumentCount' => '2'
1545  ),
1546  'TODAY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1547  'functionCall' => 'PHPExcel_Calculation_DateTime::DATENOW',
1548  'argumentCount' => '0'
1549  ),
1550  'TRANSPOSE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
1551  'functionCall' => 'PHPExcel_Calculation_LookupRef::TRANSPOSE',
1552  'argumentCount' => '1'
1553  ),
1554  'TREND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1555  'functionCall' => 'PHPExcel_Calculation_Statistical::TREND',
1556  'argumentCount' => '1-4'
1557  ),
1558  'TRIM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1559  'functionCall' => 'PHPExcel_Calculation_TextData::TRIMSPACES',
1560  'argumentCount' => '1'
1561  ),
1562  'TRIMMEAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1563  'functionCall' => 'PHPExcel_Calculation_Statistical::TRIMMEAN',
1564  'argumentCount' => '2'
1565  ),
1566  'TRUE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
1567  'functionCall' => 'PHPExcel_Calculation_Logical::TRUE',
1568  'argumentCount' => '0'
1569  ),
1570  'TRUNC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1571  'functionCall' => 'PHPExcel_Calculation_MathTrig::TRUNC',
1572  'argumentCount' => '1,2'
1573  ),
1574  'TTEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1575  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1576  'argumentCount' => '4'
1577  ),
1578  'TYPE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
1579  'functionCall' => 'PHPExcel_Calculation_Functions::TYPE',
1580  'argumentCount' => '1'
1581  ),
1582  'UPPER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1583  'functionCall' => 'PHPExcel_Calculation_TextData::UPPERCASE',
1584  'argumentCount' => '1'
1585  ),
1586  'USDOLLAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1587  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1588  'argumentCount' => '2'
1589  ),
1590  'VALUE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1591  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1592  'argumentCount' => '1'
1593  ),
1594  'VAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1595  'functionCall' => 'PHPExcel_Calculation_Statistical::VARFunc',
1596  'argumentCount' => '1+'
1597  ),
1598  'VARA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1599  'functionCall' => 'PHPExcel_Calculation_Statistical::VARA',
1600  'argumentCount' => '1+'
1601  ),
1602  'VARP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1603  'functionCall' => 'PHPExcel_Calculation_Statistical::VARP',
1604  'argumentCount' => '1+'
1605  ),
1606  'VARPA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1607  'functionCall' => 'PHPExcel_Calculation_Statistical::VARPA',
1608  'argumentCount' => '1+'
1609  ),
1610  'VDB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1611  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1612  'argumentCount' => '5-7'
1613  ),
1614  'VERSION' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
1615  'functionCall' => 'PHPExcel_Calculation_Functions::VERSION',
1616  'argumentCount' => '0'
1617  ),
1618  'VLOOKUP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
1619  'functionCall' => 'PHPExcel_Calculation_LookupRef::VLOOKUP',
1620  'argumentCount' => '3,4'
1621  ),
1622  'WEEKDAY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1623  'functionCall' => 'PHPExcel_Calculation_DateTime::DAYOFWEEK',
1624  'argumentCount' => '1,2'
1625  ),
1626  'WEEKNUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1627  'functionCall' => 'PHPExcel_Calculation_DateTime::WEEKOFYEAR',
1628  'argumentCount' => '1,2'
1629  ),
1630  'WEIBULL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1631  'functionCall' => 'PHPExcel_Calculation_Statistical::WEIBULL',
1632  'argumentCount' => '4'
1633  ),
1634  'WORKDAY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1635  'functionCall' => 'PHPExcel_Calculation_DateTime::WORKDAY',
1636  'argumentCount' => '2+'
1637  ),
1638  'XIRR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1639  'functionCall' => 'PHPExcel_Calculation_Financial::XIRR',
1640  'argumentCount' => '2,3'
1641  ),
1642  'XNPV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1643  'functionCall' => 'PHPExcel_Calculation_Financial::XNPV',
1644  'argumentCount' => '3'
1645  ),
1646  'YEAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1647  'functionCall' => 'PHPExcel_Calculation_DateTime::YEAR',
1648  'argumentCount' => '1'
1649  ),
1650  'YEARFRAC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1651  'functionCall' => 'PHPExcel_Calculation_DateTime::YEARFRAC',
1652  'argumentCount' => '2,3'
1653  ),
1654  'YIELD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1655  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1656  'argumentCount' => '6,7'
1657  ),
1658  'YIELDDISC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1659  'functionCall' => 'PHPExcel_Calculation_Financial::YIELDDISC',
1660  'argumentCount' => '4,5'
1661  ),
1662  'YIELDMAT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1663  'functionCall' => 'PHPExcel_Calculation_Financial::YIELDMAT',
1664  'argumentCount' => '5,6'
1665  ),
1666  'ZTEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1667  'functionCall' => 'PHPExcel_Calculation_Statistical::ZTEST',
1668  'argumentCount' => '2-3'
1669  )
1670  );
1671 
1672 
1673  // Internal functions used for special control purposes
1674  private static $_controlFunctions = array(
1675  'MKMATRIX' => array('argumentCount' => '*',
1676  'functionCall' => 'self::_mkMatrix'
1677  )
1678  );
1679 
1680 
1681 
1682 
1683  private function __construct() {
1684  $localeFileDirectory = PHPEXCEL_ROOT.'PHPExcel/locale/';
1685  foreach (glob($localeFileDirectory.'/*',GLOB_ONLYDIR) as $filename) {
1686  $filename = substr($filename,strlen($localeFileDirectory)+1);
1687  if ($filename != 'en') {
1688  self::$_validLocaleLanguages[] = $filename;
1689  }
1690  }
1691 
1692  $setPrecision = (PHP_INT_SIZE == 4) ? 12 : 16;
1693  $this->_savedPrecision = ini_get('precision');
1694  if ($this->_savedPrecision < $setPrecision) {
1695  ini_set('precision',$setPrecision);
1696  }
1697  } // function __construct()
1698 
1699 
1700  public function __destruct() {
1701  ini_set('precision',$this->_savedPrecision);
1702  }
1703 
1710  public static function getInstance() {
1711  if (!isset(self::$_instance) || is_null(self::$_instance)) {
1712  self::$_instance = new PHPExcel_Calculation();
1713  }
1714 
1715  return self::$_instance;
1716  } // function getInstance()
1717 
1718 
1726  public static function flushInstance() {
1727  if (isset(self::$_instance) && !is_null(self::$_instance)) {
1728  self::$_instance->clearCalculationCache();
1729  }
1730  } // function flushInstance()
1731 
1732 
1739  public final function __clone() {
1740  throw new Exception ('Cloning a Singleton is not allowed!');
1741  } // function __clone()
1742 
1743 
1750  public static function getTRUE() {
1751  return self::$_localeBoolean['TRUE'];
1752  }
1753 
1760  public static function getFALSE() {
1761  return self::$_localeBoolean['FALSE'];
1762  }
1763 
1771  public static function setArrayReturnType($returnType) {
1772  if (($returnType == self::RETURN_ARRAY_AS_VALUE) ||
1773  ($returnType == self::RETURN_ARRAY_AS_ERROR) ||
1774  ($returnType == self::RETURN_ARRAY_AS_ARRAY)) {
1775  self::$returnArrayAsType = $returnType;
1776  return true;
1777  }
1778  return false;
1779  } // function setExcelCalendar()
1780 
1781 
1788  public static function getArrayReturnType() {
1789  return self::$returnArrayAsType;
1790  } // function getExcelCalendar()
1791 
1792 
1799  public function getCalculationCacheEnabled() {
1801  } // function getCalculationCacheEnabled()
1802 
1803 
1810  public function setCalculationCacheEnabled($pValue = true) {
1811  self::$_calculationCacheEnabled = $pValue;
1812  $this->clearCalculationCache();
1813  } // function setCalculationCacheEnabled()
1814 
1815 
1819  public function enableCalculationCache() {
1820  $this->setCalculationCacheEnabled(true);
1821  } // function enableCalculationCache()
1822 
1823 
1827  public function disableCalculationCache() {
1828  $this->setCalculationCacheEnabled(false);
1829  } // function disableCalculationCache()
1830 
1831 
1835  public function clearCalculationCache() {
1836  self::$_calculationCache = array();
1837  } // function clearCalculationCache()
1838 
1839 
1847  } // getCalculationCacheExpirationTime()
1848 
1849 
1855  public function setCalculationCacheExpirationTime($pValue = 15) {
1856  self::$_calculationCacheExpirationTime = $pValue;
1857  } // function setCalculationCacheExpirationTime()
1858 
1859 
1860 
1861 
1867  public function getLocale() {
1868  return self::$_localeLanguage;
1869  } // function getLocale()
1870 
1871 
1877  public function setLocale($locale='en_us') {
1878  // Identify our locale and language
1879  $language = $locale = strtolower($locale);
1880  if (strpos($locale,'_') !== false) {
1881  list($language) = explode('_',$locale);
1882  }
1883 
1884  // Test whether we have any language data for this language (any locale)
1885  if (in_array($language,self::$_validLocaleLanguages)) {
1886  // initialise language/locale settings
1887  self::$_localeFunctions = array();
1888  self::$_localeArgumentSeparator = ',';
1889  self::$_localeBoolean = array('TRUE' => 'TRUE', 'FALSE' => 'FALSE', 'NULL' => 'NULL');
1890  // Default is English, if user isn't requesting english, then read the necessary data from the locale files
1891  if ($locale != 'en_us') {
1892  // Search for a file with a list of function names for locale
1893  $functionNamesFile = PHPEXCEL_ROOT . 'PHPExcel/locale/'.str_replace('_','/',$locale).'/functions';
1894  if (!file_exists($functionNamesFile)) {
1895  // If there isn't a locale specific function file, look for a language specific function file
1896  $functionNamesFile = PHPEXCEL_ROOT . 'PHPExcel/locale/'.$language.'/functions';
1897  if (!file_exists($functionNamesFile)) {
1898  return false;
1899  }
1900  }
1901  // Retrieve the list of locale or language specific function names
1902  $localeFunctions = file($functionNamesFile,FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
1903  foreach ($localeFunctions as $localeFunction) {
1904  list($localeFunction) = explode('##',$localeFunction); // Strip out comments
1905  if (strpos($localeFunction,'=') !== false) {
1906  list($fName,$lfName) = explode('=',$localeFunction);
1907  $fName = trim($fName);
1908  $lfName = trim($lfName);
1909  if ((isset(self::$_PHPExcelFunctions[$fName])) && ($lfName != '') && ($fName != $lfName)) {
1910  self::$_localeFunctions[$fName] = $lfName;
1911  }
1912  }
1913  }
1914  // Default the TRUE and FALSE constants to the locale names of the TRUE() and FALSE() functions
1915  if (isset(self::$_localeFunctions['TRUE'])) { self::$_localeBoolean['TRUE'] = self::$_localeFunctions['TRUE']; }
1916  if (isset(self::$_localeFunctions['FALSE'])) { self::$_localeBoolean['FALSE'] = self::$_localeFunctions['FALSE']; }
1917 
1918  $configFile = PHPEXCEL_ROOT . 'PHPExcel/locale/'.str_replace('_','/',$locale).'/config';
1919  if (!file_exists($configFile)) {
1920  $configFile = PHPEXCEL_ROOT . 'PHPExcel/locale/'.$language.'/config';
1921  }
1922  if (file_exists($configFile)) {
1923  $localeSettings = file($configFile,FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
1924  foreach ($localeSettings as $localeSetting) {
1925  list($localeSetting) = explode('##',$localeSetting); // Strip out comments
1926  if (strpos($localeSetting,'=') !== false) {
1927  list($settingName,$settingValue) = explode('=',$localeSetting);
1928  $settingName = strtoupper(trim($settingName));
1929  switch ($settingName) {
1930  case 'ARGUMENTSEPARATOR' :
1931  self::$_localeArgumentSeparator = trim($settingValue);
1932  break;
1933  }
1934  }
1935  }
1936  }
1937  }
1938 
1939  self::$functionReplaceFromExcel = self::$functionReplaceToExcel =
1940  self::$functionReplaceFromLocale = self::$functionReplaceToLocale = null;
1941  self::$_localeLanguage = $locale;
1942  return true;
1943  }
1944  return false;
1945  } // function setLocale()
1946 
1947 
1948 
1949  public static function _translateSeparator($fromSeparator,$toSeparator,$formula,&$inBraces) {
1950  $strlen = mb_strlen($formula);
1951  for ($i = 0; $i < $strlen; ++$i) {
1952  $chr = mb_substr($formula,$i,1);
1953  switch ($chr) {
1954  case '{' : $inBraces = true;
1955  break;
1956  case '}' : $inBraces = false;
1957  break;
1958  case $fromSeparator :
1959  if (!$inBraces) {
1960  $formula = mb_substr($formula,0,$i).$toSeparator.mb_substr($formula,$i+1);
1961  }
1962  }
1963  }
1964  return $formula;
1965  }
1966 
1967  private static function _translateFormula($from,$to,$formula,$fromSeparator,$toSeparator) {
1968  // Convert any Excel function names to the required language
1969  if (self::$_localeLanguage !== 'en_us') {
1970  $inBraces = false;
1971  // If there is the possibility of braces within a quoted string, then we don't treat those as matrix indicators
1972  if (strpos($formula,'"') !== false) {
1973  // So instead we skip replacing in any quoted strings by only replacing in every other array element after we've exploded
1974  // the formula
1975  $temp = explode('"',$formula);
1976  $i = false;
1977  foreach($temp as &$value) {
1978  // Only count/replace in alternating array entries
1979  if ($i = !$i) {
1980  $value = preg_replace($from,$to,$value);
1981  $value = self::_translateSeparator($fromSeparator,$toSeparator,$value,$inBraces);
1982  }
1983  }
1984  unset($value);
1985  // Then rebuild the formula string
1986  $formula = implode('"',$temp);
1987  } else {
1988  // If there's no quoted strings, then we do a simple count/replace
1989  $formula = preg_replace($from,$to,$formula);
1990  $formula = self::_translateSeparator($fromSeparator,$toSeparator,$formula,$inBraces);
1991  }
1992  }
1993 
1994  return $formula;
1995  }
1996 
1997  private static $functionReplaceFromExcel = null;
1998  private static $functionReplaceToLocale = null;
1999 
2000  public function _translateFormulaToLocale($formula) {
2001  if (is_null(self::$functionReplaceFromExcel)) {
2002  self::$functionReplaceFromExcel = array();
2003  foreach(array_keys(self::$_localeFunctions) as $excelFunctionName) {
2004  self::$functionReplaceFromExcel[] = '/(@?[^\w\.])'.preg_quote($excelFunctionName).'([\s]*\()/Ui';
2005  }
2006  foreach(array_keys(self::$_localeBoolean) as $excelBoolean) {
2007  self::$functionReplaceFromExcel[] = '/(@?[^\w\.])'.preg_quote($excelBoolean).'([^\w\.])/Ui';
2008  }
2009 
2010  }
2011 
2012  if (is_null(self::$functionReplaceToLocale)) {
2013  self::$functionReplaceToLocale = array();
2014  foreach(array_values(self::$_localeFunctions) as $localeFunctionName) {
2015  self::$functionReplaceToLocale[] = '$1'.trim($localeFunctionName).'$2';
2016  }
2017  foreach(array_values(self::$_localeBoolean) as $localeBoolean) {
2018  self::$functionReplaceToLocale[] = '$1'.trim($localeBoolean).'$2';
2019  }
2020  }
2021 
2022  return self::_translateFormula(self::$functionReplaceFromExcel,self::$functionReplaceToLocale,$formula,',',self::$_localeArgumentSeparator);
2023  } // function _translateFormulaToLocale()
2024 
2025 
2026  private static $functionReplaceFromLocale = null;
2027  private static $functionReplaceToExcel = null;
2028 
2029  public function _translateFormulaToEnglish($formula) {
2030  if (is_null(self::$functionReplaceFromLocale)) {
2031  self::$functionReplaceFromLocale = array();
2032  foreach(array_values(self::$_localeFunctions) as $localeFunctionName) {
2033  self::$functionReplaceFromLocale[] = '/(@?[^\w\.])'.preg_quote($localeFunctionName).'([\s]*\()/Ui';
2034  }
2035  foreach(array_values(self::$_localeBoolean) as $excelBoolean) {
2036  self::$functionReplaceFromLocale[] = '/(@?[^\w\.])'.preg_quote($excelBoolean).'([^\w\.])/Ui';
2037  }
2038  }
2039 
2040  if (is_null(self::$functionReplaceToExcel)) {
2041  self::$functionReplaceToExcel = array();
2042  foreach(array_keys(self::$_localeFunctions) as $excelFunctionName) {
2043  self::$functionReplaceToExcel[] = '$1'.trim($excelFunctionName).'$2';
2044  }
2045  foreach(array_keys(self::$_localeBoolean) as $excelBoolean) {
2046  self::$functionReplaceToExcel[] = '$1'.trim($excelBoolean).'$2';
2047  }
2048  }
2049 
2050  return self::_translateFormula(self::$functionReplaceFromLocale,self::$functionReplaceToExcel,$formula,self::$_localeArgumentSeparator,',');
2051  } // function _translateFormulaToEnglish()
2052 
2053 
2054  public static function _localeFunc($function) {
2055  if (self::$_localeLanguage !== 'en_us') {
2056  $functionName = trim($function,'(');
2057  if (isset(self::$_localeFunctions[$functionName])) {
2058  $brace = ($functionName != $function);
2059  $function = self::$_localeFunctions[$functionName];
2060  if ($brace) { $function .= '('; }
2061  }
2062  }
2063  return $function;
2064  }
2065 
2066 
2067 
2068 
2075  public static function _wrapResult($value) {
2076  if (is_string($value)) {
2077  // Error values cannot be "wrapped"
2078  if (preg_match('/^'.self::CALCULATION_REGEXP_ERROR.'$/i', $value, $match)) {
2079  // Return Excel errors "as is"
2080  return $value;
2081  }
2082  // Return strings wrapped in quotes
2083  return '"'.$value.'"';
2084  // Convert numeric errors to NaN error
2085  } else if((is_float($value)) && ((is_nan($value)) || (is_infinite($value)))) {
2087  }
2088 
2089  return $value;
2090  } // function _wrapResult()
2091 
2092 
2099  public static function _unwrapResult($value) {
2100  if (is_string($value)) {
2101  if ((isset($value{0})) && ($value{0} == '"') && (substr($value,-1) == '"')) {
2102  return substr($value,1,-1);
2103  }
2104  // Convert numeric errors to NaN error
2105  } else if((is_float($value)) && ((is_nan($value)) || (is_infinite($value)))) {
2107  }
2108  return $value;
2109  } // function _unwrapResult()
2110 
2111 
2112 
2113 
2123  public function calculate(PHPExcel_Cell $pCell = null) {
2124  try {
2125  return $this->calculateCellValue($pCell);
2126  } catch (Exception $e) {
2127  throw(new Exception($e->getMessage()));
2128  }
2129  } // function calculate()
2130 
2131 
2141  public function calculateCellValue(PHPExcel_Cell $pCell = null, $resetLog = true) {
2142  if ($resetLog) {
2143  // Initialise the logging settings if requested
2144  $this->formulaError = null;
2145  $this->debugLog = $this->debugLogStack = array();
2146  $this->_cyclicFormulaCount = 1;
2147 
2149  self::$returnArrayAsType = self::RETURN_ARRAY_AS_ARRAY;
2150  }
2151 
2152  // Read the formula from the cell
2153  if (is_null($pCell)) {
2154  return null;
2155  }
2156 
2157  if ($resetLog) {
2158  self::$returnArrayAsType = $returnArrayAsType;
2159  }
2160  // Execute the calculation for the cell formula
2161  try {
2162  $result = self::_unwrapResult($this->_calculateFormulaValue($pCell->getValue(), $pCell->getCoordinate(), $pCell));
2163  } catch (Exception $e) {
2164  throw(new Exception($e->getMessage()));
2165  }
2166 
2167  if ((is_array($result)) && (self::$returnArrayAsType != self::RETURN_ARRAY_AS_ARRAY)) {
2168  $testResult = PHPExcel_Calculation_Functions::flattenArray($result);
2169  if (self::$returnArrayAsType == self::RETURN_ARRAY_AS_ERROR) {
2171  }
2172  // If there's only a single cell in the array, then we allow it
2173  if (count($testResult) != 1) {
2174  // If keys are numeric, then it's a matrix result rather than a cell range result, so we permit it
2175  $r = array_keys($result);
2176  $r = array_shift($r);
2177  if (!is_numeric($r)) { return PHPExcel_Calculation_Functions::VALUE(); }
2178  if (is_array($result[$r])) {
2179  $c = array_keys($result[$r]);
2180  $c = array_shift($c);
2181  if (!is_numeric($c)) {
2183  }
2184  }
2185  }
2186  $result = array_shift($testResult);
2187  }
2188 
2189  if (is_null($result)) {
2190  return 0;
2191  } elseif((is_float($result)) && ((is_nan($result)) || (is_infinite($result)))) {
2193  }
2194  return $result;
2195  } // function calculateCellValue(
2196 
2197 
2205  public function parseFormula($formula) {
2206  // Basic validation that this is indeed a formula
2207  // We return an empty array if not
2208  $formula = trim($formula);
2209  if ((!isset($formula{0})) || ($formula{0} != '=')) return array();
2210  $formula = ltrim(substr($formula,1));
2211  if (!isset($formula{0})) return array();
2212 
2213  // Parse the formula and return the token stack
2214  return $this->_parseFormula($formula);
2215  } // function parseFormula()
2216 
2217 
2225  public function calculateFormula($formula, $cellID=null, PHPExcel_Cell $pCell = null) {
2226  // Initialise the logging settings
2227  $this->formulaError = null;
2228  $this->debugLog = $this->debugLogStack = array();
2229 
2230  // Disable calculation cacheing because it only applies to cell calculations, not straight formulae
2231  // But don't actually flush any cache
2232  $resetCache = $this->getCalculationCacheEnabled();
2233  self::$_calculationCacheEnabled = false;
2234  // Execute the calculation
2235  try {
2236  $result = self::_unwrapResult($this->_calculateFormulaValue($formula, $cellID, $pCell));
2237  } catch (Exception $e) {
2238  throw(new Exception($e->getMessage()));
2239  }
2240 
2241  // Reset calculation cacheing to its previous state
2242  self::$_calculationCacheEnabled = $resetCache;
2243 
2244  return $result;
2245  } // function calculateFormula()
2246 
2247 
2257  public function _calculateFormulaValue($formula, $cellID=null, PHPExcel_Cell $pCell = null) {
2258 // echo '<b>'.$cellID.'</b><br />';
2259  $cellValue = '';
2260 
2261  // Basic validation that this is indeed a formula
2262  // We simply return the "cell value" (formula) if not
2263  $formula = trim($formula);
2264  if ($formula{0} != '=') return self::_wrapResult($formula);
2265  $formula = ltrim(substr($formula,1));
2266  if (!isset($formula{0})) return self::_wrapResult($formula);
2267 
2268  $wsTitle = "\x00Wrk";
2269  if (!is_null($pCell)) {
2270  $pCellParent = $pCell->getParent();
2271  if (!is_null($pCellParent)) {
2272  $wsTitle = $pCellParent->getTitle();
2273  }
2274  }
2275  // Is calculation cacheing enabled?
2276  if (!is_null($cellID)) {
2277  if (self::$_calculationCacheEnabled) {
2278  // Is the value present in calculation cache?
2279 // echo 'Testing cache value<br />';
2280  if (isset(self::$_calculationCache[$wsTitle][$cellID])) {
2281 // echo 'Value is in cache<br />';
2282  $this->_writeDebug('Testing cache value for cell '.$cellID);
2283  // Is cache still valid?
2284  if ((microtime(true) - self::$_calculationCache[$wsTitle][$cellID]['time']) < self::$_calculationCacheExpirationTime) {
2285 // echo 'Cache time is still valid<br />';
2286  $this->_writeDebug('Retrieving value for '.$cellID.' from cache');
2287  // Return the cached result
2288  $returnValue = self::$_calculationCache[$wsTitle][$cellID]['data'];
2289 // echo 'Retrieving data value of '.$returnValue.' for '.$cellID.' from cache<br />';
2290  if (is_array($returnValue)) {
2291  $returnValue = PHPExcel_Calculation_Functions::flattenArray($returnValue);
2292  return array_shift($returnValue);
2293  }
2294  return $returnValue;
2295  } else {
2296 // echo 'Cache has expired<br />';
2297  $this->_writeDebug('Cache value for '.$cellID.' has expired');
2298  // Clear the cache if it's no longer valid
2299  unset(self::$_calculationCache[$wsTitle][$cellID]);
2300  }
2301  }
2302  }
2303  }
2304 
2305  if ((in_array($wsTitle.'!'.$cellID,$this->debugLogStack)) && ($wsTitle != "\x00Wrk")) {
2306  if ($this->cyclicFormulaCount <= 0) {
2307  return $this->_raiseFormulaError('Cyclic Reference in Formula');
2308  } elseif (($this->_cyclicFormulaCount >= $this->cyclicFormulaCount) &&
2309  ($this->_cyclicFormulaCell == $wsTitle.'!'.$cellID)) {
2310  return $cellValue;
2311  } elseif ($this->_cyclicFormulaCell == $wsTitle.'!'.$cellID) {
2313  if ($this->_cyclicFormulaCount >= $this->cyclicFormulaCount) {
2314  return $cellValue;
2315  }
2316  } elseif ($this->_cyclicFormulaCell == '') {
2317  $this->_cyclicFormulaCell = $wsTitle.'!'.$cellID;
2318  if ($this->_cyclicFormulaCount >= $this->cyclicFormulaCount) {
2319  return $cellValue;
2320  }
2321  }
2322  }
2323  $this->debugLogStack[] = $wsTitle.'!'.$cellID;
2324  // Parse the formula onto the token stack and calculate the value
2325  $cellValue = $this->_processTokenStack($this->_parseFormula($formula, $pCell), $cellID, $pCell);
2326  array_pop($this->debugLogStack);
2327 
2328  // Save to calculation cache
2329  if (!is_null($cellID)) {
2330  if (self::$_calculationCacheEnabled) {
2331  self::$_calculationCache[$wsTitle][$cellID]['time'] = microtime(true);
2332  self::$_calculationCache[$wsTitle][$cellID]['data'] = $cellValue;
2333  }
2334  }
2335 
2336  // Return the calculated value
2337  return $cellValue;
2338  } // function _calculateFormulaValue()
2339 
2340 
2353  private static function _checkMatrixOperands(&$operand1,&$operand2,$resize = 1) {
2354  // Examine each of the two operands, and turn them into an array if they aren't one already
2355  // Note that this function should only be called if one or both of the operand is already an array
2356  if (!is_array($operand1)) {
2357  list($matrixRows,$matrixColumns) = self::_getMatrixDimensions($operand2);
2358  $operand1 = array_fill(0,$matrixRows,array_fill(0,$matrixColumns,$operand1));
2359  $resize = 0;
2360  } elseif (!is_array($operand2)) {
2361  list($matrixRows,$matrixColumns) = self::_getMatrixDimensions($operand1);
2362  $operand2 = array_fill(0,$matrixRows,array_fill(0,$matrixColumns,$operand2));
2363  $resize = 0;
2364  }
2365 
2366  list($matrix1Rows,$matrix1Columns) = self::_getMatrixDimensions($operand1);
2367  list($matrix2Rows,$matrix2Columns) = self::_getMatrixDimensions($operand2);
2368  if (($matrix1Rows == $matrix2Columns) && ($matrix2Rows == $matrix1Columns)) {
2369  $resize = 1;
2370  }
2371 
2372  if ($resize == 2) {
2373  // Given two matrices of (potentially) unequal size, convert the smaller in each dimension to match the larger
2374  self::_resizeMatricesExtend($operand1,$operand2,$matrix1Rows,$matrix1Columns,$matrix2Rows,$matrix2Columns);
2375  } elseif ($resize == 1) {
2376  // Given two matrices of (potentially) unequal size, convert the larger in each dimension to match the smaller
2377  self::_resizeMatricesShrink($operand1,$operand2,$matrix1Rows,$matrix1Columns,$matrix2Rows,$matrix2Columns);
2378  }
2379  return array( $matrix1Rows,$matrix1Columns,$matrix2Rows,$matrix2Columns);
2380  } // function _checkMatrixOperands()
2381 
2382 
2389  public static function _getMatrixDimensions(&$matrix) {
2390  $matrixRows = count($matrix);
2391  $matrixColumns = 0;
2392  foreach($matrix as $rowKey => $rowValue) {
2393  $matrixColumns = max(count($rowValue),$matrixColumns);
2394  if (!is_array($rowValue)) {
2395  $matrix[$rowKey] = array($rowValue);
2396  } else {
2397  $matrix[$rowKey] = array_values($rowValue);
2398  }
2399  }
2400  $matrix = array_values($matrix);
2401  return array($matrixRows,$matrixColumns);
2402  } // function _getMatrixDimensions()
2403 
2404 
2411  private static function _resizeMatricesShrink(&$matrix1,&$matrix2,$matrix1Rows,$matrix1Columns,$matrix2Rows,$matrix2Columns) {
2412  if (($matrix2Columns < $matrix1Columns) || ($matrix2Rows < $matrix1Rows)) {
2413  if ($matrix2Columns < $matrix1Columns) {
2414  for ($i = 0; $i < $matrix1Rows; ++$i) {
2415  for ($j = $matrix2Columns; $j < $matrix1Columns; ++$j) {
2416  unset($matrix1[$i][$j]);
2417  }
2418  }
2419  }
2420  if ($matrix2Rows < $matrix1Rows) {
2421  for ($i = $matrix2Rows; $i < $matrix1Rows; ++$i) {
2422  unset($matrix1[$i]);
2423  }
2424  }
2425  }
2426 
2427  if (($matrix1Columns < $matrix2Columns) || ($matrix1Rows < $matrix2Rows)) {
2428  if ($matrix1Columns < $matrix2Columns) {
2429  for ($i = 0; $i < $matrix2Rows; ++$i) {
2430  for ($j = $matrix1Columns; $j < $matrix2Columns; ++$j) {
2431  unset($matrix2[$i][$j]);
2432  }
2433  }
2434  }
2435  if ($matrix1Rows < $matrix2Rows) {
2436  for ($i = $matrix1Rows; $i < $matrix2Rows; ++$i) {
2437  unset($matrix2[$i]);
2438  }
2439  }
2440  }
2441  } // function _resizeMatricesShrink()
2442 
2443 
2450  private static function _resizeMatricesExtend(&$matrix1,&$matrix2,$matrix1Rows,$matrix1Columns,$matrix2Rows,$matrix2Columns) {
2451  if (($matrix2Columns < $matrix1Columns) || ($matrix2Rows < $matrix1Rows)) {
2452  if ($matrix2Columns < $matrix1Columns) {
2453  for ($i = 0; $i < $matrix2Rows; ++$i) {
2454  $x = $matrix2[$i][$matrix2Columns-1];
2455  for ($j = $matrix2Columns; $j < $matrix1Columns; ++$j) {
2456  $matrix2[$i][$j] = $x;
2457  }
2458  }
2459  }
2460  if ($matrix2Rows < $matrix1Rows) {
2461  $x = $matrix2[$matrix2Rows-1];
2462  for ($i = 0; $i < $matrix1Rows; ++$i) {
2463  $matrix2[$i] = $x;
2464  }
2465  }
2466  }
2467 
2468  if (($matrix1Columns < $matrix2Columns) || ($matrix1Rows < $matrix2Rows)) {
2469  if ($matrix1Columns < $matrix2Columns) {
2470  for ($i = 0; $i < $matrix1Rows; ++$i) {
2471  $x = $matrix1[$i][$matrix1Columns-1];
2472  for ($j = $matrix1Columns; $j < $matrix2Columns; ++$j) {
2473  $matrix1[$i][$j] = $x;
2474  }
2475  }
2476  }
2477  if ($matrix1Rows < $matrix2Rows) {
2478  $x = $matrix1[$matrix1Rows-1];
2479  for ($i = 0; $i < $matrix2Rows; ++$i) {
2480  $matrix1[$i] = $x;
2481  }
2482  }
2483  }
2484  } // function _resizeMatricesExtend()
2485 
2486 
2493  private function _showValue($value) {
2494  if ($this->writeDebugLog) {
2495  $testArray = PHPExcel_Calculation_Functions::flattenArray($value);
2496  if (count($testArray) == 1) {
2497  $value = array_pop($testArray);
2498  }
2499 
2500  if (is_array($value)) {
2501  $returnMatrix = array();
2502  $pad = $rpad = ', ';
2503  foreach($value as $row) {
2504  if (is_array($row)) {
2505  $returnMatrix[] = implode($pad,$row);
2506  $rpad = '; ';
2507  } else {
2508  $returnMatrix[] = $row;
2509  }
2510  }
2511  return '{ '.implode($rpad,$returnMatrix).' }';
2512  } elseif(is_bool($value)) {
2513  return ($value) ? self::$_localeBoolean['TRUE'] : self::$_localeBoolean['FALSE'];
2514  }
2515  }
2516  return $value;
2517  } // function _showValue()
2518 
2519 
2526  private function _showTypeDetails($value) {
2527  if ($this->writeDebugLog) {
2528  $testArray = PHPExcel_Calculation_Functions::flattenArray($value);
2529  if (count($testArray) == 1) {
2530  $value = array_pop($testArray);
2531  }
2532 
2533  if (is_null($value)) {
2534  return 'a null value';
2535  } elseif (is_float($value)) {
2536  $typeString = 'a floating point number';
2537  } elseif(is_int($value)) {
2538  $typeString = 'an integer number';
2539  } elseif(is_bool($value)) {
2540  $typeString = 'a boolean';
2541  } elseif(is_array($value)) {
2542  $typeString = 'a matrix';
2543  } else {
2544  if ($value == '') {
2545  return 'an empty string';
2546  } elseif ($value{0} == '#') {
2547  return 'a '.$value.' error';
2548  } else {
2549  $typeString = 'a string';
2550  }
2551  }
2552  return $typeString.' with a value of '.$this->_showValue($value);
2553  }
2554  } // function _showTypeDetails()
2555 
2556 
2557  private static function _convertMatrixReferences($formula) {
2558  static $matrixReplaceFrom = array('{',';','}');
2559  static $matrixReplaceTo = array('MKMATRIX(MKMATRIX(','),MKMATRIX(','))');
2560 
2561  // Convert any Excel matrix references to the MKMATRIX() function
2562  if (strpos($formula,'{') !== false) {
2563  // If there is the possibility of braces within a quoted string, then we don't treat those as matrix indicators
2564  if (strpos($formula,'"') !== false) {
2565  // So instead we skip replacing in any quoted strings by only replacing in every other array element after we've exploded
2566  // the formula
2567  $temp = explode('"',$formula);
2568  // Open and Closed counts used for trapping mismatched braces in the formula
2569  $openCount = $closeCount = 0;
2570  $i = false;
2571  foreach($temp as &$value) {
2572  // Only count/replace in alternating array entries
2573  if ($i = !$i) {
2574  $openCount += substr_count($value,'{');
2575  $closeCount += substr_count($value,'}');
2576  $value = str_replace($matrixReplaceFrom,$matrixReplaceTo,$value);
2577  }
2578  }
2579  unset($value);
2580  // Then rebuild the formula string
2581  $formula = implode('"',$temp);
2582  } else {
2583  // If there's no quoted strings, then we do a simple count/replace
2584  $openCount = substr_count($formula,'{');
2585  $closeCount = substr_count($formula,'}');
2586  $formula = str_replace($matrixReplaceFrom,$matrixReplaceTo,$formula);
2587  }
2588  // Trap for mismatched braces and trigger an appropriate error
2589  if ($openCount < $closeCount) {
2590  if ($openCount > 0) {
2591  return $this->_raiseFormulaError("Formula Error: Mismatched matrix braces '}'");
2592  } else {
2593  return $this->_raiseFormulaError("Formula Error: Unexpected '}' encountered");
2594  }
2595  } elseif ($openCount > $closeCount) {
2596  if ($closeCount > 0) {
2597  return $this->_raiseFormulaError("Formula Error: Mismatched matrix braces '{'");
2598  } else {
2599  return $this->_raiseFormulaError("Formula Error: Unexpected '{' encountered");
2600  }
2601  }
2602  }
2603 
2604  return $formula;
2605  } // function _convertMatrixReferences()
2606 
2607 
2608  private static function _mkMatrix() {
2609  return func_get_args();
2610  } // function _mkMatrix()
2611 
2612 
2613  // Convert infix to postfix notation
2614  private function _parseFormula($formula, PHPExcel_Cell $pCell = null) {
2615  if (($formula = self::_convertMatrixReferences(trim($formula))) === false) {
2616  return false;
2617  }
2618 
2619  // If we're using cell caching, then $pCell may well be flushed back to the cache (which detaches the parent worksheet),
2620  // so we store the parent worksheet so that we can re-attach it when necessary
2621  $pCellParent = (!is_null($pCell)) ? $pCell->getParent() : null;
2622 
2623  // Binary Operators
2624  // These operators always work on two values
2625  // Array key is the operator, the value indicates whether this is a left or right associative operator
2626  $operatorAssociativity = array('^' => 0, // Exponentiation
2627  '*' => 0, '/' => 0, // Multiplication and Division
2628  '+' => 0, '-' => 0, // Addition and Subtraction
2629  '&' => 0, // Concatenation
2630  '|' => 0, ':' => 0, // Intersect and Range
2631  '>' => 0, '<' => 0, '=' => 0, '>=' => 0, '<=' => 0, '<>' => 0 // Comparison
2632  );
2633  // Comparison (Boolean) Operators
2634  // These operators work on two values, but always return a boolean result
2635  $comparisonOperators = array('>' => true, '<' => true, '=' => true, '>=' => true, '<=' => true, '<>' => true);
2636 
2637  // Operator Precedence
2638  // This list includes all valid operators, whether binary (including boolean) or unary (such as %)
2639  // Array key is the operator, the value is its precedence
2640  $operatorPrecedence = array(':' => 8, // Range
2641  '|' => 7, // Intersect
2642  '~' => 6, // Negation
2643  '%' => 5, // Percentage
2644  '^' => 4, // Exponentiation
2645  '*' => 3, '/' => 3, // Multiplication and Division
2646  '+' => 2, '-' => 2, // Addition and Subtraction
2647  '&' => 1, // Concatenation
2648  '>' => 0, '<' => 0, '=' => 0, '>=' => 0, '<=' => 0, '<>' => 0 // Comparison
2649  );
2650 
2651  $regexpMatchString = '/^('.self::CALCULATION_REGEXP_FUNCTION.
2652  '|'.self::CALCULATION_REGEXP_NUMBER.
2653  '|'.self::CALCULATION_REGEXP_STRING.
2654  '|'.self::CALCULATION_REGEXP_OPENBRACE.
2655  '|'.self::CALCULATION_REGEXP_CELLREF.
2656  '|'.self::CALCULATION_REGEXP_NAMEDRANGE.
2657  '|'.self::CALCULATION_REGEXP_ERROR.
2658  ')/si';
2659 
2660  // Start with initialisation
2661  $index = 0;
2662  $stack = new PHPExcel_Token_Stack;
2663  $output = array();
2664  $expectingOperator = false; // We use this test in syntax-checking the expression to determine when a
2665  // - is a negation or + is a positive operator rather than an operation
2666  $expectingOperand = false; // We use this test in syntax-checking the expression to determine whether an operand
2667  // should be null in a function call
2668  // The guts of the lexical parser
2669  // Loop through the formula extracting each operator and operand in turn
2670  while(true) {
2671 // echo 'Assessing Expression <b>'.substr($formula, $index).'</b><br />';
2672  $opCharacter = $formula{$index}; // Get the first character of the value at the current index position
2673 // echo 'Initial character of expression block is '.$opCharacter.'<br />';
2674  if ((isset($comparisonOperators[$opCharacter])) && (strlen($formula) > $index) && (isset($comparisonOperators[$formula{$index+1}]))) {
2675  $opCharacter .= $formula{++$index};
2676 // echo 'Initial character of expression block is comparison operator '.$opCharacter.'<br />';
2677  }
2678 
2679  // Find out if we're currently at the beginning of a number, variable, cell reference, function, parenthesis or operand
2680  $isOperandOrFunction = preg_match($regexpMatchString, substr($formula, $index), $match);
2681 // echo '$isOperandOrFunction is '.(($isOperandOrFunction) ? 'True' : 'False').'<br />';
2682 // var_dump($match);
2683 
2684  if ($opCharacter == '-' && !$expectingOperator) { // Is it a negation instead of a minus?
2685 // echo 'Element is a Negation operator<br />';
2686  $stack->push('Unary Operator','~'); // Put a negation on the stack
2687  ++$index; // and drop the negation symbol
2688  } elseif ($opCharacter == '%' && $expectingOperator) {
2689 // echo 'Element is a Percentage operator<br />';
2690  $stack->push('Unary Operator','%'); // Put a percentage on the stack
2691  ++$index;
2692  } elseif ($opCharacter == '+' && !$expectingOperator) { // Positive (unary plus rather than binary operator plus) can be discarded?
2693 // echo 'Element is a Positive number, not Plus operator<br />';
2694  ++$index; // Drop the redundant plus symbol
2695  } elseif ((($opCharacter == '~') || ($opCharacter == '|')) && (!$isOperandOrFunction)) { // We have to explicitly deny a tilde or pipe, because they are legal
2696  return $this->_raiseFormulaError("Formula Error: Illegal character '~'"); // on the stack but not in the input expression
2697 
2698  } elseif ((isset(self::$_operators[$opCharacter]) or $isOperandOrFunction) && $expectingOperator) { // Are we putting an operator on the stack?
2699 // echo 'Element with value '.$opCharacter.' is an Operator<br />';
2700  while($stack->count() > 0 &&
2701  ($o2 = $stack->last()) &&
2702  isset(self::$_operators[$o2['value']]) &&
2703  @($operatorAssociativity[$opCharacter] ? $operatorPrecedence[$opCharacter] < $operatorPrecedence[$o2['value']] : $operatorPrecedence[$opCharacter] <= $operatorPrecedence[$o2['value']])) {
2704  $output[] = $stack->pop(); // Swap operands and higher precedence operators from the stack to the output
2705  }
2706  $stack->push('Binary Operator',$opCharacter); // Finally put our current operator onto the stack
2707  ++$index;
2708  $expectingOperator = false;
2709 
2710  } elseif ($opCharacter == ')' && $expectingOperator) { // Are we expecting to close a parenthesis?
2711 // echo 'Element is a Closing bracket<br />';
2712  $expectingOperand = false;
2713  while (($o2 = $stack->pop()) && $o2['value'] != '(') { // Pop off the stack back to the last (
2714  if (is_null($o2)) return $this->_raiseFormulaError('Formula Error: Unexpected closing brace ")"');
2715  else $output[] = $o2;
2716  }
2717  $d = $stack->last(2);
2718  if (preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $d['value'], $matches)) { // Did this parenthesis just close a function?
2719  $functionName = $matches[1]; // Get the function name
2720 // echo 'Closed Function is '.$functionName.'<br />';
2721  $d = $stack->pop();
2722  $argumentCount = $d['value']; // See how many arguments there were (argument count is the next value stored on the stack)
2723 // if ($argumentCount == 0) {
2724 // echo 'With no arguments<br />';
2725 // } elseif ($argumentCount == 1) {
2726 // echo 'With 1 argument<br />';
2727 // } else {
2728 // echo 'With '.$argumentCount.' arguments<br />';
2729 // }
2730  $output[] = $d; // Dump the argument count on the output
2731  $output[] = $stack->pop(); // Pop the function and push onto the output
2732  if (isset(self::$_controlFunctions[$functionName])) {
2733 // echo 'Built-in function '.$functionName.'<br />';
2734  $expectedArgumentCount = self::$_controlFunctions[$functionName]['argumentCount'];
2735  $functionCall = self::$_controlFunctions[$functionName]['functionCall'];
2736  } elseif (isset(self::$_PHPExcelFunctions[$functionName])) {
2737 // echo 'PHPExcel function '.$functionName.'<br />';
2738  $expectedArgumentCount = self::$_PHPExcelFunctions[$functionName]['argumentCount'];
2739  $functionCall = self::$_PHPExcelFunctions[$functionName]['functionCall'];
2740  } else { // did we somehow push a non-function on the stack? this should never happen
2741  return $this->_raiseFormulaError("Formula Error: Internal error, non-function on stack");
2742  }
2743  // Check the argument count
2744  $argumentCountError = false;
2745  if (is_numeric($expectedArgumentCount)) {
2746  if ($expectedArgumentCount < 0) {
2747 // echo '$expectedArgumentCount is between 0 and '.abs($expectedArgumentCount).'<br />';
2748  if ($argumentCount > abs($expectedArgumentCount)) {
2749  $argumentCountError = true;
2750  $expectedArgumentCountString = 'no more than '.abs($expectedArgumentCount);
2751  }
2752  } else {
2753 // echo '$expectedArgumentCount is numeric '.$expectedArgumentCount.'<br />';
2754  if ($argumentCount != $expectedArgumentCount) {
2755  $argumentCountError = true;
2756  $expectedArgumentCountString = $expectedArgumentCount;
2757  }
2758  }
2759  } elseif ($expectedArgumentCount != '*') {
2760  $isOperandOrFunction = preg_match('/(\d*)([-+,])(\d*)/',$expectedArgumentCount,$argMatch);
2761 // print_r($argMatch);
2762 // echo '<br />';
2763  switch ($argMatch[2]) {
2764  case '+' :
2765  if ($argumentCount < $argMatch[1]) {
2766  $argumentCountError = true;
2767  $expectedArgumentCountString = $argMatch[1].' or more ';
2768  }
2769  break;
2770  case '-' :
2771  if (($argumentCount < $argMatch[1]) || ($argumentCount > $argMatch[3])) {
2772  $argumentCountError = true;
2773  $expectedArgumentCountString = 'between '.$argMatch[1].' and '.$argMatch[3];
2774  }
2775  break;
2776  case ',' :
2777  if (($argumentCount != $argMatch[1]) && ($argumentCount != $argMatch[3])) {
2778  $argumentCountError = true;
2779  $expectedArgumentCountString = 'either '.$argMatch[1].' or '.$argMatch[3];
2780  }
2781  break;
2782  }
2783  }
2784  if ($argumentCountError) {
2785  return $this->_raiseFormulaError("Formula Error: Wrong number of arguments for $functionName() function: $argumentCount given, ".$expectedArgumentCountString." expected");
2786  }
2787  }
2788  ++$index;
2789 
2790  } elseif ($opCharacter == ',') { // Is this the separator for function arguments?
2791 // echo 'Element is a Function argument separator<br />';
2792  while (($o2 = $stack->pop()) && $o2['value'] != '(') { // Pop off the stack back to the last (
2793  if (is_null($o2)) return $this->_raiseFormulaError("Formula Error: Unexpected ,");
2794  else $output[] = $o2; // pop the argument expression stuff and push onto the output
2795  }
2796  // If we've a comma when we're expecting an operand, then what we actually have is a null operand;
2797  // so push a null onto the stack
2798  if (($expectingOperand) || (!$expectingOperator)) {
2799  $output[] = array('type' => 'NULL Value', 'value' => self::$_ExcelConstants['NULL'], 'reference' => null);
2800  }
2801  // make sure there was a function
2802  $d = $stack->last(2);
2803  if (!preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $d['value'], $matches))
2804  return $this->_raiseFormulaError("Formula Error: Unexpected ,");
2805  $d = $stack->pop();
2806  $stack->push($d['type'],++$d['value'],$d['reference']); // increment the argument count
2807  $stack->push('Brace', '('); // put the ( back on, we'll need to pop back to it again
2808  $expectingOperator = false;
2809  $expectingOperand = true;
2810  ++$index;
2811 
2812  } elseif ($opCharacter == '(' && !$expectingOperator) {
2813 // echo 'Element is an Opening Bracket<br />';
2814  $stack->push('Brace', '(');
2815  ++$index;
2816 
2817  } elseif ($isOperandOrFunction && !$expectingOperator) { // do we now have a function/variable/number?
2818  $expectingOperator = true;
2819  $expectingOperand = false;
2820  $val = $match[1];
2821  $length = strlen($val);
2822 // echo 'Element with value '.$val.' is an Operand, Variable, Constant, String, Number, Cell Reference or Function<br />';
2823 
2824  if (preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $val, $matches)) {
2825  $val = preg_replace('/\s/','',$val);
2826 // echo 'Element '.$val.' is a Function<br />';
2827  if (isset(self::$_PHPExcelFunctions[strtoupper($matches[1])]) || isset(self::$_controlFunctions[strtoupper($matches[1])])) { // it's a function
2828  $stack->push('Function', strtoupper($val));
2829  $ax = preg_match('/^\s*(\s*\))/i', substr($formula, $index+$length), $amatch);
2830  if ($ax) {
2831  $stack->push('Operand Count for Function '.self::_localeFunc(strtoupper($val)).')', 0);
2832  $expectingOperator = true;
2833  } else {
2834  $stack->push('Operand Count for Function '.self::_localeFunc(strtoupper($val)).')', 1);
2835  $expectingOperator = false;
2836  }
2837  $stack->push('Brace', '(');
2838  } else { // it's a var w/ implicit multiplication
2839  $output[] = array('type' => 'Value', 'value' => $matches[1], 'reference' => null);
2840  }
2841  } elseif (preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'$/i', $val, $matches)) {
2842 // echo 'Element '.$val.' is a Cell reference<br />';
2843  // Watch for this case-change when modifying to allow cell references in different worksheets...
2844  // Should only be applied to the actual cell column, not the worksheet name
2845 
2846  // If the last entry on the stack was a : operator, then we have a cell range reference
2847  $testPrevOp = $stack->last(1);
2848  if ($testPrevOp['value'] == ':') {
2849  // If we have a worksheet reference, then we're playing with a 3D reference
2850  if ($matches[2] == '') {
2851  // Otherwise, we 'inherit' the worksheet reference from the start cell reference
2852  // The start of the cell range reference should be the last entry in $output
2853  $startCellRef = $output[count($output)-1]['value'];
2854  preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'$/i', $startCellRef, $startMatches);
2855  if ($startMatches[2] > '') {
2856  $val = $startMatches[2].'!'.$val;
2857  }
2858  } else {
2859  return $this->_raiseFormulaError("3D Range references are not yet supported");
2860  }
2861  }
2862 
2863  $output[] = array('type' => 'Cell Reference', 'value' => $val, 'reference' => $val);
2864 // $expectingOperator = false;
2865  } else { // it's a variable, constant, string, number or boolean
2866 // echo 'Element is a Variable, Constant, String, Number or Boolean<br />';
2867  // If the last entry on the stack was a : operator, then we may have a row or column range reference
2868  $testPrevOp = $stack->last(1);
2869  if ($testPrevOp['value'] == ':') {
2870  $startRowColRef = $output[count($output)-1]['value'];
2871  $rangeWS1 = '';
2872  if (strpos('!',$startRowColRef) !== false) {
2873  list($rangeWS1,$startRowColRef) = explode('!',$startRowColRef);
2874  }
2875  if ($rangeWS1 != '') $rangeWS1 .= '!';
2876  $rangeWS2 = $rangeWS1;
2877  if (strpos('!',$val) !== false) {
2878  list($rangeWS2,$val) = explode('!',$val);
2879  }
2880  if ($rangeWS2 != '') $rangeWS2 .= '!';
2881  if ((is_integer($startRowColRef)) && (ctype_digit($val)) &&
2882  ($startRowColRef <= 1048576) && ($val <= 1048576)) {
2883  // Row range
2884  $endRowColRef = (!is_null($pCellParent)) ? $pCellParent->getHighestColumn() : 'XFD'; // Max 16,384 columns for Excel2007
2885  $output[count($output)-1]['value'] = $rangeWS1.'A'.$startRowColRef;
2886  $val = $rangeWS2.$endRowColRef.$val;
2887  } elseif ((ctype_alpha($startRowColRef)) && (ctype_alpha($val)) &&
2888  (strlen($startRowColRef) <= 3) && (strlen($val) <= 3)) {
2889  // Column range
2890  $endRowColRef = (!is_null($pCellParent)) ? $pCellParent->getHighestRow() : 1048576; // Max 1,048,576 rows for Excel2007
2891  $output[count($output)-1]['value'] = $rangeWS1.strtoupper($startRowColRef).'1';
2892  $val = $rangeWS2.$val.$endRowColRef;
2893  }
2894  }
2895 
2896  $localeConstant = false;
2897  if ($opCharacter == '"') {
2898 // echo 'Element is a String<br />';
2899  // UnEscape any quotes within the string
2900  $val = self::_wrapResult(str_replace('""','"',self::_unwrapResult($val)));
2901  } elseif (is_numeric($val)) {
2902 // echo 'Element is a Number<br />';
2903  if ((strpos($val,'.') !== false) || (stripos($val,'e') !== false) || ($val > PHP_INT_MAX) || ($val < -PHP_INT_MAX)) {
2904 // echo 'Casting '.$val.' to float<br />';
2905  $val = (float) $val;
2906  } else {
2907 // echo 'Casting '.$val.' to integer<br />';
2908  $val = (integer) $val;
2909  }
2910  } elseif (isset(self::$_ExcelConstants[trim(strtoupper($val))])) {
2911  $excelConstant = trim(strtoupper($val));
2912 // echo 'Element '.$excelConstant.' is an Excel Constant<br />';
2913  $val = self::$_ExcelConstants[$excelConstant];
2914  } elseif (($localeConstant = array_search(trim(strtoupper($val)), self::$_localeBoolean)) !== false) {
2915 // echo 'Element '.$localeConstant.' is an Excel Constant<br />';
2916  $val = self::$_ExcelConstants[$localeConstant];
2917  }
2918  $details = array('type' => 'Value', 'value' => $val, 'reference' => null);
2919  if ($localeConstant) { $details['localeValue'] = $localeConstant; }
2920  $output[] = $details;
2921  }
2922  $index += $length;
2923 
2924  } elseif ($opCharacter == '$') { // absolute row or column range
2925  ++$index;
2926  } elseif ($opCharacter == ')') { // miscellaneous error checking
2927  if ($expectingOperand) {
2928  $output[] = array('type' => 'Null Value', 'value' => self::$_ExcelConstants['NULL'], 'reference' => null);
2929  $expectingOperand = false;
2930  $expectingOperator = true;
2931  } else {
2932  return $this->_raiseFormulaError("Formula Error: Unexpected ')'");
2933  }
2934  } elseif (isset(self::$_operators[$opCharacter]) && !$expectingOperator) {
2935  return $this->_raiseFormulaError("Formula Error: Unexpected operator '$opCharacter'");
2936  } else { // I don't even want to know what you did to get here
2937  return $this->_raiseFormulaError("Formula Error: An unexpected error occured");
2938  }
2939  // Test for end of formula string
2940  if ($index == strlen($formula)) {
2941  // Did we end with an operator?.
2942  // Only valid for the % unary operator
2943  if ((isset(self::$_operators[$opCharacter])) && ($opCharacter != '%')) {
2944  return $this->_raiseFormulaError("Formula Error: Operator '$opCharacter' has no operands");
2945  } else {
2946  break;
2947  }
2948  }
2949  // Ignore white space
2950  while (($formula{$index} == "\n") || ($formula{$index} == "\r")) {
2951  ++$index;
2952  }
2953  if ($formula{$index} == ' ') {
2954  while ($formula{$index} == ' ') {
2955  ++$index;
2956  }
2957  // If we're expecting an operator, but only have a space between the previous and next operands (and both are
2958  // Cell References) then we have an INTERSECTION operator
2959 // echo 'Possible Intersect Operator<br />';
2960  if (($expectingOperator) && (preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'.*/Ui', substr($formula, $index), $match)) &&
2961  ($output[count($output)-1]['type'] == 'Cell Reference')) {
2962 // echo 'Element is an Intersect Operator<br />';
2963  while($stack->count() > 0 &&
2964  ($o2 = $stack->last()) &&
2965  isset(self::$_operators[$o2['value']]) &&
2966  @($operatorAssociativity[$opCharacter] ? $operatorPrecedence[$opCharacter] < $operatorPrecedence[$o2['value']] : $operatorPrecedence[$opCharacter] <= $operatorPrecedence[$o2['value']])) {
2967  $output[] = $stack->pop(); // Swap operands and higher precedence operators from the stack to the output
2968  }
2969  $stack->push('Binary Operator','|'); // Put an Intersect Operator on the stack
2970  $expectingOperator = false;
2971  }
2972  }
2973  }
2974 
2975  while (!is_null($op = $stack->pop())) { // pop everything off the stack and push onto output
2976  if ($opCharacter['value'] == '(') return $this->_raiseFormulaError("Formula Error: Expecting ')'"); // if there are any opening braces on the stack, then braces were unbalanced
2977  $output[] = $op;
2978  }
2979  return $output;
2980  } // function _parseFormula()
2981 
2982 
2983  // evaluate postfix notation
2984  private function _processTokenStack($tokens, $cellID = null, PHPExcel_Cell $pCell = null) {
2985  if ($tokens == false) return false;
2986 
2987  // If we're using cell caching, then $pCell may well be flushed back to the cache (which detaches the parent worksheet),
2988  // so we store the parent worksheet so that we can re-attach it when necessary
2989  $pCellParent = (!is_null($pCell)) ? $pCell->getParent() : null;
2990  $stack = new PHPExcel_Token_Stack;
2991 
2992  // Loop through each token in turn
2993  foreach ($tokens as $tokenData) {
2994 // print_r($tokenData);
2995 // echo '<br />';
2996  $token = $tokenData['value'];
2997 // echo '<b>Token is '.$token.'</b><br />';
2998  // if the token is a binary operator, pop the top two values off the stack, do the operation, and push the result back on the stack
2999  if (isset(self::$_binaryOperators[$token])) {
3000 // echo 'Token is a binary operator<br />';
3001  // We must have two operands, error if we don't
3002  if (is_null($operand2Data = $stack->pop())) return $this->_raiseFormulaError('Internal error - Operand value missing from stack');
3003  if (is_null($operand1Data = $stack->pop())) return $this->_raiseFormulaError('Internal error - Operand value missing from stack');
3004  // Log what we're doing
3005  $operand1 = $operand1Data['value'];
3006  $operand2 = $operand2Data['value'];
3007  if ($token == ':') {
3008  $this->_writeDebug('Evaluating Range '.$this->_showValue($operand1Data['reference']).$token.$this->_showValue($operand2Data['reference']));
3009  } else {
3010  $this->_writeDebug('Evaluating '.$this->_showValue($operand1).' '.$token.' '.$this->_showValue($operand2));
3011  }
3012  // Process the operation in the appropriate manner
3013  switch ($token) {
3014  // Comparison (Boolean) Operators
3015  case '>' : // Greater than
3016  case '<' : // Less than
3017  case '>=' : // Greater than or Equal to
3018  case '<=' : // Less than or Equal to
3019  case '=' : // Equality
3020  case '<>' : // Inequality
3021  $this->_executeBinaryComparisonOperation($cellID,$operand1,$operand2,$token,$stack);
3022  break;
3023  // Binary Operators
3024  case ':' : // Range
3025  $sheet1 = $sheet2 = '';
3026  if (strpos($operand1Data['reference'],'!') !== false) {
3027  list($sheet1,$operand1Data['reference']) = explode('!',$operand1Data['reference']);
3028  } else {
3029  $sheet1 = (!is_null($pCellParent)) ? $pCellParent->getTitle() : '';
3030  }
3031  if (strpos($operand2Data['reference'],'!') !== false) {
3032  list($sheet2,$operand2Data['reference']) = explode('!',$operand2Data['reference']);
3033  } else {
3034  $sheet2 = $sheet1;
3035  }
3036  if ($sheet1 == $sheet2) {
3037  if (is_null($operand1Data['reference'])) {
3038  if ((trim($operand1Data['value']) != '') && (is_numeric($operand1Data['value']))) {
3039  $operand1Data['reference'] = $pCell->getColumn().$operand1Data['value'];
3040  } elseif (trim($operand1Data['reference']) == '') {
3041  $operand1Data['reference'] = $pCell->getCoordinate();
3042  } else {
3043  $operand1Data['reference'] = $operand1Data['value'].$pCell->getRow();
3044  }
3045  }
3046  if (is_null($operand2Data['reference'])) {
3047  if ((trim($operand2Data['value']) != '') && (is_numeric($operand2Data['value']))) {
3048  $operand2Data['reference'] = $pCell->getColumn().$operand2Data['value'];
3049  } elseif (trim($operand2Data['reference']) == '') {
3050  $operand2Data['reference'] = $pCell->getCoordinate();
3051  } else {
3052  $operand2Data['reference'] = $operand2Data['value'].$pCell->getRow();
3053  }
3054  }
3055 
3056  $oData = array_merge(explode(':',$operand1Data['reference']),explode(':',$operand2Data['reference']));
3057  $oCol = $oRow = array();
3058  foreach($oData as $oDatum) {
3059  $oCR = PHPExcel_Cell::coordinateFromString($oDatum);
3060  $oCol[] = PHPExcel_Cell::columnIndexFromString($oCR[0]) - 1;
3061  $oRow[] = $oCR[1];
3062  }
3063  $cellRef = PHPExcel_Cell::stringFromColumnIndex(min($oCol)).min($oRow).':'.PHPExcel_Cell::stringFromColumnIndex(max($oCol)).max($oRow);
3064  if (!is_null($pCellParent)) {
3065  $cellValue = $this->extractCellRange($cellRef, $pCellParent->getParent()->getSheetByName($sheet1), false);
3066  } else {
3067  return $this->_raiseFormulaError('Unable to access Cell Reference');
3068  }
3069  $stack->push('Cell Reference',$cellValue,$cellRef);
3070  } else {
3071  $stack->push('Error',PHPExcel_Calculation_Functions::REF(),null);
3072  }
3073 
3074  break;
3075  case '+' : // Addition
3076  $this->_executeNumericBinaryOperation($cellID,$operand1,$operand2,$token,'plusEquals',$stack);
3077  break;
3078  case '-' : // Subtraction
3079  $this->_executeNumericBinaryOperation($cellID,$operand1,$operand2,$token,'minusEquals',$stack);
3080  break;
3081  case '*' : // Multiplication
3082  $this->_executeNumericBinaryOperation($cellID,$operand1,$operand2,$token,'arrayTimesEquals',$stack);
3083  break;
3084  case '/' : // Division
3085  $this->_executeNumericBinaryOperation($cellID,$operand1,$operand2,$token,'arrayRightDivide',$stack);
3086  break;
3087  case '^' : // Exponential
3088  $this->_executeNumericBinaryOperation($cellID,$operand1,$operand2,$token,'power',$stack);
3089  break;
3090  case '&' : // Concatenation
3091  // If either of the operands is a matrix, we need to treat them both as matrices
3092  // (converting the other operand to a matrix if need be); then perform the required
3093  // matrix operation
3094  if (is_bool($operand1)) {
3095  $operand1 = ($operand1) ? self::$_localeBoolean['TRUE'] : self::$_localeBoolean['FALSE'];
3096  }
3097  if (is_bool($operand2)) {
3098  $operand2 = ($operand2) ? self::$_localeBoolean['TRUE'] : self::$_localeBoolean['FALSE'];
3099  }
3100  if ((is_array($operand1)) || (is_array($operand2))) {
3101  // Ensure that both operands are arrays/matrices
3102  self::_checkMatrixOperands($operand1,$operand2,2);
3103  try {
3104  // Convert operand 1 from a PHP array to a matrix
3105  $matrix = new PHPExcel_Shared_JAMA_Matrix($operand1);
3106  // Perform the required operation against the operand 1 matrix, passing in operand 2
3107  $matrixResult = $matrix->concat($operand2);
3108  $result = $matrixResult->getArray();
3109  } catch (Exception $ex) {
3110  $this->_writeDebug('JAMA Matrix Exception: '.$ex->getMessage());
3111  $result = '#VALUE!';
3112  }
3113  } else {
3114  $result = '"'.str_replace('""','"',self::_unwrapResult($operand1,'"').self::_unwrapResult($operand2,'"')).'"';
3115  }
3116  $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($result));
3117  $stack->push('Value',$result);
3118  break;
3119  case '|' : // Intersect
3120  $rowIntersect = array_intersect_key($operand1,$operand2);
3121  $cellIntersect = $oCol = $oRow = array();
3122  foreach(array_keys($rowIntersect) as $row) {
3123  $oRow[] = $row;
3124  foreach($rowIntersect[$row] as $col => $data) {
3125  $oCol[] = PHPExcel_Cell::columnIndexFromString($col) - 1;
3126  $cellIntersect[$row] = array_intersect_key($operand1[$row],$operand2[$row]);
3127  }
3128  }
3129  $cellRef = PHPExcel_Cell::stringFromColumnIndex(min($oCol)).min($oRow).':'.PHPExcel_Cell::stringFromColumnIndex(max($oCol)).max($oRow);
3130  $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($cellIntersect));
3131  $stack->push('Value',$cellIntersect,$cellRef);
3132  break;
3133  }
3134 
3135  // if the token is a unary operator, pop one value off the stack, do the operation, and push it back on
3136  } elseif (($token === '~') || ($token === '%')) {
3137 // echo 'Token is a unary operator<br />';
3138  if (is_null($arg = $stack->pop())) return $this->_raiseFormulaError('Internal error - Operand value missing from stack');
3139  $arg = $arg['value'];
3140  if ($token === '~') {
3141 // echo 'Token is a negation operator<br />';
3142  $this->_writeDebug('Evaluating Negation of '.$this->_showValue($arg));
3143  $multiplier = -1;
3144  } else {
3145 // echo 'Token is a percentile operator<br />';
3146  $this->_writeDebug('Evaluating Percentile of '.$this->_showValue($arg));
3147  $multiplier = 0.01;
3148  }
3149  if (is_array($arg)) {
3150  self::_checkMatrixOperands($arg,$multiplier,2);
3151  try {
3152  $matrix1 = new PHPExcel_Shared_JAMA_Matrix($arg);
3153  $matrixResult = $matrix1->arrayTimesEquals($multiplier);
3154  $result = $matrixResult->getArray();
3155  } catch (Exception $ex) {
3156  $this->_writeDebug('JAMA Matrix Exception: '.$ex->getMessage());
3157  $result = '#VALUE!';
3158  }
3159  $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($result));
3160  $stack->push('Value',$result);
3161  } else {
3162  $this->_executeNumericBinaryOperation($cellID,$multiplier,$arg,'*','arrayTimesEquals',$stack);
3163  }
3164 
3165  } elseif (preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'$/i', $token, $matches)) {
3166  $cellRef = null;
3167 // echo 'Element '.$token.' is a Cell reference<br />';
3168  if (isset($matches[8])) {
3169 // echo 'Reference is a Range of cells<br />';
3170  if (is_null($pCell)) {
3171 // We can't access the range, so return a REF error
3172  $cellValue = PHPExcel_Calculation_Functions::REF();
3173  } else {
3174  $cellRef = $matches[6].$matches[7].':'.$matches[9].$matches[10];
3175  if ($matches[2] > '') {
3176  $matches[2] = trim($matches[2],"\"'");
3177 // echo '$cellRef='.$cellRef.' in worksheet '.$matches[2].'<br />';
3178  $this->_writeDebug('Evaluating Cell Range '.$cellRef.' in worksheet '.$matches[2]);
3179  if (!is_null($pCellParent)) {
3180  $cellValue = $this->extractCellRange($cellRef, $pCellParent->getParent()->getSheetByName($matches[2]), false);
3181  } else {
3182  return $this->_raiseFormulaError('Unable to access Cell Reference');
3183  }
3184  $this->_writeDebug('Evaluation Result for cells '.$cellRef.' in worksheet '.$matches[2].' is '.$this->_showTypeDetails($cellValue));
3185 // $cellRef = $matches[2].'!'.$cellRef;
3186  } else {
3187 // echo '$cellRef='.$cellRef.' in current worksheet<br />';
3188  $this->_writeDebug('Evaluating Cell Range '.$cellRef.' in current worksheet');
3189  if (!is_null($pCellParent)) {
3190  $cellValue = $this->extractCellRange($cellRef, $pCellParent, false);
3191  } else {
3192  return $this->_raiseFormulaError('Unable to access Cell Reference');
3193  }
3194  $this->_writeDebug('Evaluation Result for cells '.$cellRef.' is '.$this->_showTypeDetails($cellValue));
3195  }
3196  }
3197  } else {
3198 // echo 'Reference is a single Cell<br />';
3199  if (is_null($pCell)) {
3200 // We can't access the cell, so return a REF error
3201  $cellValue = PHPExcel_Calculation_Functions::REF();
3202  } else {
3203  $cellRef = $matches[6].$matches[7];
3204  if ($matches[2] > '') {
3205  $matches[2] = trim($matches[2],"\"'");
3206 // echo '$cellRef='.$cellRef.' in worksheet '.$matches[2].'<br />';
3207  $this->_writeDebug('Evaluating Cell '.$cellRef.' in worksheet '.$matches[2]);
3208  if (!is_null($pCellParent)) {
3209  if ($pCellParent->getParent()->getSheetByName($matches[2])->cellExists($cellRef)) {
3210  $cellValue = $this->extractCellRange($cellRef, $pCellParent->getParent()->getSheetByName($matches[2]), false);
3211  $pCell->attach($pCellParent);
3212  } else {
3213  $cellValue = null;
3214  }
3215  } else {
3216  return $this->_raiseFormulaError('Unable to access Cell Reference');
3217  }
3218  $this->_writeDebug('Evaluation Result for cell '.$cellRef.' in worksheet '.$matches[2].' is '.$this->_showTypeDetails($cellValue));
3219 // $cellRef = $matches[2].'!'.$cellRef;
3220  } else {
3221 // echo '$cellRef='.$cellRef.' in current worksheet<br />';
3222  $this->_writeDebug('Evaluating Cell '.$cellRef.' in current worksheet');
3223  if ($pCellParent->cellExists($cellRef)) {
3224  $cellValue = $this->extractCellRange($cellRef, $pCellParent, false);
3225  $pCell->attach($pCellParent);
3226  } else {
3227  $cellValue = null;
3228  }
3229  $this->_writeDebug('Evaluation Result for cell '.$cellRef.' is '.$this->_showTypeDetails($cellValue));
3230  }
3231  }
3232  }
3233  $stack->push('Value',$cellValue,$cellRef);
3234 
3235  // if the token is a function, pop arguments off the stack, hand them to the function, and push the result back on
3236  } elseif (preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $token, $matches)) {
3237 // echo 'Token is a function<br />';
3238  $functionName = $matches[1];
3239  $argCount = $stack->pop();
3240  $argCount = $argCount['value'];
3241  if ($functionName != 'MKMATRIX') {
3242  $this->_writeDebug('Evaluating Function '.self::_localeFunc($functionName).'() with '.(($argCount == 0) ? 'no' : $argCount).' argument'.(($argCount == 1) ? '' : 's'));
3243  }
3244  if ((isset(self::$_PHPExcelFunctions[$functionName])) || (isset(self::$_controlFunctions[$functionName]))) { // function
3245  if (isset(self::$_PHPExcelFunctions[$functionName])) {
3246  $functionCall = self::$_PHPExcelFunctions[$functionName]['functionCall'];
3247  $passByReference = isset(self::$_PHPExcelFunctions[$functionName]['passByReference']);
3248  $passCellReference = isset(self::$_PHPExcelFunctions[$functionName]['passCellReference']);
3249  } elseif (isset(self::$_controlFunctions[$functionName])) {
3250  $functionCall = self::$_controlFunctions[$functionName]['functionCall'];
3251  $passByReference = isset(self::$_controlFunctions[$functionName]['passByReference']);
3252  $passCellReference = isset(self::$_controlFunctions[$functionName]['passCellReference']);
3253  }
3254  // get the arguments for this function
3255 // echo 'Function '.$functionName.' expects '.$argCount.' arguments<br />';
3256  $args = $argArrayVals = array();
3257  for ($i = 0; $i < $argCount; ++$i) {
3258  $arg = $stack->pop();
3259  $a = $argCount - $i - 1;
3260  if (($passByReference) &&
3261  (isset(self::$_PHPExcelFunctions[$functionName]['passByReference'][$a])) &&
3262  (self::$_PHPExcelFunctions[$functionName]['passByReference'][$a])) {
3263  if (is_null($arg['reference'])) {
3264  $args[] = $cellID;
3265  if ($functionName != 'MKMATRIX') { $argArrayVals[] = $this->_showValue($cellID); }
3266  } else {
3267  $args[] = $arg['reference'];
3268  if ($functionName != 'MKMATRIX') { $argArrayVals[] = $this->_showValue($arg['reference']); }
3269  }
3270  } else {
3271  $args[] = self::_unwrapResult($arg['value']);
3272  if ($functionName != 'MKMATRIX') { $argArrayVals[] = $this->_showValue($arg['value']); }
3273  }
3274  }
3275  // Reverse the order of the arguments
3276  krsort($args);
3277  if (($passByReference) && ($argCount == 0)) {
3278  $args[] = $cellID;
3279  $argArrayVals[] = $this->_showValue($cellID);
3280  }
3281 // echo 'Arguments are: ';
3282 // print_r($args);
3283 // echo '<br />';
3284  if ($functionName != 'MKMATRIX') {
3285  if ($this->writeDebugLog) {
3286  krsort($argArrayVals);
3287  $this->_writeDebug('Evaluating '. self::_localeFunc($functionName).'( '.implode(self::$_localeArgumentSeparator.' ',PHPExcel_Calculation_Functions::flattenArray($argArrayVals)).' )');
3288  }
3289  }
3290  // Process each argument in turn, building the return value as an array
3291 // if (($argCount == 1) && (is_array($args[1])) && ($functionName != 'MKMATRIX')) {
3292 // $operand1 = $args[1];
3293 // $this->_writeDebug('Argument is a matrix: '.$this->_showValue($operand1));
3294 // $result = array();
3295 // $row = 0;
3296 // foreach($operand1 as $args) {
3297 // if (is_array($args)) {
3298 // foreach($args as $arg) {
3299 // $this->_writeDebug('Evaluating '.self::_localeFunc($functionName).'( '.$this->_showValue($arg).' )');
3300 // $r = call_user_func_array($functionCall,$arg);
3301 // $this->_writeDebug('Evaluation Result for '.self::_localeFunc($functionName).'() function call is '.$this->_showTypeDetails($r));
3302 // $result[$row][] = $r;
3303 // }
3304 // ++$row;
3305 // } else {
3306 // $this->_writeDebug('Evaluating '.self::_localeFunc($functionName).'( '.$this->_showValue($args).' )');
3307 // $r = call_user_func_array($functionCall,$args);
3308 // $this->_writeDebug('Evaluation Result for '.self::_localeFunc($functionName).'() function call is '.$this->_showTypeDetails($r));
3309 // $result[] = $r;
3310 // }
3311 // }
3312 // } else {
3313  // Process the argument with the appropriate function call
3314  if ($passCellReference) {
3315  $args[] = $pCell;
3316  }
3317  if (strpos($functionCall,'::') !== false) {
3318  $result = call_user_func_array(explode('::',$functionCall),$args);
3319  } else {
3320  foreach($args as &$arg) {
3322  }
3323  unset($arg);
3324  $result = call_user_func_array($functionCall,$args);
3325  }
3326 // }
3327  if ($functionName != 'MKMATRIX') {
3328  $this->_writeDebug('Evaluation Result for '.self::_localeFunc($functionName).'() function call is '.$this->_showTypeDetails($result));
3329  }
3330  $stack->push('Value',self::_wrapResult($result));
3331  }
3332 
3333  } else {
3334  // if the token is a number, boolean, string or an Excel error, push it onto the stack
3335  if (isset(self::$_ExcelConstants[strtoupper($token)])) {
3336  $excelConstant = strtoupper($token);
3337 // echo 'Token is a PHPExcel constant: '.$excelConstant.'<br />';
3338  $stack->push('Constant Value',self::$_ExcelConstants[$excelConstant]);
3339  $this->_writeDebug('Evaluating Constant '.$excelConstant.' as '.$this->_showTypeDetails(self::$_ExcelConstants[$excelConstant]));
3340  } elseif ((is_numeric($token)) || (is_null($token)) || (is_bool($token)) || ($token == '') || ($token{0} == '"') || ($token{0} == '#')) {
3341 // echo 'Token is a number, boolean, string, null or an Excel error<br />';
3342  $stack->push('Value',$token);
3343  // if the token is a named range, push the named range name onto the stack
3344  } elseif (preg_match('/^'.self::CALCULATION_REGEXP_NAMEDRANGE.'$/i', $token, $matches)) {
3345 // echo 'Token is a named range<br />';
3346  $namedRange = $matches[6];
3347 // echo 'Named Range is '.$namedRange.'<br />';
3348  $this->_writeDebug('Evaluating Named Range '.$namedRange);
3349  $cellValue = $this->extractNamedRange($namedRange, ((null !== $pCell) ? $pCellParent : null), false);
3350  $pCell->attach($pCellParent);
3351  $this->_writeDebug('Evaluation Result for named range '.$namedRange.' is '.$this->_showTypeDetails($cellValue));
3352  $stack->push('Named Range',$cellValue,$namedRange);
3353  } else {
3354  return $this->_raiseFormulaError("undefined variable '$token'");
3355  }
3356  }
3357  }
3358  // when we're out of tokens, the stack should have a single element, the final result
3359  if ($stack->count() != 1) return $this->_raiseFormulaError("internal error");
3360  $output = $stack->pop();
3361  $output = $output['value'];
3362 
3363 // if ((is_array($output)) && (self::$returnArrayAsType != self::RETURN_ARRAY_AS_ARRAY)) {
3364 // return array_shift(PHPExcel_Calculation_Functions::flattenArray($output));
3365 // }
3366  return $output;
3367  } // function _processTokenStack()
3368 
3369 
3370  private function _validateBinaryOperand($cellID,&$operand,&$stack) {
3371  // Numbers, matrices and booleans can pass straight through, as they're already valid
3372  if (is_string($operand)) {
3373  // We only need special validations for the operand if it is a string
3374  // Start by stripping off the quotation marks we use to identify true excel string values internally
3375  if ($operand > '' && $operand{0} == '"') { $operand = self::_unwrapResult($operand); }
3376  // If the string is a numeric value, we treat it as a numeric, so no further testing
3377  if (!is_numeric($operand)) {
3378  // If not a numeric, test to see if the value is an Excel error, and so can't be used in normal binary operations
3379  if ($operand > '' && $operand{0} == '#') {
3380  $stack->push('Value', $operand);
3381  $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($operand));
3382  return false;
3384  // If not a numeric or a fraction, then it's a text string, and so can't be used in mathematical binary operations
3385  $stack->push('Value', '#VALUE!');
3386  $this->_writeDebug('Evaluation Result is a '.$this->_showTypeDetails('#VALUE!'));
3387  return false;
3388  }
3389  }
3390  }
3391 
3392  // return a true if the value of the operand is one that we can use in normal binary operations
3393  return true;
3394  } // function _validateBinaryOperand()
3395 
3396 
3397  private function _executeBinaryComparisonOperation($cellID,$operand1,$operand2,$operation,&$stack,$recursingArrays=false) {
3398  // If we're dealing with matrix operations, we want a matrix result
3399  if ((is_array($operand1)) || (is_array($operand2))) {
3400  $result = array();
3401  if ((is_array($operand1)) && (!is_array($operand2))) {
3402  foreach($operand1 as $x => $operandData) {
3403  $this->_writeDebug('Evaluating '.$this->_showValue($operandData).' '.$operation.' '.$this->_showValue($operand2));
3404  $this->_executeBinaryComparisonOperation($cellID,$operandData,$operand2,$operation,$stack);
3405  $r = $stack->pop();
3406  $result[$x] = $r['value'];
3407  }
3408  } elseif ((!is_array($operand1)) && (is_array($operand2))) {
3409  foreach($operand2 as $x => $operandData) {
3410  $this->_writeDebug('Evaluating '.$this->_showValue($operand1).' '.$operation.' '.$this->_showValue($operandData));
3411  $this->_executeBinaryComparisonOperation($cellID,$operand1,$operandData,$operation,$stack);
3412  $r = $stack->pop();
3413  $result[$x] = $r['value'];
3414  }
3415  } else {
3416  if (!$recursingArrays) { self::_checkMatrixOperands($operand1,$operand2,2); }
3417  foreach($operand1 as $x => $operandData) {
3418  $this->_writeDebug('Evaluating '.$this->_showValue($operandData).' '.$operation.' '.$this->_showValue($operand2[$x]));
3419  $this->_executeBinaryComparisonOperation($cellID,$operandData,$operand2[$x],$operation,$stack,true);
3420  $r = $stack->pop();
3421  $result[$x] = $r['value'];
3422  }
3423  }
3424  // Log the result details
3425  $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($result));
3426  // And push the result onto the stack
3427  $stack->push('Array',$result);
3428  return true;
3429  }
3430 
3431  // Simple validate the two operands if they are string values
3432  if (is_string($operand1) && $operand1 > '' && $operand1{0} == '"') { $operand1 = self::_unwrapResult($operand1); }
3433  if (is_string($operand2) && $operand2 > '' && $operand2{0} == '"') { $operand2 = self::_unwrapResult($operand2); }
3434 
3435  // execute the necessary operation
3436  switch ($operation) {
3437  // Greater than
3438  case '>':
3439  $result = ($operand1 > $operand2);
3440  break;
3441  // Less than
3442  case '<':
3443  $result = ($operand1 < $operand2);
3444  break;
3445  // Equality
3446  case '=':
3447  $result = ($operand1 == $operand2);
3448  break;
3449  // Greater than or equal
3450  case '>=':
3451  $result = ($operand1 >= $operand2);
3452  break;
3453  // Less than or equal
3454  case '<=':
3455  $result = ($operand1 <= $operand2);
3456  break;
3457  // Inequality
3458  case '<>':
3459  $result = ($operand1 != $operand2);
3460  break;
3461  }
3462 
3463  // Log the result details
3464  $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($result));
3465  // And push the result onto the stack
3466  $stack->push('Value',$result);
3467  return true;
3468  } // function _executeBinaryComparisonOperation()
3469 
3470 
3471  private function _executeNumericBinaryOperation($cellID,$operand1,$operand2,$operation,$matrixFunction,&$stack) {
3472  // Validate the two operands
3473  if (!$this->_validateBinaryOperand($cellID,$operand1,$stack)) return false;
3474  if (!$this->_validateBinaryOperand($cellID,$operand2,$stack)) return false;
3475 
3476  $executeMatrixOperation = false;
3477  // If either of the operands is a matrix, we need to treat them both as matrices
3478  // (converting the other operand to a matrix if need be); then perform the required
3479  // matrix operation
3480  if ((is_array($operand1)) || (is_array($operand2))) {
3481  // Ensure that both operands are arrays/matrices
3482  $executeMatrixOperation = true;
3483  $mSize = array();
3484  list($mSize[],$mSize[],$mSize[],$mSize[]) = self::_checkMatrixOperands($operand1,$operand2,2);
3485 
3486  // But if they're both single cell matrices, then we can treat them as simple values
3487  if (array_sum($mSize) == 4) {
3488  $executeMatrixOperation = false;
3489  $operand1 = $operand1[0][0];
3490  $operand2 = $operand2[0][0];
3491  }
3492  }
3493 
3494  if ($executeMatrixOperation) {
3495  try {
3496  // Convert operand 1 from a PHP array to a matrix
3497  $matrix = new PHPExcel_Shared_JAMA_Matrix($operand1);
3498  // Perform the required operation against the operand 1 matrix, passing in operand 2
3499  $matrixResult = $matrix->$matrixFunction($operand2);
3500  $result = $matrixResult->getArray();
3501  } catch (Exception $ex) {
3502  $this->_writeDebug('JAMA Matrix Exception: '.$ex->getMessage());
3503  $result = '#VALUE!';
3504  }
3505  } else {
3507  ((is_string($operand1) && !is_numeric($operand1)) || (is_string($operand2) && !is_numeric($operand2)))) {
3509  } else {
3510  // If we're dealing with non-matrix operations, execute the necessary operation
3511  switch ($operation) {
3512  // Addition
3513  case '+':
3514  $result = $operand1+$operand2;
3515  break;
3516  // Subtraction
3517  case '-':
3518  $result = $operand1-$operand2;
3519  break;
3520  // Multiplication
3521  case '*':
3522  $result = $operand1*$operand2;
3523  break;
3524  // Division
3525  case '/':
3526  if ($operand2 == 0) {
3527  // Trap for Divide by Zero error
3528  $stack->push('Value','#DIV/0!');
3529  $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails('#DIV/0!'));
3530  return false;
3531  } else {
3532  $result = $operand1/$operand2;
3533  }
3534  break;
3535  // Power
3536  case '^':
3537  $result = pow($operand1,$operand2);
3538  break;
3539  }
3540  }
3541  }
3542 
3543  // Log the result details
3544  $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($result));
3545  // And push the result onto the stack
3546  $stack->push('Value',$result);
3547  return true;
3548  } // function _executeNumericBinaryOperation()
3549 
3550 
3551  private function _writeDebug($message) {
3552  // Only write the debug log if logging is enabled
3553  if ($this->writeDebugLog) {
3554  if ($this->echoDebugLog) {
3555  echo implode(' -> ',$this->debugLogStack).' -> '.$message,'<br />';
3556  }
3557  $this->debugLog[] = implode(' -> ',$this->debugLogStack).' -> '.$message;
3558  }
3559  } // function _writeDebug()
3560 
3561 
3562  // trigger an error, but nicely, if need be
3563  protected function _raiseFormulaError($errorMessage) {
3564  $this->formulaError = $errorMessage;
3565  if (!$this->suppressFormulaErrors) throw new Exception($errorMessage);
3566  trigger_error($errorMessage, E_USER_ERROR);
3567  } // function _raiseFormulaError()
3568 
3569 
3578  public function extractCellRange(&$pRange = 'A1', PHPExcel_Worksheet $pSheet = null, $resetLog=true) {
3579  // Return value
3580  $returnValue = array ();
3581 
3582 // echo 'extractCellRange('.$pRange.')<br />';
3583  if (!is_null($pSheet)) {
3584 // echo 'Passed sheet name is '.$pSheet->getTitle().'<br />';
3585 // echo 'Range reference is '.$pRange.'<br />';
3586  if (strpos ($pRange, '!') !== false) {
3587 // echo '$pRange reference includes sheet reference<br />';
3588  $worksheetReference = PHPExcel_Worksheet::extractSheetTitle($pRange, true);
3589  $pSheet = $pSheet->getParent()->getSheetByName($worksheetReference[0]);
3590 // echo 'New sheet name is '.$pSheet->getTitle().'<br />';
3591  $pRange = $worksheetReference[1];
3592 // echo 'Adjusted Range reference is '.$pRange.'<br />';
3593  }
3594 
3595  // Extract range
3596  $aReferences = PHPExcel_Cell::extractAllCellReferencesInRange($pRange);
3597  $pRange = $pSheet->getTitle().'!'.$pRange;
3598  if (!isset($aReferences[1])) {
3599  // Single cell in range
3600  list($currentCol,$currentRow) = sscanf($aReferences[0],'%[A-Z]%d');
3601  if ($pSheet->cellExists($aReferences[0])) {
3602  $returnValue[$currentRow][$currentCol] = $pSheet->getCell($aReferences[0])->getCalculatedValue($resetLog);
3603  } else {
3604  $returnValue[$currentRow][$currentCol] = null;
3605  }
3606  } else {
3607  // Extract cell data for all cells in the range
3608  foreach ($aReferences as $reference) {
3609  // Extract range
3610  list($currentCol,$currentRow) = sscanf($reference,'%[A-Z]%d');
3611 
3612  if ($pSheet->cellExists($reference)) {
3613  $returnValue[$currentRow][$currentCol] = $pSheet->getCell($reference)->getCalculatedValue($resetLog);
3614  } else {
3615  $returnValue[$currentRow][$currentCol] = null;
3616  }
3617  }
3618  }
3619  }
3620 
3621  // Return
3622  return $returnValue;
3623  } // function extractCellRange()
3624 
3625 
3634  public function extractNamedRange(&$pRange = 'A1', PHPExcel_Worksheet $pSheet = null, $resetLog=true) {
3635  // Return value
3636  $returnValue = array ();
3637 
3638 // echo 'extractNamedRange('.$pRange.')<br />';
3639  if (!is_null($pSheet)) {
3640 // echo 'Current sheet name is '.$pSheet->getTitle().'<br />';
3641 // echo 'Range reference is '.$pRange.'<br />';
3642  if (strpos ($pRange, '!') !== false) {
3643 // echo '$pRange reference includes sheet reference<br />';
3644  $worksheetReference = PHPExcel_Worksheet::extractSheetTitle($pRange, true);
3645  $pSheet = $pSheet->getParent()->getSheetByName($worksheetReference[0]);
3646 // echo 'New sheet name is '.$pSheet->getTitle().'<br />';
3647  $pRange = $worksheetReference[1];
3648 // echo 'Adjusted Range reference is '.$pRange.'<br />';
3649  }
3650 
3651  // Named range?
3652  $namedRange = PHPExcel_NamedRange::resolveRange($pRange, $pSheet);
3653  if (!is_null($namedRange)) {
3654  $pSheet = $namedRange->getWorksheet();
3655 // echo 'Named Range '.$pRange.' (';
3656  $pRange = $namedRange->getRange();
3657  $splitRange = PHPExcel_Cell::splitRange($pRange);
3658  // Convert row and column references
3659  if (ctype_alpha($splitRange[0][0])) {
3660  $pRange = $splitRange[0][0] . '1:' . $splitRange[0][1] . $namedRange->getWorksheet()->getHighestRow();
3661  } elseif(ctype_digit($splitRange[0][0])) {
3662  $pRange = 'A' . $splitRange[0][0] . ':' . $namedRange->getWorksheet()->getHighestColumn() . $splitRange[0][1];
3663  }
3664 // echo $pRange.') is in sheet '.$namedRange->getWorksheet()->getTitle().'<br />';
3665 
3666 // if ($pSheet->getTitle() != $namedRange->getWorksheet()->getTitle()) {
3667 // if (!$namedRange->getLocalOnly()) {
3668 // $pSheet = $namedRange->getWorksheet();
3669 // } else {
3670 // return $returnValue;
3671 // }
3672 // }
3673  } else {
3675  }
3676 
3677  // Extract range
3678  $aReferences = PHPExcel_Cell::extractAllCellReferencesInRange($pRange);
3679 // var_dump($aReferences);
3680  if (!isset($aReferences[1])) {
3681  // Single cell (or single column or row) in range
3682  list($currentCol,$currentRow) = PHPExcel_Cell::coordinateFromString($aReferences[0]);
3683  if ($pSheet->cellExists($aReferences[0])) {
3684  $returnValue[$currentRow][$currentCol] = $pSheet->getCell($aReferences[0])->getCalculatedValue($resetLog);
3685  } else {
3686  $returnValue[$currentRow][$currentCol] = null;
3687  }
3688  } else {
3689  // Extract cell data for all cells in the range
3690  foreach ($aReferences as $reference) {
3691  // Extract range
3692  list($currentCol,$currentRow) = PHPExcel_Cell::coordinateFromString($reference);
3693 // echo 'NAMED RANGE: $currentCol='.$currentCol.' $currentRow='.$currentRow.'<br />';
3694  if ($pSheet->cellExists($reference)) {
3695  $returnValue[$currentRow][$currentCol] = $pSheet->getCell($reference)->getCalculatedValue($resetLog);
3696  } else {
3697  $returnValue[$currentRow][$currentCol] = null;
3698  }
3699  }
3700  }
3701 // print_r($returnValue);
3702 // echo '<br />';
3703  }
3704 
3705  // Return
3706  return $returnValue;
3707  } // function extractNamedRange()
3708 
3709 
3716  public function isImplemented($pFunction = '') {
3717  $pFunction = strtoupper ($pFunction);
3718  if (isset(self::$_PHPExcelFunctions[$pFunction])) {
3719  return (self::$_PHPExcelFunctions[$pFunction]['functionCall'] != 'PHPExcel_Calculation_Functions::DUMMY');
3720  } else {
3721  return false;
3722  }
3723  } // function isImplemented()
3724 
3725 
3731  public function listFunctions() {
3732  // Return value
3733  $returnValue = array();
3734  // Loop functions
3735  foreach(self::$_PHPExcelFunctions as $functionName => $function) {
3736  if ($function['functionCall'] != 'PHPExcel_Calculation_Functions::DUMMY') {
3737  $returnValue[$functionName] = new PHPExcel_Calculation_Function($function['category'],
3738  $functionName,
3739  $function['functionCall']
3740  );
3741  }
3742  }
3743 
3744  // Return
3745  return $returnValue;
3746  } // function listFunctions()
3747 
3748 
3754  public function listAllFunctionNames() {
3755  return array_keys(self::$_PHPExcelFunctions);
3756  } // function listAllFunctionNames()
3757 
3763  public function listFunctionNames() {
3764  // Return value
3765  $returnValue = array();
3766  // Loop functions
3767  foreach(self::$_PHPExcelFunctions as $functionName => $function) {
3768  if ($function['functionCall'] != 'PHPExcel_Calculation_Functions::DUMMY') {
3769  $returnValue[] = $functionName;
3770  }
3771  }
3772 
3773  // Return
3774  return $returnValue;
3775  } // function listFunctionNames()
3776 
3777 } // class PHPExcel_Calculation
3778 
3779 
3780 
3781 
3782 // for internal use
3784 
3785  private $_stack = array();
3786  private $_count = 0;
3787 
3788 
3789  public function count() {
3790  return $this->_count;
3791  } // function count()
3792 
3793 
3794  public function push($type,$value,$reference=null) {
3795  $this->_stack[$this->_count++] = array('type' => $type,
3796  'value' => $value,
3797  'reference' => $reference
3798  );
3799  if ($type == 'Function') {
3800  $localeFunction = PHPExcel_Calculation::_localeFunc($value);
3801  if ($localeFunction != $value) {
3802  $this->_stack[($this->_count - 1)]['localeValue'] = $localeFunction;
3803  }
3804  }
3805  } // function push()
3806 
3807 
3808  public function pop() {
3809  if ($this->_count > 0) {
3810  return $this->_stack[--$this->_count];
3811  }
3812  return null;
3813  } // function pop()
3814 
3815 
3816  public function last($n=1) {
3817  if ($this->_count-$n < 0) {
3818  return null;
3819  }
3820  return $this->_stack[$this->_count-$n];
3821  } // function last()
3822 
3823 
3824  function __construct() {
3825  }
3826 
3827 } // class PHPExcel_Token_Stack