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