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