Subversion Repositories eFlore/Applications.cel

Rev

Details | Last modification | View Log | RSS feed

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