1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26
27
28 #include "parclass.hxx"
29 #include "token.hxx"
30 #include "global.hxx"
31 #include "callform.hxx"
32 #include "addincol.hxx"
33 #include "funcdesc.hxx"
34 #include <unotools/charclass.hxx>
35 #include <tools/debug.hxx>
36 #include <string.h>
37
38 #if OSL_DEBUG_LEVEL > 1
39 // the documentation thingy
40 #include <stdio.h>
41 #include <com/sun/star/sheet/FormulaLanguage.hpp>
42 #include "compiler.hxx"
43 #include "sc.hrc" // VAR_ARGS
44 #endif
45
46
47 /* Following assumptions are made:
48 * - OpCodes not specified at all will have at least one and only parameters of
49 * type Value, no check is done on the count of parameters => no Bounds type
50 * is returned.
51 * - For OpCodes with a variable number of parameters the type(s) of the last
52 * repeated parameter(s) specified determine(s) the type(s) of all following
53 * parameters.
54 */
55
56 const ScParameterClassification::RawData ScParameterClassification::pRawData[] =
57 {
58 // { OpCode, {{ Type, ... }, nRepeatLast }},
59
60 // IF() and CHOOSE() are somewhat special, since the ScJumpMatrix is
61 // created inside those functions and ConvertMatrixParameters() is not
62 // called for them.
63 { ocIf, {{ Array, Reference, Reference }, 0 }},
64 { ocChose, {{ Array, Reference }, 1 }},
65 // Other specials.
66 { ocOpen, {{ Bounds }, 0 }},
67 { ocClose, {{ Bounds }, 0 }},
68 { ocSep, {{ Bounds }, 0 }},
69 { ocNoName, {{ Bounds }, 0 }},
70 { ocErrCell, {{ Bounds }, 0 }},
71 { ocStop, {{ Bounds }, 0 }},
72 { ocUnion, {{ Reference, Reference }, 0 }},
73 { ocRange, {{ Reference, Reference }, 0 }},
74 // Functions with Value parameters only but not in resource.
75 { ocBackSolver, {{ Value, Value, Value }, 0 }},
76 { ocTableOp, {{ Value, Value, Value, Value, Value }, 0 }},
77 // Operators and functions.
78 { ocAdd, {{ Array, Array }, 0 }},
79 { ocAmpersand, {{ Array, Array }, 0 }},
80 { ocAnd, {{ Reference }, 1 }},
81 { ocAreas, {{ Reference }, 0 }},
82 { ocAveDev, {{ Reference }, 1 }},
83 { ocAverage, {{ Reference }, 1 }},
84 { ocAverageA, {{ Reference }, 1 }},
85 { ocAverageIf, {{ Reference, Value, Reference }, 0 }},
86 { ocAverageIfs, {{ Reference, Reference, Value }, 2 }},
87 { ocCell, {{ Value, Reference }, 0 }},
88 { ocColumn, {{ Reference }, 0 }},
89 { ocColumns, {{ Reference }, 1 }},
90 { ocCorrel, {{ ForceArray, ForceArray }, 0 }},
91 { ocCount, {{ Reference }, 1 }},
92 { ocCount2, {{ Reference }, 1 }},
93 { ocCountEmptyCells, {{ Reference }, 0 }},
94 { ocCountIf, {{ Reference, Value }, 0 }},
95 { ocCountIfs, {{ Reference, Value }, 2 }},
96 { ocCovar, {{ ForceArray, ForceArray }, 0 }},
97 { ocDBAverage, {{ Reference, Reference, Reference }, 0 }},
98 { ocDBCount, {{ Reference, Reference, Reference }, 0 }},
99 { ocDBCount2, {{ Reference, Reference, Reference }, 0 }},
100 { ocDBGet, {{ Reference, Reference, Reference }, 0 }},
101 { ocDBMax, {{ Reference, Reference, Reference }, 0 }},
102 { ocDBMin, {{ Reference, Reference, Reference }, 0 }},
103 { ocDBProduct, {{ Reference, Reference, Reference }, 0 }},
104 { ocDBStdDev, {{ Reference, Reference, Reference }, 0 }},
105 { ocDBStdDevP, {{ Reference, Reference, Reference }, 0 }},
106 { ocDBSum, {{ Reference, Reference, Reference }, 0 }},
107 { ocDBVar, {{ Reference, Reference, Reference }, 0 }},
108 { ocDBVarP, {{ Reference, Reference, Reference }, 0 }},
109 { ocDevSq, {{ Reference }, 1 }},
110 { ocDiv, {{ Array, Array }, 0 }},
111 { ocEqual, {{ Array, Array }, 0 }},
112 { ocForecast, {{ Value, ForceArray, ForceArray }, 0 }},
113 { ocFrequency, {{ Reference, Reference }, 0 }},
114 { ocFTest, {{ ForceArray, ForceArray }, 0 }},
115 { ocGeoMean, {{ Reference }, 1 }},
116 { ocGCD, {{ Reference }, 1 }},
117 { ocGreater, {{ Array, Array }, 0 }},
118 { ocGreaterEqual, {{ Array, Array }, 0 }},
119 { ocGrowth, {{ Reference, Reference, Reference, Value }, 0 }},
120 { ocHarMean, {{ Reference }, 1 }},
121 { ocHLookup, {{ Value, Reference, Value, Value }, 0 }},
122 { ocIRR, {{ Reference, Value }, 0 }},
123 { ocIndex, {{ Reference, Value, Value, Value }, 0 }},
124 { ocIntercept, {{ ForceArray, ForceArray }, 0 }},
125 { ocIntersect, {{ Reference, Reference }, 0 }},
126 { ocIsRef, {{ Reference }, 0 }},
127 { ocLCM, {{ Reference }, 1 }},
128 { ocKurt, {{ Reference }, 1 }},
129 { ocLarge, {{ Reference, Value }, 0 }},
130 { ocLess, {{ Array, Array }, 0 }},
131 { ocLessEqual, {{ Array, Array }, 0 }},
132 { ocLookup, {{ Value, ReferenceOrForceArray, ReferenceOrForceArray }, 0 }},
133 { ocMatch, {{ Value, Reference, Reference }, 0 }},
134 { ocMatDet, {{ ForceArray }, 0 }},
135 { ocMatInv, {{ ForceArray }, 0 }},
136 { ocMatMult, {{ ForceArray, ForceArray }, 0 }},
137 { ocMatTrans, {{ Array }, 0 }}, // strange, but Xcl doesn't force MatTrans array
138 { ocMatValue, {{ Reference, Value, Value }, 0 }},
139 { ocMax, {{ Reference }, 1 }},
140 { ocMaxA, {{ Reference }, 1 }},
141 { ocMedian, {{ Reference }, 1 }},
142 { ocMin, {{ Reference }, 1 }},
143 { ocMinA, {{ Reference }, 1 }},
144 { ocMIRR, {{ Reference, Value, Value }, 0 }},
145 { ocModalValue, {{ ForceArray }, 1 }},
146 { ocMul, {{ Array, Array }, 0 }},
147 { ocMultiArea, {{ Reference }, 1 }},
148 { ocN, {{ Reference }, 0 }},
149 { ocNPV, {{ Value, Reference }, 1 }},
150 { ocNeg, {{ Array }, 0 }},
151 { ocNegSub, {{ Array }, 0 }},
152 { ocNot, {{ Array }, 0 }},
153 { ocNotEqual, {{ Array, Array }, 0 }},
154 { ocOffset, {{ Reference, Value, Value, Value, Value }, 0 }},
155 { ocOr, {{ Reference }, 1 }},
156 { ocPearson, {{ ForceArray, ForceArray }, 0 }},
157 { ocPercentile, {{ Reference, Value }, 0 }},
158 { ocPercentrank, {{ Reference, Value }, 0 }},
159 { ocPow, {{ Array, Array }, 0 }},
160 { ocPower, {{ Array, Array }, 0 }},
161 { ocProb, {{ ForceArray, ForceArray, Value, Value }, 0 }},
162 { ocProduct, {{ Reference }, 1 }},
163 { ocQuartile, {{ Reference, Value }, 0 }},
164 { ocRank, {{ Value, Reference, Value }, 0 }},
165 { ocRGP, {{ Reference, Reference, Value, Value }, 0 }},
166 { ocRKP, {{ Reference, Reference, Value, Value }, 0 }},
167 { ocRow, {{ Reference }, 0 }},
168 { ocRows, {{ Reference }, 1 }},
169 { ocRSQ, {{ ForceArray, ForceArray }, 0 }},
170 { ocSchiefe, {{ Reference }, 1 }},
171 { ocSlope, {{ ForceArray, ForceArray }, 0 }},
172 { ocSmall, {{ Reference, Value }, 0 }},
173 { ocStDev, {{ Reference }, 1 }},
174 { ocStDevA, {{ Reference }, 1 }},
175 { ocStDevP, {{ Reference }, 1 }},
176 { ocStDevPA, {{ Reference }, 1 }},
177 { ocSTEYX, {{ ForceArray, ForceArray }, 0 }},
178 { ocSub, {{ Array, Array }, 0 }},
179 { ocSubTotal, {{ Value, Reference }, 1 }},
180 { ocSum, {{ Reference }, 1 }},
181 { ocSumIf, {{ Reference, Value, Reference }, 0 }},
182 { ocSumIfs, {{ Reference, Reference, Value }, 2 }},
183 { ocSumProduct, {{ ForceArray }, 1 }},
184 { ocSumSQ, {{ Reference }, 1 }},
185 { ocSumX2MY2, {{ ForceArray, ForceArray }, 0 }},
186 { ocSumX2DY2, {{ ForceArray, ForceArray }, 0 }},
187 { ocSumXMY2, {{ ForceArray, ForceArray }, 0 }},
188 { ocTable, {{ Reference }, 0 }},
189 { ocTables, {{ Reference }, 1 }},
190 { ocTrend, {{ Reference, Reference, Reference, Value }, 0 }},
191 { ocTrimMean, {{ Reference, Value }, 0 }},
192 { ocTTest, {{ ForceArray, ForceArray, Value, Value }, 0 }},
193 { ocVar, {{ Reference }, 1 }},
194 { ocVarA, {{ Reference }, 1 }},
195 { ocVarP, {{ Reference }, 1 }},
196 { ocVarPA, {{ Reference }, 1 }},
197 { ocVLookup, {{ Value, Reference, Value, Value }, 0 }},
198 { ocXor, {{ Reference }, 1 }},
199 { ocZTest, {{ Reference, Value, Value }, 0 }},
200 // Excel doubts:
201 // ocT: Excel says (and handles) Reference, error? This means no position
202 // dependent SingleRef if DoubleRef, and no array calculation, just the
203 // upper left corner. We never did that.
204 { ocT, {{ Value }, 0 }},
205 // The stopper.
206 { ocNone, {{ Bounds }, 0 } }
207 };
208
209 ScParameterClassification::RunData * ScParameterClassification::pData = NULL;
210
211
Init()212 void ScParameterClassification::Init()
213 {
214 if ( pData )
215 return;
216 pData = new RunData[ SC_OPCODE_LAST_OPCODE_ID + 1 ];
217 memset( pData, 0, sizeof(RunData) * (SC_OPCODE_LAST_OPCODE_ID + 1));
218
219 // init from specified static data above
220 for ( size_t i=0; i < sizeof(pRawData) / sizeof(RawData); ++i )
221 {
222 const RawData* pRaw = &pRawData[i];
223 if ( pRaw->eOp > SC_OPCODE_LAST_OPCODE_ID )
224 {
225 DBG_ASSERT( pRaw->eOp == ocNone, "RawData OpCode error");
226 }
227 else
228 {
229 RunData* pRun = &pData[ pRaw->eOp ];
230 #ifdef DBG_UTIL
231 if ( pRun->aData.nParam[0] != Unknown )
232 {
233 DBG_ERROR1( "already assigned: %d", pRaw->eOp);
234 }
235 #endif
236 memcpy( &(pRun->aData), &(pRaw->aData), sizeof(CommonData));
237 // fill 0-initialized fields with real values
238 if ( pRun->aData.nRepeatLast )
239 {
240 for ( size_t j=0; j < CommonData::nMaxParams; ++j )
241 {
242 if ( pRun->aData.nParam[j] )
243 pRun->nMinParams = sal::static_int_cast<sal_uInt8>( j+1 );
244 else if (j >= pRun->aData.nRepeatLast)
245 pRun->aData.nParam[j] = pRun->aData.nParam[j - pRun->aData.nRepeatLast];
246 else
247 {
248 DBG_ERROR2( "bad classification: eOp %d, repeated param %d negative offset", pRaw->eOp, j);
249 pRun->aData.nParam[j] = Unknown;
250 }
251 }
252 }
253 else
254 {
255 for ( size_t j=0; j < CommonData::nMaxParams; ++j )
256 {
257 if ( !pRun->aData.nParam[j] )
258 {
259 if ( j == 0 || pRun->aData.nParam[j-1] != Bounds )
260 pRun->nMinParams = sal::static_int_cast<sal_uInt8>( j );
261 pRun->aData.nParam[j] = Bounds;
262 }
263 }
264 if ( !pRun->nMinParams &&
265 pRun->aData.nParam[CommonData::nMaxParams-1] != Bounds)
266 pRun->nMinParams = CommonData::nMaxParams;
267 }
268 for ( size_t j=0; j < CommonData::nMaxParams; ++j )
269 {
270 if ( pRun->aData.nParam[j] == ForceArray || pRun->aData.nParam[j] == ReferenceOrForceArray )
271 {
272 pRun->bHasForceArray = true;
273 break; // for
274 }
275 }
276 }
277 }
278
279 #if OSL_DEBUG_LEVEL > 1
280 GenerateDocumentation();
281 #endif
282 }
283
284
Exit()285 void ScParameterClassification::Exit()
286 {
287 delete [] pData;
288 pData = NULL;
289 }
290
291
GetParameterType(const formula::FormulaToken * pToken,sal_uInt16 nParameter)292 ScParameterClassification::Type ScParameterClassification::GetParameterType(
293 const formula::FormulaToken* pToken, sal_uInt16 nParameter)
294 {
295 OpCode eOp = pToken->GetOpCode();
296 switch ( eOp )
297 {
298 case ocExternal:
299 return GetExternalParameterType( pToken, nParameter);
300 //break;
301 case ocMacro:
302 return Reference;
303 //break;
304 default:
305 {
306 // added to avoid warnings
307 }
308 }
309 if ( 0 <= (short)eOp && eOp <= SC_OPCODE_LAST_OPCODE_ID )
310 {
311 sal_uInt8 nRepeat;
312 Type eType;
313 if ( nParameter < CommonData::nMaxParams )
314 eType = pData[eOp].aData.nParam[nParameter];
315 else if ( (nRepeat = pData[eOp].aData.nRepeatLast) > 0 )
316 {
317 // The usual case is 1 repeated parameter, we don't need to
318 // calculate that on each call.
319 sal_uInt16 nParam = (nRepeat > 1 ?
320 (pData[eOp].nMinParams -
321 ((nParameter - pData[eOp].nMinParams) % nRepeat)) :
322 pData[eOp].nMinParams);
323 return pData[eOp].aData.nParam[nParam];
324 }
325 else
326 eType = Bounds;
327 return eType == Unknown ? Value : eType;
328 }
329 return Unknown;
330 }
331
332
333 ScParameterClassification::Type
GetExternalParameterType(const formula::FormulaToken * pToken,sal_uInt16 nParameter)334 ScParameterClassification::GetExternalParameterType( const formula::FormulaToken* pToken,
335 sal_uInt16 nParameter)
336 {
337 Type eRet = Unknown;
338 // similar to ScInterpreter::ScExternal()
339 sal_uInt16 nIndex;
340 String aUnoName;
341 String aFuncName( ScGlobal::pCharClass->upper( pToken->GetExternal()));
342 if ( ScGlobal::GetFuncCollection()->SearchFunc( aFuncName, nIndex) )
343 {
344 FuncData* pFuncData = (FuncData*)ScGlobal::GetFuncCollection()->At(
345 nIndex);
346 if ( nParameter >= pFuncData->GetParamCount() )
347 eRet = Bounds;
348 else
349 {
350 switch ( pFuncData->GetParamType( nParameter) )
351 {
352 case PTR_DOUBLE:
353 case PTR_STRING:
354 eRet = Value;
355 break;
356 default:
357 eRet = Reference;
358 // also array types are created using an area reference
359 }
360 }
361 }
362 else if ( (aUnoName = ScGlobal::GetAddInCollection()->FindFunction(
363 aFuncName, sal_False)).Len() )
364 {
365 // the relevant parts of ScUnoAddInCall without having to create one
366 const ScUnoAddInFuncData* pFuncData =
367 ScGlobal::GetAddInCollection()->GetFuncData( aUnoName, true ); // need fully initialized data
368 if ( pFuncData )
369 {
370 long nCount = pFuncData->GetArgumentCount();
371 if ( nCount <= 0 )
372 eRet = Bounds;
373 else
374 {
375 const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
376 if ( nParameter >= nCount &&
377 pArgs[nCount-1].eType == SC_ADDINARG_VARARGS )
378 eRet = Value;
379 // last arg is sequence, optional "any"s, we simply can't
380 // determine the type
381 if ( eRet == Unknown )
382 {
383 if ( nParameter >= nCount )
384 eRet = Bounds;
385 else
386 {
387 switch ( pArgs[nParameter].eType )
388 {
389 case SC_ADDINARG_INTEGER:
390 case SC_ADDINARG_DOUBLE:
391 case SC_ADDINARG_STRING:
392 eRet = Value;
393 break;
394 default:
395 eRet = Reference;
396 }
397 }
398 }
399 }
400 }
401 }
402 return eRet;
403 }
404
405 //-----------------------------------------------------------------------------
406
407 #if OSL_DEBUG_LEVEL > 1
408
409 // add remaining functions, all Value parameters
MergeArgumentsFromFunctionResource()410 void ScParameterClassification::MergeArgumentsFromFunctionResource()
411 {
412 ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
413 for ( const ScFuncDesc* pDesc = pFuncList->First(); pDesc;
414 pDesc = pFuncList->Next() )
415 {
416 if ( pDesc->nFIndex > SC_OPCODE_LAST_OPCODE_ID ||
417 pData[pDesc->nFIndex].aData.nParam[0] != Unknown )
418 continue; // not an internal opcode or already done
419
420 RunData* pRun = &pData[ pDesc->nFIndex ];
421 sal_uInt16 nArgs = pDesc->GetSuppressedArgCount();
422 if ( nArgs >= PAIRED_VAR_ARGS )
423 {
424 nArgs -= PAIRED_VAR_ARGS - 2;
425 pRun->aData.nRepeatLast = 2;
426 }
427 else if ( nArgs >= VAR_ARGS )
428 {
429 nArgs -= VAR_ARGS - 1;
430 pRun->aData.nRepeatLast = 1;
431 }
432 if ( nArgs > CommonData::nMaxParams )
433 {
434 DBG_ERROR2( "ScParameterClassification::Init: too many arguments in listed function: %s: %d",
435 ByteString( *(pDesc->pFuncName),
436 RTL_TEXTENCODING_UTF8).GetBuffer(), nArgs);
437 nArgs = CommonData::nMaxParams - 1;
438 pRun->aData.nRepeatLast = 1;
439 }
440 pRun->nMinParams = static_cast< sal_uInt8 >( nArgs );
441 for ( size_t j=0; j < nArgs; ++j )
442 {
443 pRun->aData.nParam[j] = Value;
444 }
445 if ( pRun->aData.nRepeatLast )
446 {
447 for ( size_t j = nArgs; j < CommonData::nMaxParams; ++j )
448 {
449 pRun->aData.nParam[j] = Value;
450 }
451 }
452 else
453 {
454 for ( size_t j = nArgs; j < CommonData::nMaxParams; ++j )
455 {
456 pRun->aData.nParam[j] = Bounds;
457 }
458 }
459 }
460 }
461
462
GenerateDocumentation()463 void ScParameterClassification::GenerateDocumentation()
464 {
465 static const sal_Char aEnvVarName[] = "OOO_CALC_GENPARCLASSDOC";
466 if ( !getenv( aEnvVarName) )
467 return;
468 MergeArgumentsFromFunctionResource();
469 ScAddress aAddress;
470 ScCompiler aComp(NULL,aAddress);
471 ScCompiler::OpCodeMapPtr xMap( aComp.GetOpCodeMap(::com::sun::star::sheet::FormulaLanguage::ENGLISH));
472 if (!xMap)
473 return;
474 fflush( stderr);
475 size_t nCount = xMap->getSymbolCount();
476 for ( size_t i=0; i<nCount; ++i )
477 {
478 OpCode eOp = OpCode(i);
479 if ( xMap->getSymbol(eOp).Len() )
480 {
481 fprintf( stdout, "%s: ", aEnvVarName);
482 ByteString aStr( xMap->getSymbol(eOp), RTL_TEXTENCODING_UTF8);
483 aStr += "(";
484 formula::FormulaByteToken aToken( eOp);
485 sal_uInt8 nParams = GetMinimumParameters( eOp);
486 // preset parameter count according to opcode value, with some
487 // special handling
488 if ( eOp < SC_OPCODE_STOP_DIV )
489 {
490 switch ( eOp )
491 {
492 case ocIf:
493 aToken.SetByte(3);
494 break;
495 case ocChose:
496 aToken.SetByte(2);
497 break;
498 case ocPercentSign:
499 aToken.SetByte(1);
500 break;
501 default:;
502 }
503 }
504 else if ( eOp < SC_OPCODE_STOP_ERRORS )
505 aToken.SetByte(0);
506 else if ( eOp < SC_OPCODE_STOP_BIN_OP )
507 {
508 switch ( eOp )
509 {
510 case ocAnd:
511 case ocOr:
512 aToken.SetByte(1); // (r1)AND(r2) --> AND( r1, ...)
513 break;
514 default:
515 aToken.SetByte(2);
516 }
517 }
518 else if ( eOp < SC_OPCODE_STOP_UN_OP )
519 aToken.SetByte(1);
520 else if ( eOp < SC_OPCODE_STOP_NO_PAR )
521 aToken.SetByte(0);
522 else if ( eOp < SC_OPCODE_STOP_1_PAR )
523 aToken.SetByte(1);
524 else
525 aToken.SetByte( nParams);
526 // compare (this is a mere test for opcode order Div, BinOp, UnOp,
527 // NoPar, 1Par, ...) and override parameter count with
528 // classification
529 if ( nParams != aToken.GetByte() )
530 fprintf( stdout, "(parameter count differs, token Byte: %d classification: %d) ",
531 aToken.GetByte(), nParams);
532 aToken.SetByte( nParams);
533 if ( nParams != aToken.GetParamCount() )
534 fprintf( stdout, "(parameter count differs, token ParamCount: %d classification: %d) ",
535 aToken.GetParamCount(), nParams);
536 for ( sal_uInt16 j=0; j < nParams; ++j )
537 {
538 if ( j > 0 )
539 aStr += ",";
540 Type eType = GetParameterType( &aToken, j);
541 switch ( eType )
542 {
543 case Value :
544 aStr += " Value";
545 break;
546 case Reference :
547 aStr += " Reference";
548 break;
549 case Array :
550 aStr += " Array";
551 break;
552 case ForceArray :
553 aStr += " ForceArray";
554 break;
555 case ReferenceOrForceArray :
556 aStr += " ReferenceOrForceArray";
557 break;
558 case Bounds :
559 aStr += " (Bounds, classification error?)";
560 break;
561 default:
562 aStr += " (???, classification error?)";
563 }
564 }
565 if ( HasRepeatParameters( eOp) )
566 aStr += ", ...";
567 if ( nParams )
568 aStr += " ";
569 aStr += ")";
570 switch ( eOp )
571 {
572 case ocZGZ:
573 aStr += " // RRI in English resource, but ZGZ in English-only section";
574 break;
575 case ocMultiArea:
576 aStr += " // e.g. combined first parameter of INDEX() function, not a real function";
577 break;
578 case ocBackSolver:
579 aStr += " // goal seek via menu, not a real function";
580 break;
581 case ocTableOp:
582 aStr += " // MULTIPLE.OPERATIONS in English resource, but TABLE in English-only section";
583 break;
584 case ocNoName:
585 aStr += " // error function, not a real function";
586 break;
587 default:;
588 }
589 fprintf( stdout, "%s\n", aStr.GetBuffer());
590 }
591 }
592 fflush( stdout);
593 }
594
595 #endif // OSL_DEBUG_LEVEL
596
597