xref: /trunk/main/sc/source/filter/qpro/qproform.cxx (revision b77af630)
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_scfilt.hxx"
26 
27 #include <sal/config.h>
28 #include "qpro.hxx"
29 
30 #include "qproform.hxx"
31 #include "formel.hxx"
32 #include "compiler.hxx"
33 #include <tokstack.hxx>
34 #include "ftools.hxx"
35 
ReadSRD(ScSingleRefData & rSRD,sal_Int8 nPage,sal_Int8 nCol,sal_uInt16 nRelBit)36 void QProToSc::ReadSRD( ScSingleRefData& rSRD, sal_Int8 nPage, sal_Int8 nCol, sal_uInt16 nRelBit )
37 {
38     sal_uInt16 nTmp = nRelBit & 0x1fff;
39     rSRD.InitAddress( ScAddress( nCol, (~nTmp + 1), 0 ) );
40     if( nRelBit & 0x4000 )
41     {
42         rSRD.nRelCol = nCol;
43         rSRD.SetColRel( sal_True );
44     }
45     else
46     {
47         rSRD.nCol = nCol;
48         rSRD.SetColRel( sal_False );
49     }
50     if( nRelBit & 0x2000 )
51     {
52         rSRD.nRelRow = (~nTmp + 1);
53         rSRD.nRelRow = (sal_Int16)(nTmp << 3);
54         rSRD.nRelRow /= 8;
55         rSRD.SetRowRel( sal_True );
56     }
57     else
58     {
59         rSRD.nRow = nTmp;
60         rSRD.SetRowRel( sal_False );
61     }
62     if( nRelBit & 0x8000 )
63     {
64         rSRD.nRelTab = nPage;
65         rSRD.SetTabRel( sal_True );
66         // absolute tab needed in caller for comparison in case of DoubleRef
67         rSRD.nTab = aEingPos.Tab() + nPage;
68     }
69     else
70     {
71         rSRD.nTab = nPage;
72         rSRD.SetTabRel( sal_False );
73     }
74     if (rSRD.nTab != aEingPos.Tab())
75         rSRD.SetFlag3D( sal_True);
76 }
77 
QProToSc(SvStream & rStream,const ScAddress & rRefPos)78 QProToSc::QProToSc( SvStream& rStream, const ScAddress& rRefPos ) :
79     ConverterBase( 128 ),
80     maIn( rStream )
81 {
82     aEingPos = rRefPos;
83 }
84 
DoFunc(DefTokenId eOc,sal_uInt16 nArgs,const sal_Char * pExtString)85 void QProToSc::DoFunc( DefTokenId eOc, sal_uInt16 nArgs, const sal_Char* pExtString )
86 {
87     TokenId  eParam[ nBufSize ];
88     sal_Int32    nCount;
89     TokenId  nPush, nPush1;
90 
91     sal_Bool bAddIn = sal_False;
92     sal_Bool bNeg = sal_False;
93 
94     if( eOc == ocNoName )
95     {
96         bAddIn = sal_True;
97         if( pExtString )
98         {
99             ByteString s;
100             s = pExtString;
101             s.Insert( "QPRO_", 0 );
102             nPush = aPool.Store( eOc, String( s, maIn.GetStreamCharSet() ) );
103             aPool << nPush;
104         }
105         else
106             aPool << ocNoName;
107     }
108 
109     if( nArgs < nBufSize )
110     {
111         for( nCount = 0; nCount < nArgs ; nCount++ )
112             aStack >> eParam[ nCount ];
113     }
114     else
115         return;
116 
117     switch( eOc )
118     {
119         case ocIndex:
120             nPush = eParam[ 0 ];
121             eParam[ 0 ] = eParam[ 1 ];
122             eParam[ 1 ] = nPush;
123             IncToken( eParam[ 0 ] );
124             IncToken( eParam[ 1 ] );
125             break;
126 
127         case ocIRR:
128             nPush = eParam[ 0 ];
129             eParam[ 0 ] = eParam[ 1 ];
130             eParam[ 1 ] = nPush;
131             break;
132 
133         case ocGetYear:
134             nPush = aPool.Store( 1900.0 );
135             aPool << ocOpen;
136             break;
137 
138         default:
139             break;
140     }
141 
142     if( !bAddIn )
143         aPool << eOc;
144 
145     aPool << ocOpen;
146 
147     if( nArgs> 0 )
148     {
149         sal_Int16 nNull = -1;
150         sal_Int16 nLast = nArgs- 1;
151 
152         if( eOc == ocZGZ )
153             aPool << eParam[ 2 ] << ocSep << eParam[ 1 ] << ocSep << eParam[ 0 ];
154         if( eOc == ocZinsZ )
155             aPool << eParam[ 3 ] << ocSep << eParam[ 2 ] << ocSep << eParam[ 1 ] << ocSep << eParam[ 0 ];
156         else
157         {
158             aPool << eParam[ nLast ];
159             for( nCount = nLast - 1 ; nCount >= 0 ; nCount-- )
160             {
161                 if( nCount != nNull )
162                     aPool << ocSep << eParam[ nCount ];
163             }
164         }
165     }
166 
167     if( eOc == ocGetYear )
168         aPool << ocClose << ocSub << nPush;
169     else if( eOc == ocFixed )
170         aPool << ocSep << ocTrue << ocOpen << ocClose;
171 
172     aPool << ocClose;
173     aPool >> aStack;
174 
175     if( bNeg )
176     {
177         aPool << ocOpen << ocSub << aStack << ocClose;
178         aPool >> aStack;
179     }
180 }
181 
IncToken(TokenId & rParam)182 void QProToSc::IncToken( TokenId &rParam )
183 {
184     aPool << ocOpen << rParam << mnAddToken;
185     rParam = aPool.Store();
186 }
187 
188 #define SAFEDEC_OR_RET(nRef, amt, ret) \
189 do { \
190     if (nRef < amt)\
191         return ret; \
192     nRef-=amt; \
193 } while(0)
194 
Convert(const ScTokenArray * & pArray,sal_uInt16,const FORMULA_TYPE)195 ConvErr QProToSc::Convert( const ScTokenArray*& pArray, sal_uInt16 /*nLen*/, const FORMULA_TYPE /*eFT*/ )
196 {
197     sal_uInt8 nFmla[ nBufSize ], i, nArg, nArgArray[ nBufSize ];
198     sal_Int8 nCol, nPage;
199     sal_uInt16 nInt, nIntCount = 0, nStringCount = 0, nFloatCount = 0, nDLLCount = 0, nIntArray[ nBufSize ], nArgCount = 0;
200     String sStringArray[ nBufSize ];
201     sal_uInt16 nDummy, nDLLId, nDLLArray[ nBufSize ];
202     sal_uInt16 nNote, nRef, nRelBits;
203     TokenId nPush;
204     ScComplexRefData aCRD;
205     ScSingleRefData aSRD;
206     FUNC_TYPE eType;
207     DefTokenId eOc;
208     double nFloatArray[ nBufSize ], nFloat;
209     const sal_Char* pExtString = 0;
210 
211     aCRD.InitFlags();
212     aSRD.InitFlags();
213     maIn >> nRef;
214 
215     if( nRef < nBufSize )
216     {
217         for( i=0; i < nRef; i++)
218         {
219             maIn >> nFmla[i];
220 
221             if( nFmla[ i ] == 0x05 )
222             {
223                 maIn >> nInt;
224                 nIntArray[ nIntCount ] = nInt;
225 		SAFEDEC_OR_RET(nRef, 2, ConvErrCount);
226                 nIntCount++;
227             }
228 
229             if( nFmla[ i ] == 0x00 )
230             {
231                 maIn >> nFloat;
232                 nFloatArray[ nFloatCount ] = nFloat;
233 		SAFEDEC_OR_RET(nRef, 8, ConvErrCount);
234                 nFloatCount++;
235             }
236 
237             if( nFmla[ i ] == 0x1a )
238             {
239                 maIn >> nArg >> nDummy >> nDLLId;
240                 nArgArray[ nArgCount ] = nArg;
241                 nDLLArray[ nDLLCount ] = nDLLId;
242 		SAFEDEC_OR_RET(nRef, 5, ConvErrCount);
243                 nDLLCount++;
244                 nArgCount++;
245             }
246             if( nFmla[ i ] == 0x06 )
247             {
248                 String aTmp( ScfTools::ReadCString( maIn ), maIn.GetStreamCharSet() );
249                 sStringArray[ nStringCount ] = aTmp;
250                 nStringCount++;
251 		SAFEDEC_OR_RET(nRef, aTmp.Len() + 1, ConvErrCount);
252             }
253         }
254     }
255     else
256         return ConvErrCount;
257 
258     i = 0, nIntCount = 0, nFloatCount = 0, nDLLCount = 0, nArgCount = 0, nStringCount =0;
259 
260     while( i < nRef && ( nFmla[ i ] != 0x03 ) )
261     {
262         eType = IndexToType( nFmla[ i ] );
263         eOc = IndexToToken( nFmla[ i ] );
264         if( eOc == ocNoName )
265             pExtString = getString( nFmla[ i ] );
266 
267         switch( eType )
268         {
269             case FT_NotImpl:
270                 DoFunc( ocNoName, 0, pExtString );
271                 break;
272 
273             case FT_FuncFix0:
274                 DoFunc( eOc, 0, NULL );
275                 break;
276 
277             case FT_FuncFix1:
278                 DoFunc( eOc, 1, NULL );
279                 break;
280 
281             case FT_FuncFix2:
282                 DoFunc( eOc, 2, NULL );
283                 break;
284 
285             case FT_FuncFix3:
286                 DoFunc( eOc, 3, NULL );
287                 break;
288 
289             case FT_FuncFix4:
290                 DoFunc( eOc, 4, NULL );
291                 break;
292 
293             case FT_FuncFix5:
294                 DoFunc( eOc, 5, NULL );
295                 break;
296 
297             case FT_FuncFix6:
298                 DoFunc( eOc, 6, NULL );
299                 break;
300 
301             case FT_DLL:{
302                 eOc = IndexToDLLId( nDLLArray[ nDLLCount ] );
303                 sal_uInt8 nPar = nArgArray[ nArgCount ];
304                 DoFunc( eOc, nPar, NULL );
305                 nDLLCount++;
306                 nArgCount++;
307                 }
308                 break;
309 
310             case FT_Cref : // Single cell reference
311                 maIn >> nNote >> nCol >> nPage >> nRelBits;
312                 ReadSRD( aSRD, nPage, nCol, nRelBits );
313                 aStack << aPool.Store( aSRD );
314                 break;
315 
316             case FT_Range: // Block reference
317                 maIn >> nNote >> nCol >> nPage >> nRelBits;
318                 ReadSRD( aCRD.Ref1, nPage, nCol, nRelBits );
319                 maIn >> nCol >> nPage >> nRelBits;
320                 ReadSRD( aCRD.Ref2, nPage, nCol, nRelBits );
321                 // Sheet name of second corner is not displayed if identical
322                 if (aCRD.Ref1.IsFlag3D() && aCRD.Ref1.nTab == aCRD.Ref2.nTab &&
323                         aCRD.Ref1.IsTabRel() == aCRD.Ref2.IsTabRel())
324                     aCRD.Ref2.SetFlag3D( sal_False);
325                 aStack << aPool.Store( aCRD );
326                 break;
327 
328             case FT_FuncVar:{ // Sum of a sequence of numbers
329                 sal_uInt8 nArgs;
330                 i++;
331                 nArgs = nFmla[ i ];
332                 DoFunc( eOc, nArgs, NULL );
333                 }
334                 break;
335 
336             case FT_Op: // operators
337                 aStack >> nPush;
338                 aPool << aStack << eOc << nPush;
339                 aPool >> aStack;
340                 break;
341 
342             case FT_Braces:
343                 aPool << ocOpen << aStack << ocClose;
344                 aPool >> aStack;
345                 break;
346 
347             case FT_ConstInt:{
348                 sal_uInt16 nVal;
349                 nVal = nIntArray[ nIntCount ];
350                 aStack << aPool.Store( ( double ) nVal );
351                 nIntCount++;
352                 }
353                 break;
354 
355             case FT_ConstFloat:{
356                 double nVal;
357                 nVal = nFloatArray[ nFloatCount ];
358                 aStack << aPool.Store( nVal );
359                 nFloatCount++;
360                 }
361                 break;
362 
363             case FT_ConstString:{
364                 String aLabel;
365                 aLabel = sStringArray[ nStringCount ];
366                 aStack << aPool.Store( aLabel );
367                 nStringCount++;
368                 }
369                 break;
370 
371             case FT_Neg:
372                 aPool <<  ocNegSub << aStack;
373                 aPool >> aStack;
374                 break;
375 
376             case FT_NOP:    // indicates invalid opcode.
377             case FT_Return: // indicates end of formula
378                 break;
379         }
380         i++;
381     }
382     pArray = aPool[ aStack.Get() ];
383     return ConvOK;
384 }
385 
386 static const struct
387 {
388     DefTokenId nToken;
389     FUNC_TYPE   nType;
390 } aFuncMap[] = {
391     { ocPush, FT_ConstFloat },
392     { ocPush, FT_Cref },
393     { ocPush, FT_Range },
394     { ocPush, FT_Return },
395     { ocPush, FT_Braces },
396     { ocPush, FT_ConstInt },
397     { ocPush, FT_ConstString },
398     { ocPush, FT_NOP },
399 	{ ocNegSub, FT_Neg },                       // 0x08
400     { ocAdd, FT_Op },
401     { ocSub, FT_Op },
402     { ocMul, FT_Op },
403     { ocDiv, FT_Op },
404     { ocPow, FT_Op },
405     { ocEqual, FT_Op },
406     { ocNotEqual, FT_Op },
407 	{ ocLessEqual, FT_Op },                     // 0x10
408     { ocGreaterEqual, FT_Op },
409     { ocLess, FT_Op },
410     { ocGreater, FT_Op },
411     { ocAnd, FT_Op },
412     { ocOr, FT_Op },
413     { ocNot, FT_FuncFix1 },
414     { ocPush, FT_NOP }, 	// Unary plus
415     { ocAddress, FT_FuncFix4 }, // Address of
416     { ocNoName, FT_NotImpl }, // Halt function
417     { ocNoName, FT_DLL }, // DLL function
418     { ocNoName, FT_NOP }, // Extended operands
419     { ocNoName, FT_NOP }, // Extended operands
420     { ocNoName, FT_NOP }, // Reserved
421     { ocNoName, FT_NOP }, // Reserved
422     { ocNotAvail, FT_FuncFix0 }, // NA
423     { ocNoName, FT_FuncFix0 }, // Error         // 0x20
424     { ocAbs, FT_FuncFix1 },
425     { ocInt, FT_FuncFix1 },
426     { ocSqrt, FT_FuncFix1 },
427     { ocLog10, FT_FuncFix1 },
428     { ocLn, FT_FuncFix1 },
429     { ocPi, FT_FuncFix0 },
430     { ocSin, FT_FuncFix1 },
431     { ocCos, FT_FuncFix1 },
432     { ocTan, FT_FuncFix1 },
433     { ocArcTan2, FT_FuncFix2 },
434     { ocArcTan, FT_FuncFix1 },
435     { ocArcSin, FT_FuncFix1 },
436     { ocArcCos, FT_FuncFix1 },
437     { ocExp, FT_FuncFix1 },
438     { ocMod, FT_FuncFix2 },
439 	{ ocChose, FT_FuncVar },                    // 0x30
440     { ocIsNA, FT_FuncFix1 },
441     { ocIsError, FT_FuncFix1 },
442     { ocFalse, FT_FuncFix0 },
443     { ocTrue, FT_FuncFix0 },
444     { ocRandom, FT_FuncFix0 },
445     { ocGetDate, FT_FuncFix3 },
446     { ocGetActTime, FT_FuncFix0 },
447     { ocNoName, FT_NotImpl },    // QPro Pmt
448     { ocNoName, FT_NotImpl },    // QPro Pv
449     { ocNoName, FT_NotImpl },    // QPro Fv
450     { ocIf, FT_FuncFix3 },
451     { ocGetDay, FT_FuncFix1 },
452     { ocGetMonth, FT_FuncFix1 },
453     { ocGetYear, FT_FuncFix1 },
454     { ocRound, FT_FuncFix2 },
455     { ocGetTime, FT_FuncFix3 },                  // 0x40
456     { ocGetHour, FT_FuncFix1 },
457     { ocGetMin, FT_FuncFix1 },
458     { ocGetSec, FT_FuncFix1 },
459     { ocIsValue, FT_FuncFix1 },
460     { ocIsString, FT_FuncFix1 },
461     { ocLen, FT_FuncFix1 },
462     { ocValue, FT_FuncFix1 },
463     { ocFixed, FT_FuncFix2 },
464     { ocMid, FT_FuncFix3 },
465     { ocChar, FT_FuncFix1 },
466     { ocCode, FT_FuncFix1 },
467     { ocFind, FT_FuncFix3 },
468     { ocGetDateValue, FT_FuncFix1 },
469     { ocGetTimeValue, FT_FuncFix1 },
470     { ocNoName, FT_NotImpl },
471 	{ ocSum, FT_FuncVar },                     // 0x50
472     { ocAverage, FT_FuncVar },
473     { ocCount, FT_FuncVar },
474     { ocMin, FT_FuncVar },
475     { ocMax, FT_FuncVar },
476     { ocVLookup, FT_FuncFix3 },
477     { ocNPV, FT_FuncFix2 },
478     { ocVar, FT_FuncVar },
479     { ocNormDist, FT_FuncVar },
480     { ocIRR, FT_FuncFix2 },
481     { ocHLookup, FT_FuncFix3 },
482     { ocDBSum, FT_FuncFix3 },
483     { ocDBAverage, FT_FuncFix3 },
484     { ocDBCount, FT_FuncFix3 },
485     { ocDBMin, FT_FuncFix3 },
486     { ocDBMax, FT_FuncFix3 },
487 	{ ocDBVar, FT_FuncFix3 },                 // 0x60
488     { ocDBStdDev, FT_FuncFix3 },
489     { ocNoName, FT_NotImpl },
490     { ocColumns, FT_FuncFix1 },
491     { ocRows, FT_FuncFix1 },
492     { ocRept, FT_FuncFix2 },
493     { ocUpper, FT_FuncFix1 },
494     { ocLower, FT_FuncFix1 },
495     { ocLeft, FT_FuncFix2 },
496     { ocRight, FT_FuncFix2 },
497     { ocReplace, FT_FuncFix4 },
498     { ocPropper, FT_FuncFix1 },
499     { ocCell, FT_FuncFix2 },
500     { ocTrim, FT_FuncFix1 },
501     { ocClean, FT_FuncFix1 },
502     { ocNoName, FT_NotImpl },
503     { ocNoName, FT_NotImpl },               // 0x70
504     { ocExact, FT_FuncFix2 },
505     { ocNoName, FT_NotImpl }, // Call()
506     { ocIndirect, FT_FuncFix1 },
507     { ocZGZ, FT_FuncFix3 }, // Interest
508     { ocNoName, FT_NotImpl },
509     { ocNoName, FT_NotImpl },
510     { ocLIA, FT_FuncFix3 },
511     { ocDIA, FT_FuncFix4 },
512     { ocGDA, FT_FuncFix4 },
513     { ocStDevP, FT_FuncVar },
514     { ocVarP, FT_FuncVar },
515     { ocDBStdDevP, FT_FuncVar },
516     { ocDBVarP, FT_FuncVar },
517     { ocBW, FT_FuncFix3 },  // QPro Pval
518     { ocRMZ, FT_FuncFix5 }, // QPro Paymt
519     { ocZW, FT_FuncFix3 },  // QPro Fval   // 0x80
520     { ocZZR, FT_FuncFix5 },
521     { ocZins, FT_FuncFix5 },
522     { ocZinsZ, FT_FuncFix4 },
523     { ocKapz, FT_FuncFix6 },
524     { ocSumProduct, FT_FuncFix2 },
525     { ocNoName, FT_NotImpl },
526     { ocNoName, FT_NotImpl },
527     { ocNoName, FT_NotImpl },
528     { ocNoName, FT_NotImpl },
529     { ocDeg, FT_FuncFix1 },
530     { ocRad, FT_FuncFix1 },
531     { ocNoName, FT_NotImpl },
532     { ocNoName, FT_NotImpl },
533     { ocGetActDate, FT_FuncFix0 },
534     { ocNPV, FT_FuncFix2 },
535     { ocNoName, FT_NotImpl }, 				 // 0x90
536     { ocNoName, FT_NotImpl },
537     { ocNoName, FT_NOP },
538     { ocNoName, FT_NOP }, // 147
539     { ocNoName, FT_NOP }, // 148
540     { ocNoName, FT_NOP }, // 149
541     { ocNoName, FT_NOP }, // 150
542     { ocNoName, FT_NOP }, // 151
543     { ocNoName, FT_NOP }, // 152
544     { ocNoName, FT_NOP }, // 153
545     { ocTable, FT_FuncFix1 },
546     { ocNoName, FT_NOP }, // 155 - opcodes do not represent any function.
547     { ocNoName, FT_NOP }, // 156
548     { ocIndex,  FT_FuncFix4 },
549     { ocNoName, FT_NotImpl },
550     { ocNoName, FT_NotImpl }, // Gives the property of the particular object
551     { ocNoName, FT_NotImpl },  // Dynamic Data Exchange Link // 0x100
552     { ocNoName, FT_NotImpl }   // gives properties of DOS menus
553 };
554 
555 const int nIndexCount = sizeof( aFuncMap ) / sizeof( aFuncMap[ 0 ] );
556 
IndexToToken(sal_uInt16 nIndex)557 DefTokenId QProToSc::IndexToToken( sal_uInt16 nIndex )
558 {
559     if( nIndex < nIndexCount )
560         return aFuncMap[ nIndex ].nToken;
561     return ocNoName;
562 }
563 
IndexToType(sal_uInt8 nIndex)564 FUNC_TYPE QProToSc::IndexToType( sal_uInt8 nIndex )
565 {
566     if( nIndex < nIndexCount )
567         return aFuncMap[ nIndex ].nType;
568     return FT_NotImpl;
569 }
570 
IndexToDLLId(sal_uInt16 nIndex)571 DefTokenId QProToSc::IndexToDLLId( sal_uInt16 nIndex )
572 {
573     DefTokenId eId;
574     switch( nIndex )
575     {
576         case 0x0001:
577             eId = ocAveDev;
578             break;
579 
580         case 0x0024:
581             eId = ocGCD;
582             break;
583 
584         case 0x0025:
585             eId = ocLCM;
586             break;
587 
588         case 0x0027:
589             eId = ocCeil;
590             break;
591 
592         case 0x0028:
593             eId = ocEven;
594             break;
595 
596         case 0x0022:
597             eId = ocFact;
598             break;
599 
600         case 0x002a:
601             eId = ocFloor;
602             break;
603 
604         case 0x002d:
605             eId = ocOdd;
606             break;
607 
608         case 0x0006:
609             eId = ocBetaDist;
610             break;
611 
612         case 0x0008:
613             eId = ocBetaInv;
614             break;
615 
616         case 0x0010:
617             eId = ocCovar;
618             break;
619 
620         case 0x000b:
621             eId = ocChiInv;
622             break;
623 
624         case 0x003d:
625             eId = ocLaufz;
626             break;
627 
628         case 0x0019:
629             eId = ocFInv;
630             break;
631 
632         case 0x001a:
633             eId = ocFisher;
634             break;
635 
636         case 0x001b:
637             eId = ocFisherInv;
638             break;
639 
640         case 0x0030:
641             eId = ocMedian;
642             break;
643 
644         default:
645             eId = ocNoName;
646             break;
647     }
648     return eId;
649 }
650 
getString(sal_uInt8 nIndex)651 const sal_Char* QProToSc::getString( sal_uInt8 nIndex )
652 {
653     const sal_Char* pExtString = 0;
654     switch( nIndex )
655     {
656         case 57:
657             pExtString = "Pv";
658             break;
659 
660         case 58:
661             pExtString = "Fv";
662             break;
663 
664 		case 98:
665 			pExtString = "Index2D";
666 			break;
667 
668         case 111:
669             pExtString = "S";
670             break;
671 
672         case 112:
673             pExtString = "N";
674             break;
675 
676         case 114:
677             pExtString = "CALL";
678             break;
679 
680         case 117:
681             pExtString = "TERM";
682             break;
683 
684         case 118:
685             pExtString = "CTERM";
686             break;
687 
688         case 134:
689             pExtString = "MEMAVAIL";
690             break;
691 
692         case 135:
693             pExtString = "MEMEMSAVAIL";
694             break;
695 
696         case 136:
697             pExtString = "FILEEXISTS";
698             break;
699 
700         case 137:
701             pExtString = "CURVALUE";
702             break;
703 
704         case 140:
705             pExtString = "HEX";
706             break;
707 
708         case 141:
709             pExtString = "NUM";
710             break;
711 
712         case 145:
713             pExtString = "VERSION";
714             break;
715 
716         case 157:
717             pExtString = "INDEX3D";
718             break;
719 
720         case 158:
721             pExtString = "CELLINDEX3D";
722             break;
723 
724         case 159:
725             pExtString = "PROPERTY";
726             break;
727 
728         case 160:
729             pExtString = "DDE";
730             break;
731 
732         case 161:
733             pExtString = "COMMAND";
734             break;
735 
736         default:
737             pExtString = NULL;
738             break;
739     }
740     return pExtString;
741 }
742