xref: /trunk/main/basic/source/classes/disas.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_basic.hxx"
30 
31 #include <stdio.h>
32 #include <string.h>
33 #include <tools/stream.hxx>
34 #include <basic/sbx.hxx>
35 #include "sb.hxx"
36 #include "iosys.hxx"
37 #include "disas.hxx"
38 #include "sbtrace.hxx"
39 
40 
41 static const char* pOp1[] = {
42 	"NOP",
43 
44 	// Operators
45 	// the following operators have the same order as in
46 	// enum SbxVarOp
47 	"EXP", "MUL", "DIV", "MOD", "PLUS", "MINUS", "NEG",
48 	"EQ", "NE", "LT", "GT", "LE", "GE",
49 	"IDIV", "AND", "OR", "XOR", "EQV", "IMP", "NOT",
50 	"CAT",
51 	// End enum SbxVarOp
52 	"LIKE", "IS",
53 	// Load/Store
54 	"ARGC",             // Create new Argv
55 	"ARGV",             // TOS ==> current Argv
56 	"INPUT",            // Input ==> TOS
57 	"LINPUT",           // Line Input ==> TOS
58 	"GET",              // get TOS
59 	"SET",              // Save Object TOS ==> TOS-1
60 	"PUT",              // TOS ==> TOS-1
61 	"CONST",            // TOS ==> TOS-1, then ReadOnly
62 	"DIM",              // DIM
63 	"REDIM",            // REDIM
64 	"REDIMP",           // REDIM PRESERVE
65 	"ERASE",            // delete TOS
66 	// Branch
67 	"STOP",             // End of program
68 	"INITFOR",          // FOR-Variable init
69 	"NEXT",             // FOR-Variable increment
70 	"CASE",             // Begin CASE
71 	"ENDCASE",          // End CASE
72 	"STDERR",           // Default error handling
73 	"NOERROR",          // No error handling
74 	"LEAVE",            // leave UP
75 	// I/O
76 	"CHANNEL",          // TOS = Channelnumber
77 	"PRINT",            // print TOS
78 	"PRINTF",           // print TOS in field
79 	"WRITE",            // write TOS
80 	"RENAME",           // Rename Tos+1 to Tos
81 	"PROMPT",           // TOS = Prompt for Input
82 	"RESTART",          // Define restart point
83 	"STDIO",            // Switch to I/O channel 0
84 	// Misc
85 	"EMPTY",            // Empty statement to stack
86 	"ERROR",            // TOS = error code
87 	"LSET",             // Save object TOS ==> TOS-1
88 	"RSET",             // Save object TOS ==> TOS-1 (TODO: Same as above?)
89     "REDIMP_ERASE",
90     "INITFOREACH",
91 	"VBASET",
92 	"ERASE_CLEAR",
93 	"ARRAYACCESS",
94 	"BYVAL"
95 };
96 
97 static const char* pOp2[] = {
98 	"NUMBER",            // Load a numeric constant (+ID)
99 	"STRING",            // Load a string constant (+ID)
100 	"CONSTANT",          // Immediate Load (+value)
101 	"ARGN",              // Save named args in argv (+StringID)
102 	"PAD",               // Pad String to defined length (+length)
103 	// Branches
104 	"JUMP",              // Jump to target (+Target)
105 	"JUMP.T",            // evaluate TOS, conditional jump (+Target)
106 	"JUMP.F",            // evaluate TOS, conditional jump (+Target)
107 	"ONJUMP",            // evaluate TOS, jump into JUMP-table (+MaxVal)
108 	"GOSUB",             // UP-Call (+Target)
109 	"RETURN",            // UP-Return (+0 or Target)
110 	"TESTFOR",           // Test FOR-Variable, increment (+Endlabel)
111 	"CASETO",            // Tos+1 <= Case <= Tos, 2xremove (+Target)
112 	"ERRHDL",            // Error-Handler (+Offset)
113 	"RESUME",            // Resume after errors (+0 or 1 or Label)
114 	// I/O
115 	"CLOSE",             // (+channel/0)
116 	"PRCHAR",            // (+char)
117 	// Objects
118 	"SETCLASS",          // Test Set + Classname (+StringId)
119 	"TESTCLASS",         // Check TOS class (+StringId)
120 	"LIB",               // Set Libname for Declare-Procs (+StringId)
121 	// New since Beta 3 (TODO: Which Beta3?)
122 	"BASED",             // TOS is incremted about BASE, push BASE before
123 	"ARGTYP",            // Convert last parameter in argv (+Type)
124 	"VBASETCLASS",
125 };
126 
127 static const char* pOp3[] = {
128 	// All opcodes with two operands
129 	"RTL",              // Load from RTL (+StringID+Typ)
130 	"FIND",             // Load (+StringID+Typ)
131 	"ELEM",             // Load element (+StringID+Typ)
132 	"PARAM",            // Parameter (+Offset+Typ)
133 
134     // Branching
135 	"CALL",             // Call DECLARE method (+StringID+Typ)
136 	"CALL.C",           // Call Cdecl-DECLARE method (+StringID+Typ)
137 	"CASEIS",           // Case-Test (+Test-Opcode+False-Target)
138 	"STMNT",            // Start of a statement (+Line+Col)
139 
140     // I/O
141 	"OPEN",             // (+SvStreamFlags+Flags)
142 
143     // Objects and variables
144 	"LOCAL",            // Local variables (+StringID+Typ)
145 	"PUBLIC",           // Modul global var (+StringID+Typ)
146 	"GLOBAL",           // Global var (+StringID+Typ)
147 	"CREATE",           // Create object (+StringId+StringId)
148 	"STATIC",           // Create static object (+StringId+StringId)
149 	"TCREATE",          // Create User defined Object (+StringId+StringId)
150 	"DCREATE",          // Create User defined Object-Array kreieren (+StringId+StringId)
151     "GLOBAL_P",         // Define persistent global var (existing after basic restart)
152                         // P=PERSIST (+StringID+Typ)
153     "FIND_G",           // Searches for global var with special handling due to _GLOBAL_P
154     "DCREATE_REDIMP",   // Change dimensions of a user defined Object-Array (+StringId+StringId)
155     "FIND_CM",          // Search inside a class module (CM) to enable global search in time
156     "PUBLIC_P",        	// Module global Variable (persisted between calls)(+StringID+Typ)
157     "FIND_STATIC",     	// local static var lookup (+StringID+Typ)
158 };
159 
160 static const char** pOps[3] = { pOp1, pOp2, pOp3 };
161 
162 typedef void( SbiDisas::*Func )( String& );  // Processing routines
163 
164 static const Func pOperand2[] = {
165 	&SbiDisas::StrOp,	// Load a numeric constant (+ID)
166 	&SbiDisas::StrOp,	// Load a string constant (+ID)
167 	&SbiDisas::ImmOp,	// Immediate Load (+Wert)
168 	&SbiDisas::StrOp,	// Save a named argument (+ID)
169 	&SbiDisas::ImmOp,	// Strip String to fixed size (+length)
170 
171     // Branches
172 	&SbiDisas::LblOp,	// Jump (+Target)
173 	&SbiDisas::LblOp,	// eval TOS, conditional jump (+Target)
174 	&SbiDisas::LblOp, 	// eval TOS, conditional jump (+Target)
175 	&SbiDisas::OnOp,	// eval TOS, jump in JUMP table (+MaxVal)
176 	&SbiDisas::LblOp,	// UP call (+Target)
177 	&SbiDisas::ReturnOp,	// UP Return (+0 or Target)
178 	&SbiDisas::LblOp,	// test FOR-Variable, increment (+Endlabel)
179 	&SbiDisas::LblOp,	// Tos+1 <= Case <= Tos), 2xremove (+Target)
180 	&SbiDisas::LblOp,	// Error handler (+Offset)
181 	&SbiDisas::ResumeOp,	// Resume after errors (+0 or 1 or Label)
182 
183     // I/O
184 	&SbiDisas::CloseOp,	// (+channel/0)
185 	&SbiDisas::CharOp,	// (+char)
186 
187     // Objects
188 	&SbiDisas::StrOp,   // Test classname (+StringId)
189 	&SbiDisas::StrOp,   // TESTCLASS, Check TOS class (+StringId)
190 	&SbiDisas::StrOp,   // Set libname for declare procs (+StringId)
191 	&SbiDisas::ImmOp,   // TOS is incremented about BASE erhoeht, BASE pushed before
192 	&SbiDisas::TypeOp,  // Convert last parameter to/in(?) argv (+Typ)
193 	&SbiDisas::StrOp,   // VBASETCLASS (+StringId)
194 };
195 
196 static const Func pOperand3[] = {
197 	// All opcodes with two operands
198 	&SbiDisas::VarOp,	// Load from RTL (+StringID+Typ)
199 	&SbiDisas::VarOp,	// Load (+StringID+Typ)
200 	&SbiDisas::VarOp,	// Load Element (+StringID+Typ)
201 	&SbiDisas::OffOp,	// Parameter (+Offset+Typ)
202 
203 	// Branch
204 	&SbiDisas::VarOp,	// Call DECLARE-Method (+StringID+Typ)
205 	&SbiDisas::VarOp,	// Call CDecl-DECLARE-Methode (+StringID+Typ)
206 	&SbiDisas::CaseOp,	// Case-Test (+Test-Opcode+False-Target)
207 	&SbiDisas::StmntOp,	// Statement (+Row+Column)
208 
209 	// I/O
210 	&SbiDisas::StrmOp,	// (+SvStreamFlags+Flags)
211 
212 	// Objects
213 	&SbiDisas::VarDefOp,   // Define local var (+StringID+Typ)
214 	&SbiDisas::VarDefOp,   // Define Module global var (+StringID+Typ)
215 	&SbiDisas::VarDefOp,   // Define global var (+StringID+Typ)
216 	&SbiDisas::Str2Op,     // Create object (+StringId+StringId)
217 	&SbiDisas::VarDefOp,   // Define static object (+StringID+Typ)
218 	&SbiDisas::Str2Op,     // Create User defined Object (+StringId+StringId)
219 	&SbiDisas::Str2Op,     // Create User defined Object-Array (+StringId+StringId)
220 	&SbiDisas::VarDefOp,   // Define persistent global var P=PERSIST (+StringID+Typ)
221     &SbiDisas::VarOp,    // Searches for global var with special handling due to  _GLOBAL_P
222 	&SbiDisas::Str2Op,     // Redimensionate User defined Object-Array (+StringId+StringId)
223 	&SbiDisas::VarOp,	 // FIND_CM
224 	&SbiDisas::VarDefOp, // PUBLIC_P
225 	&SbiDisas::VarOp,	 // FIND_STATIC
226 };
227 
228 // TODO: Why as method? Isn't a simple define sufficient?
229 static const char* _crlf()
230 {
231 #if defined (UNX) || defined( PM2 )
232 	return "\n";
233 #else
234 	return "\r\n";
235 #endif
236 }
237 
238 // This method exists because we want to load the file as own segment
239 sal_Bool SbModule::Disassemble( String& rText )
240 {
241 	rText.Erase();
242 	if( pImage )
243 	{
244 		SbiDisas aDisas( this, pImage );
245 		aDisas.Disas( rText );
246 	}
247 	return sal_Bool( rText.Len() != 0 );
248 }
249 
250 SbiDisas::SbiDisas( SbModule* p, const SbiImage* q ) : rImg( *q ), pMod( p )
251 {
252 	memset( cLabels, 0, 8192 );
253 	nLine = 0;
254 	nOff = 0;
255 	nPC = 0;
256 	nOp1 = nOp2 = nParts = 0;
257 	eOp = _NOP;
258 	// Set Label-Bits
259 	nOff = 0;
260 	while( Fetch() )
261 	{
262 		switch( eOp )
263 		{
264 			case _RESUME: if( nOp1 <= 1 ) break;
265 			case _RETURN: if( !nOp1 ) break;
266 			case _JUMP:
267 			case _JUMPT:
268 			case _JUMPF:
269 			case _GOSUB:
270 			case _TESTFOR:
271 			case _CASEIS:
272 			case _CASETO:
273 			case _ERRHDL:
274                 cLabels[ (nOp1 & 0xffff) >> 3 ] |= ( 1 << ( nOp1 & 7 ) );
275                 break;
276 			default: break;
277 		}
278 	}
279 	nOff = 0;
280 	// Add the publics
281 	for( sal_uInt16 i = 0; i < pMod->GetMethods()->Count(); i++ )
282 	{
283 		SbMethod* pMeth = PTR_CAST(SbMethod,pMod->GetMethods()->Get( i ));
284 		if( pMeth )
285 		{
286 			sal_uInt16 nPos = (sal_uInt16) (pMeth->GetId());
287 			cLabels[ nPos >> 3 ] |= ( 1 << ( nPos & 7 ) );
288 		}
289 	}
290 }
291 
292 // Read current opcode
293 sal_Bool SbiDisas::Fetch()
294 {
295 	nPC = nOff;
296 	if( nOff >= rImg.GetCodeSize() )
297 		return sal_False;
298 	const unsigned char* p = (const unsigned char*)( rImg.GetCode() + nOff );
299 	eOp = (SbiOpcode) ( *p++ & 0xFF );
300 	if( eOp <= SbOP0_END )
301 	{
302 		nOp1 = nOp2 = 0;
303 		nParts = 1;
304 		nOff++;
305 		return sal_True;
306 	}
307 	else if( eOp <= SbOP1_END )
308 	{
309 		nOff += 5;
310 		if( nOff > rImg.GetCodeSize() )
311 			return sal_False;
312 		nOp1 = *p++; nOp1 |= *p++ << 8; nOp1 |= *p++ << 16; nOp1 |= *p++ << 24;
313 		nParts = 2;
314 		return sal_True;
315 	}
316 	else if( eOp <= SbOP2_END )
317 	{
318 		nOff += 9;
319 		if( nOff > rImg.GetCodeSize() )
320 			return sal_False;
321 		nOp1 = *p++; nOp1 |= *p++ << 8; nOp1 |= *p++ << 16; nOp1 |= *p++ << 24;
322 		nOp2 = *p++; nOp2 |= *p++ << 8; nOp2 |= *p++ << 16; nOp2 |= *p++ << 24;
323 		nParts = 3;
324 		return sal_True;
325 	}
326 	else
327 		return sal_False;
328 }
329 
330 void SbiDisas::Disas( SvStream& r )
331 {
332 	String aText;
333 	nOff = 0;
334 	while( DisasLine( aText ) )
335 	{
336 		ByteString aByteText( aText, gsl_getSystemTextEncoding() );
337 		r.WriteLine( aByteText );
338 	}
339 }
340 
341 void SbiDisas::Disas( String& r )
342 {
343 	r.Erase();
344 	String aText;
345 	nOff = 0;
346 	while( DisasLine( aText ) )
347 	{
348 		r += aText;
349 		r.AppendAscii( _crlf() );
350 	}
351 	aText.ConvertLineEnd();
352 }
353 
354 sal_Bool SbiDisas::DisasLine( String& rText )
355 {
356 	char cBuf[ 100 ];
357 	const char* pMask[] = {
358 		"%08" SAL_PRIXUINT32 "                            ",
359 		"%08" SAL_PRIXUINT32 " %02X                   ",
360 		"%08" SAL_PRIXUINT32 " %02X %08X          ",
361 		"%08" SAL_PRIXUINT32 " %02X %08X %08X " };
362 	rText.Erase();
363 	if( !Fetch() )
364 		return sal_False;
365 
366 #ifdef DBG_TRACE_BASIC
367 	String aTraceStr_STMNT;
368 #endif
369 
370 	// New line?
371 	if( eOp == _STMNT && nOp1 != nLine )
372 	{
373         // Find line
374         String aSource = rImg.aOUSource;
375 		nLine = nOp1;
376 		sal_uInt16 n = 0;
377 		sal_uInt16 l = (sal_uInt16)nLine;
378 		while( --l ) {
379 			n = aSource.SearchAscii( "\n", n );
380 			if( n == STRING_NOTFOUND ) break;
381 			else n++;
382 		}
383 		// Show position
384 		if( n != STRING_NOTFOUND )
385 		{
386 			sal_uInt16 n2 = aSource.SearchAscii( "\n", n );
387 			if( n2 == STRING_NOTFOUND ) n2 = aSource.Len() - n;
388 			String s( aSource.Copy( n, n2 - n + 1 ) );
389 			sal_Bool bDone;
390 			do {
391 				bDone = sal_True;
392 				n = s.Search( '\r' );
393 				if( n != STRING_NOTFOUND ) bDone = sal_False, s.Erase( n, 1 );
394 				n = s.Search( '\n' );
395 				if( n != STRING_NOTFOUND ) bDone = sal_False, s.Erase( n, 1 );
396 			} while( !bDone );
397 //          snprintf( cBuf, sizeof(cBuf), pMask[ 0 ], nPC );
398 //			rText += cBuf;
399 			rText.AppendAscii( "; " );
400 			rText += s;
401 			rText.AppendAscii( _crlf() );
402 
403 #ifdef DBG_TRACE_BASIC
404 			aTraceStr_STMNT = s;
405 #endif
406 		}
407 	}
408 
409 	// Label?
410 	const char* p = "";
411 	if( cLabels[ nPC >> 3 ] & ( 1 << ( nPC & 7 ) ) )
412 	{
413 		// Public?
414 		ByteString aByteMethName;
415 		for( sal_uInt16 i = 0; i < pMod->GetMethods()->Count(); i++ )
416 		{
417 			SbMethod* pMeth = PTR_CAST(SbMethod,pMod->GetMethods()->Get( i ));
418 			if( pMeth )
419 			{
420 				aByteMethName = ByteString( pMeth->GetName(), gsl_getSystemTextEncoding() );
421 				if( pMeth->GetId() == nPC )
422 				{
423 					p = aByteMethName.GetBuffer();
424 					break;
425 				}
426 				if( pMeth->GetId() >= nPC )
427 					break;
428 			}
429 		}
430         snprintf( cBuf, sizeof(cBuf), pMask[ 0 ], nPC );
431 		rText.AppendAscii( cBuf );
432 		if( p && *p )
433 		{
434 			rText.AppendAscii( p );
435 		}
436 		else
437 		{
438             // fix warning (now error) for "Lbl%04lX" format
439   			snprintf( cBuf, sizeof(cBuf), "Lbl%08" SAL_PRIXUINT32, nPC );
440 			rText.AppendAscii( cBuf );
441 		}
442 		rText += ':';
443 		rText.AppendAscii( _crlf() );
444 	}
445     snprintf( cBuf, sizeof(cBuf), pMask[ nParts ], nPC, (sal_uInt16) eOp, nOp1, nOp2 );
446 
447 	String aPCodeStr;
448 	aPCodeStr.AppendAscii( cBuf );
449 	int n = eOp;
450 	if( eOp >= SbOP2_START )
451 		n -= SbOP2_START;
452 	else if( eOp >= SbOP1_START )
453 		n -= SbOP1_START;
454 	aPCodeStr += '\t';
455 	aPCodeStr.AppendAscii( pOps[ nParts-1 ][ n ] );
456 	aPCodeStr += '\t';
457 	switch( nParts )
458 	{
459 		case 2: (this->*( pOperand2[ n ] ) )( aPCodeStr ); break;
460 		case 3: (this->*( pOperand3[ n ] ) )( aPCodeStr ); break;
461 	}
462 
463 	rText += aPCodeStr;
464 
465 #ifdef DBG_TRACE_BASIC
466 	dbg_RegisterTraceTextForPC( pMod, nPC, aTraceStr_STMNT, aPCodeStr );
467 #endif
468 
469 	return sal_True;
470 }
471 
472 // Read from StringPool
473 void SbiDisas::StrOp( String& rText )
474 {
475 	String aStr = rImg.GetString( (sal_uInt16)nOp1 );
476 	ByteString aByteString( aStr, RTL_TEXTENCODING_ASCII_US );
477 	const char* p = aByteString.GetBuffer();
478 	if( p )
479 	{
480 		rText += '"';
481 		rText.AppendAscii( p );
482 		rText += '"';
483 	}
484 	else
485 	{
486 		rText.AppendAscii( "?String? " );
487 		rText += (sal_uInt16)nOp1;
488 	}
489 }
490 
491 void SbiDisas::Str2Op( String& rText )
492 {
493 	StrOp( rText );
494 	rText += ',';
495 	String s;
496 	nOp1 = nOp2;
497 	StrOp( s );
498 	rText += s;
499 }
500 
501 // Immediate Operand
502 void SbiDisas::ImmOp( String& rText )
503 {
504 	rText += String::CreateFromInt32(nOp1);
505 }
506 
507 // OnGoto Operand
508 void SbiDisas::OnOp( String& rText )
509 {
510 	rText += String::CreateFromInt32(nOp1 & 0x7FFF);
511 	if( nOp1 & 0x800 )
512 		rText.AppendAscii( "\t; Gosub" );
513 }
514 
515 // Label
516 void SbiDisas::LblOp( String& rText )
517 {
518 	char cBuf[ 10 ];
519     snprintf( cBuf, sizeof(cBuf), "Lbl%04" SAL_PRIXUINT32, nOp1 );
520 	rText.AppendAscii( cBuf );
521 }
522 
523 // 0 or Label
524 void SbiDisas::ReturnOp( String& rText )
525 {
526 	if( nOp1 )
527 		LblOp( rText );
528 }
529 
530 // 0, 1 or Label
531 void SbiDisas::ResumeOp( String& rText )
532 {
533 	switch( nOp1 )
534 	{
535 		case 1: rText.AppendAscii( "NEXT" ); break;
536 		case 2: LblOp( rText );
537 	}
538 }
539 
540 // print Prompt
541 // sal_False/TRUE
542 void SbiDisas::PromptOp( String& rText )
543 {
544 	if( nOp1 )
545 		rText.AppendAscii( "\"? \"" );
546 }
547 
548 // 0 or 1
549 void SbiDisas::CloseOp( String& rText )
550 {
551 	rText.AppendAscii( nOp1 ? "Channel" : "All" );
552 }
553 
554 // Print character
555 void SbiDisas::CharOp( String& rText )
556 {
557 	const char* p = NULL;
558 	switch( nOp1 )
559 	{
560 		case  7: p = "'\\a'"; break;
561 		case  9: p = "'\\t'"; break;
562 		case 10: p = "'\\n'"; break;
563 		case 12: p = "'\\f'"; break;
564 		case 13: p = "'\\r'"; break;
565 	}
566 	if( p ) rText.AppendAscii( p );
567 	else if( nOp1 >= ' ' )
568 		rText += '\'',
569 		rText += (char) nOp1,
570 		rText += '\'';
571 	else
572 		rText.AppendAscii( "char " ),
573 		rText += (sal_uInt16)nOp1;
574 }
575 
576 // Print var: String-ID and type
577 void SbiDisas::VarOp( String& rText )
578 {
579 	rText += rImg.GetString( (sal_uInt16)(nOp1 & 0x7FFF) );
580 	rText.AppendAscii( "\t; " );
581     // The type
582 	sal_uInt32 n = nOp1;
583 	nOp1 = nOp2;
584 	TypeOp( rText );
585 	if( n & 0x8000 )
586 		rText.AppendAscii( ", Args" );
587 }
588 
589 // Define variable: String-ID and type
590 void SbiDisas::VarDefOp( String& rText )
591 {
592 	rText += rImg.GetString( (sal_uInt16)(nOp1 & 0x7FFF) );
593 	rText.AppendAscii( "\t; " );
594     // The Typ
595 	nOp1 = nOp2;
596 	TypeOp( rText );
597 }
598 
599 // Print variable: Offset and Typ
600 void SbiDisas::OffOp( String& rText )
601 {
602 	rText += String::CreateFromInt32( nOp1 & 0x7FFF );
603 	rText.AppendAscii( "\t; " );
604 	// The type
605 	sal_uInt32 n = nOp1;
606 	nOp1 = nOp2;
607 	TypeOp( rText );
608 	if( n & 0x8000 )
609 		rText.AppendAscii( ", Args" );
610 }
611 
612 // Data type
613 #ifdef HP9000 // TODO: remove this!
614 static char* SbiDisas_TypeOp_pTypes[13] = {
615 	"Empty","Null","Integer","Long","Single","Double",
616 	"Currency","Date","String","Object","Error","Boolean",
617 	"Variant" };
618 #define pTypes SbiDisas_TypeOp_pTypes
619 #endif
620 void SbiDisas::TypeOp( String& rText )
621 {
622 	// AB 19.1.96: Typ kann Flag f�r BYVAL enthalten (StepARGTYP)
623 	if( nOp1 & 0x8000 )
624 	{
625 		nOp1 &= 0x7FFF;		// Flag wegfiltern
626 		rText.AppendAscii( "BYVAL " );
627 	}
628 	if( nOp1 < 13 )
629 	{
630 #ifndef HP9000
631 		static char pTypes[][13] = {
632 			"Empty","Null","Integer","Long","Single","Double",
633 			"Currency","Date","String","Object","Error","Boolean",
634 			"Variant" };
635 #endif
636 		rText.AppendAscii( pTypes[ nOp1 ] );
637 	}
638 	else
639 	{
640 		rText.AppendAscii( "type " );
641 		rText += (sal_uInt16)nOp1;
642 	}
643 }
644 #ifdef HP9000
645 #undef pTypes
646 #endif
647 
648 // sal_True-Label, condition Opcode
649 void SbiDisas::CaseOp( String& rText )
650 {
651 	LblOp( rText );
652 	rText += ',';
653 	rText.AppendAscii( pOp1[ nOp2 - SbxEQ + _EQ ] );
654 }
655 
656 // Row, column
657 void SbiDisas::StmntOp( String& rText )
658 {
659 	rText += String::CreateFromInt32( nOp1 );
660 	rText += ',';
661 	sal_uInt32 nCol = nOp2 & 0xFF;
662 	sal_uInt32 nFor = nOp2 / 0x100;
663     rText += String::CreateFromInt32( nCol );
664 	rText.AppendAscii( " (For-Level: " );
665 	rText += String::CreateFromInt32( nFor );
666 	rText += ')';
667 }
668 
669 // open mode, flags
670 void SbiDisas::StrmOp( String& rText )
671 {
672 	char cBuf[ 10 ];
673     snprintf( cBuf, sizeof(cBuf), "%04" SAL_PRIXUINT32, nOp1 );
674 	rText.AppendAscii( cBuf );
675 	if( nOp2 & SBSTRM_INPUT )
676 		rText.AppendAscii( ", Input" );
677 	if( nOp2 & SBSTRM_OUTPUT )
678 		rText.AppendAscii( ", Output" );
679 	if( nOp2 & SBSTRM_APPEND )
680 		rText.AppendAscii( ", Append" );
681 	if( nOp2 & SBSTRM_RANDOM )
682 		rText.AppendAscii( ", Random" );
683 	if( nOp2 & SBSTRM_BINARY )
684 		rText.AppendAscii( ", Binary" );
685 }
686 
687 
688