Example #1
0
//---------------------------------------------------------------------------
tjs_char * TJS_tTVInt_to_str(tjs_int64 value, tjs_char *string)
{
	if(value == TJS_UI64_VAL(0x8000000000000000))
	{
		// this is a special number which we must avoid normal conversion
		TJS_strcpy(string, TJS_W("-9223372036854775808"));
		return string;
	}

	tjs_char *ostring = string;

	if(value<0) *(string++) = TJS_W('-'), value = -value;

	tjs_char buf[40];

	tjs_char *p = buf;

	do
	{
		*(p++) = (value % 10) + TJS_W('0');
		value /= 10;
	} while(value);

	p--;
	while(buf <= p) *(string++) = *(p--);
	*string = 0;

	return ostring;
}
Example #2
0
//---------------------------------------------------------------------------
tjs_int TJS_cdecl tTJSString::printf(const tjs_char *format, ...)
{
	tjs_int r;
	tjs_char *buf = new tjs_char [TJS_TTSTR_SPRINTF_BUF_SIZE];
	try
	{
		tjs_int size = TJS_TTSTR_SPRINTF_BUF_SIZE-1; /*TJS_vsnprintf(NULL, 0, format, param);*/
		va_list param;
		va_start(param, format);
		r = TJS_vsnprintf(buf, size, format, param);
		AllocBuffer(r);
		if(r)
		{
			TJS_strcpy(const_cast<tjs_char*>(c_str()), buf);
		}
		va_end(param);
		FixLen();
	}
	catch(...)
	{
		delete [] buf;
		throw;
	}
	delete [] buf;
	return r;
}
Example #3
0
/*
	these functions do :
	replace each %%, %1, %2 into %, p1, p2.
	%1 must appear only once in the message string, otherwise internal
	buffer will overflow. ( %2 must also so )
*/
ttstr TVPFormatMessage(const tjs_char *msg, const ttstr & p1)
{
	tjs_char *p;
	tjs_char * buf = new tjs_char[TJS_strlen(msg) + p1.GetLen() + 1];
	p = buf;
	for(;*msg;msg++,p++)
	{
		if(*msg == TJS_W('%'))
		{
			if(msg[1] == TJS_W('%'))
			{
				// %%
				*p = TJS_W('%');
				msg++;
				continue;
			}
			else if(msg[1] == TJS_W('1'))
			{
				// %1
				TJS_strcpy(p, p1.c_str());
				p += p1.GetLen();
				p--;
				msg++;
				continue;
			}
		}
		*p = *msg;
	}

	*p = 0;

	ttstr ret(buf);
	delete [] buf;
	return ret;
}
Example #4
0
//---------------------------------------------------------------------------
void tTJS::OutputToConsoleWithCentering(const tjs_char *msg, tjs_uint width) const
{
	// this function does not matter whether msg includes ZENKAKU characters ...
	if(!msg) return;
	tjs_int len = TJS_strlen(msg);
	tjs_int ns = ((tjs_int)width - len)/2;
	if(ns<=0)
	{
		OutputToConsole(msg);
	}
	else
	{
		tjs_char *outbuf = new tjs_char[ns + len +1];
		tjs_char *p = outbuf;
		while(ns--) *(p++)= TJS_W(' ');
		TJS_strcpy(p, msg);
		try
		{
			OutputToConsole(outbuf);
		}
		catch(...)
		{
			delete [] outbuf;
			throw;
		}

		delete [] outbuf;
	}
}
Example #5
0
int TVPWriteHWEDumpFile( EXCEPTION_POINTERS* pExceptionPointers ) {
	BOOL bMiniDumpSuccessful;
	WCHAR szPath[MAX_PATH]; 
	WCHAR szFileName[MAX_PATH]; 
	const wchar_t* szAppName = TVPKirikiri;
	const wchar_t* szVersion = TVPGetVersionString().c_str();

	TVPEnsureDataPathDirectory();
	TJS_strcpy(szPath, TVPNativeDataPath.c_str());

	SYSTEMTIME stLocalTime;
	::GetLocalTime( &stLocalTime );
	StringCchPrintf( szFileName, MAX_PATH, L"%s%s%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp",
				szPath, szAppName, szVersion,
				stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
				stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond,
				GetCurrentProcessId(), GetCurrentThreadId());
	HANDLE hDumpFile = ::CreateFile(szFileName, GENERIC_READ|GENERIC_WRITE,
				FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);

	MINIDUMP_EXCEPTION_INFORMATION ExpParam;
	ExpParam.ThreadId = ::GetCurrentThreadId();
	ExpParam.ExceptionPointers = pExceptionPointers;
	ExpParam.ClientPointers = TRUE;
	bMiniDumpSuccessful = MiniDumpWriteDump( ::GetCurrentProcess(), ::GetCurrentProcessId(), hDumpFile, MiniDumpWithDataSegs, &ExpParam, NULL, NULL);
	return EXCEPTION_EXECUTE_HANDLER;
}
Example #6
0
//---------------------------------------------------------------------------
void tTJSScriptBlock::SetName(const tjs_char *name, tjs_int lineofs)
{
    if(Name) delete [] Name, Name = NULL;
    if(name)
    {
        LineOffset = lineofs;
        Name = new tjs_char[ TJS_strlen(name) + 1];
        TJS_strcpy(Name, name);
    }
}
Example #7
0
//---------------------------------------------------------------------------
void TVPClipboardSetText(const ttstr & text)
{
	if( ::OpenClipboard(0) ) {
		HGLOBAL ansihandle = NULL;
		HGLOBAL unicodehandle = NULL;
		try {
			// store ANSI string
			std::string ansistr = text.AsNarrowStdString();
			int ansistrlen = (ansistr.length() + 1)*sizeof(char);
			ansihandle = ::GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, ansistrlen);
			if( !ansihandle ) TVPThrowExceptionMessage( TVPFaildClipboardCopy );

			char *mem = (char*)::GlobalLock(ansihandle);
			if(mem) strncpy_s(mem, ansistrlen, ansistr.c_str(),ansistrlen);
			::GlobalUnlock(ansihandle);

			::SetClipboardData( CF_TEXT, ansihandle );
			ansihandle = NULL;

			// store UNICODE string
			unicodehandle = ::GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, (text.GetLen() + 1) * sizeof(tjs_char));
			if(!unicodehandle) TVPThrowExceptionMessage( TVPFaildClipboardCopy );;

			tjs_char *unimem = (tjs_char*)::GlobalLock(unicodehandle);
			if(unimem) TJS_strcpy(unimem, text.c_str());
			::GlobalUnlock(unicodehandle);

			::SetClipboardData( CF_UNICODETEXT, unicodehandle );
			unicodehandle = NULL;
		} catch(...) {
			if(ansihandle) ::GlobalFree(ansihandle);
			if(unicodehandle) ::GlobalFree(unicodehandle);
			::CloseClipboard();
			throw;
		}
		::CloseClipboard();
	}
}
Example #8
0
//---------------------------------------------------------------------------
void tTJS::OutputToConsoleSeparator(const tjs_char *text, tjs_uint count) const
{
	tjs_int len = TJS_strlen(text);
	tjs_char *outbuf = new tjs_char [ len * count + 1];
	tjs_char *p = outbuf;
	while(count--)
	{
		TJS_strcpy(p, text);
		p += len;
	}

	try
	{
		OutputToConsole(outbuf);
	}
	catch(...)
	{
		delete [] outbuf;
		throw;
	}

	delete [] outbuf;
}
Example #9
0
void tTJSScriptBlock::SetText(tTJSVariant *result, const tjs_char *text,
                              iTJSDispatch2 * context, bool isexpression)
{
    TJS_F_TRACE("tTJSScriptBlock::SetText");


    // compiles text and executes its global level scripts.
    // the script will be compiled as an expression if isexpressn is true.
    if(!text) return;
    if(!text[0]) return;

    TJS_D((TJS_W("Counting lines ...\n")))

    Script = new tjs_char[TJS_strlen(text)+1];
    TJS_strcpy(Script, text);

    // calculation of line-count
    tjs_char *ls = Script;
    tjs_char *p = Script;
    while(*p)
    {
        if(*p == TJS_W('\r') || *p == TJS_W('\n'))
        {
            LineVector.push_back(int(ls - Script));
            LineLengthVector.push_back(int(p - ls));
            if(*p == TJS_W('\r') && p[1] == TJS_W('\n')) p++;
            p++;
            ls = p;
        }
        else
        {
            p++;
        }
    }

    if(p!=ls)
    {
        LineVector.push_back(int(ls - Script));
        LineLengthVector.push_back(int(p - ls));
    }

    try
    {

        // parse and execute
#ifdef TJS_DEBUG_PROFILE_TIME
        {
            tTJSTimeProfiler p(parsetime);
#endif

            Parse(text, isexpression, result != NULL);

#ifdef TJS_DEBUG_PROFILE_TIME
        }

        {
            char buf[256];
            sprintf(buf, "parsing : %d", parsetime);
            OutputDebugString(buf);
            if(parsetime)
            {
                sprintf(buf, "Commit : %d (%d%%)", time_Commit, time_Commit*100/parsetime);
                OutputDebugString(buf);
                sprintf(buf, "yylex : %d (%d%%)", time_yylex, time_yylex*100/parsetime);
                OutputDebugString(buf);
                sprintf(buf, "MakeNP : %d (%d%%)", time_make_np, time_make_np*100/parsetime);
                OutputDebugString(buf);
                sprintf(buf, "GenNodeCode : %d (%d%%)", time_GenNodeCode, time_GenNodeCode*100/parsetime);
                OutputDebugString(buf);
                sprintf(buf, "  PutCode : %d (%d%%)", time_PutCode, time_PutCode*100/parsetime);
                OutputDebugString(buf);
                sprintf(buf, "  PutData : %d (%d%%)", time_PutData, time_PutData*100/parsetime);
                OutputDebugString(buf);
                sprintf(buf, "  this_proxy : %d (%d%%)", time_this_proxy, time_this_proxy*100/parsetime);
                OutputDebugString(buf);

                sprintf(buf, "ns::Push : %d (%d%%)", time_ns_Push, time_ns_Push*100/parsetime);
                OutputDebugString(buf);
                sprintf(buf, "ns::Pop : %d (%d%%)", time_ns_Pop, time_ns_Pop*100/parsetime);
                OutputDebugString(buf);
                sprintf(buf, "ns::Find : %d (%d%%)", time_ns_Find, time_ns_Find*100/parsetime);
                OutputDebugString(buf);
                sprintf(buf, "ns::Remove : %d (%d%%)", time_ns_Remove, time_ns_Remove*100/parsetime);
                OutputDebugString(buf);
                sprintf(buf, "ns::Commit : %d (%d%%)", time_ns_Commit, time_ns_Commit*100/parsetime);
                OutputDebugString(buf);

            }
        }
#endif

#ifdef TJS_DEBUG_DISASM
        std::list<tTJSInterCodeContext *>::iterator i =
            InterCodeContextList.begin();
        while(i != InterCodeContextList.end())
        {
            ConsoleOutput(TJS_W(""), (void*)this);
            ConsoleOutput((*i)->GetName(), (void*)this);
            (*i)->Disassemble(ConsoleOutput, (void*)this);
            i++;
        }
#endif

        // execute global level script
        ExecuteTopLevelScript(result, context);
    }
    catch(...)
    {
        if(InterCodeContextList.size() != 1)
        {
            if(TopLevelContext) TopLevelContext->Release(), TopLevelContext = NULL;
            while(ContextStack.size())
            {
                ContextStack.top()->Release();
                ContextStack.pop();
            }
        }
        throw;
    }

    if(InterCodeContextList.size() != 1)
    {
        // this is not a single-context script block
        // (may hook itself)
        // release all contexts and global at this time
        if(TopLevelContext) TopLevelContext->Release(), TopLevelContext = NULL;
        while(ContextStack.size())
        {
            ContextStack.top()->Release();
            ContextStack.pop();
        }
    }
}
Example #10
0
void tTJSInterCodeContext::Disassemble(
	void (*output_func)(const tjs_char *msg, const tjs_char *comment, tjs_int addr,
	const tjs_int32 *codestart, tjs_int size, void *data),
	void (*output_func_src)(const tjs_char *msg, const tjs_char *name, tjs_int line,
	void *data), void *data, tjs_int start, tjs_int end)
{
	// dis-assemble the intermediate code.
	// "output_func" points a line output function.

//	tTJSVariantString * s;

	tTJSString msg;
	tTJSString com;

	tjs_int prevline = -1;
	tjs_int curline = -1;

	if(end <= 0) end = CodeAreaSize;
	if(end > CodeAreaSize) end = CodeAreaSize;

	for(tjs_int i = start; i < end; )
	{
		msg.Clear();
		com.Clear();
		tjs_int size;
		tjs_int srcpos = CodePosToSrcPos(i);
		tjs_int line = Block->SrcPosToLine(srcpos);

		// output source lines as comment
		if(curline == -1 || curline <= line)
		{
			if(curline == -1) curline = line;
			tjs_int nl = line - curline;
			while(curline <= line)
			{
				if(nl<3 || nl >= 3 && line-curline <= 2)
				{
					tjs_int len;
					tjs_char *src = Block->GetLine(curline, &len);
					tjs_char * buf = new tjs_char[len + 1];
					TJS_strcpy_maxlen(buf, src, len);
					try
					{
						output_func_src(buf, TJS_W(""), curline, data);
					}
					catch(...)
					{
						delete [] buf;
						throw;
					}
					delete [] buf;
					curline++;
				}
				else
				{
					curline = line - 2;
				}
			}
		}
		else if(prevline != line)
		{
			tjs_int len;
			tjs_char *src = Block->GetLine(line, &len);
			tjs_char * buf = new tjs_char[len + 1];
			TJS_strcpy_maxlen(buf, src, len);
			try
			{
				output_func_src((const tjs_char*)buf, TJS_W(""), line, data);
			}
			catch(...)
			{
				delete [] buf;
				throw;
			}
			delete [] buf;
		}

		prevline = line;

		// decode each instructions
		switch(CodeArea[i])
		{
		case VM_NOP:
			msg.printf(TJS_W("nop"));
			size = 1;
			break;

		case VM_NF:
			msg.printf(TJS_W("nf"));
			size = 1;
			break;

		case VM_CONST:
			msg.printf(TJS_W("const %%%d, *%d"),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+1]),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+2]));
			if(DataArea)
			{
				com.printf(TJS_W("*%d = %ls"), TJS_FROM_VM_REG_ADDR(CodeArea[i+2]),
					GetValueComment(TJS_GET_VM_REG(DataArea, CodeArea[i+2])).c_str());
			}
			size = 3;
			break;


#define OP2_DISASM(c, x) \
	case c: \
		msg.printf(TJS_W(x) TJS_W(" %%%d, %%%d"), TJS_FROM_VM_REG_ADDR(CodeArea[i+1]), \
										TJS_FROM_VM_REG_ADDR(CodeArea[i+2])); \
		size = 3; \
		break
		// instructions that
		// 1. have two operands that represent registers.
		// 2. do not have property access variants.
		OP2_DISASM(VM_CP,		"cp");
		OP2_DISASM(VM_CEQ,		"ceq");
		OP2_DISASM(VM_CDEQ,		"cdeq");
		OP2_DISASM(VM_CLT,		"clt");
		OP2_DISASM(VM_CGT,		"cgt");
		OP2_DISASM(VM_CHKINS,	"chkins");
#undef OP2_DISASM


#define OP2_DISASM(c, x) \
	case c: \
		msg.printf(TJS_W(x) TJS_W(" %%%d, %%%d"), TJS_FROM_VM_REG_ADDR(CodeArea[i+1]), \
									TJS_FROM_VM_REG_ADDR(CodeArea[i+2])); \
		size = 3; \
		break; \
	case c+1: \
		msg.printf(TJS_W(x) TJS_W("pd") TJS_W(" %%%d, %%%d.*%d, %%%d"), \
			TJS_FROM_VM_REG_ADDR(CodeArea[i+1]), \
			TJS_FROM_VM_REG_ADDR(CodeArea[i+2]), \
			TJS_FROM_VM_REG_ADDR(CodeArea[i+3]), \
			TJS_FROM_VM_REG_ADDR(CodeArea[i+4])); \
		if(DataArea) \
		{ \
			com.printf(TJS_W("*%d = %ls"), TJS_FROM_VM_REG_ADDR(CodeArea[i+3]), \
				GetValueComment(TJS_GET_VM_REG(DataArea, CodeArea[i+3])).c_str()); \
		} \
		size = 5; \
		break; \
	case c+2: \
		msg.printf(TJS_W(x) TJS_W("pi") TJS_W(" %%%d, %%%d.%%%d, %%%d"), \
			TJS_FROM_VM_REG_ADDR(CodeArea[i+1]), \
			TJS_FROM_VM_REG_ADDR(CodeArea[i+2]), \
			TJS_FROM_VM_REG_ADDR(CodeArea[i+3]), \
			TJS_FROM_VM_REG_ADDR(CodeArea[i+4])); \
		size = 5; \
		break; \
	case c+3: \
		msg.printf(TJS_W(x) TJS_W("p") TJS_W(" %%%d, %%%d, %%%d"), \
			TJS_FROM_VM_REG_ADDR(CodeArea[i+1]), \
			TJS_FROM_VM_REG_ADDR(CodeArea[i+2]), \
			TJS_FROM_VM_REG_ADDR(CodeArea[i+3])); \
		size = 4; \
		break
		// instructions that
		// 1. have two operands that represent registers.
		// 2. have property access variants
		OP2_DISASM(VM_LOR,		"lor");
		OP2_DISASM(VM_LAND,		"land");
		OP2_DISASM(VM_BOR,		"bor");
		OP2_DISASM(VM_BXOR,		"bxor");
		OP2_DISASM(VM_BAND,		"band");
		OP2_DISASM(VM_SAR,		"sar");
		OP2_DISASM(VM_SAL,		"sal");
		OP2_DISASM(VM_SR,		"sr");
		OP2_DISASM(VM_ADD,		"add");
		OP2_DISASM(VM_SUB,		"sub");
		OP2_DISASM(VM_MOD,		"mod");
		OP2_DISASM(VM_DIV,		"div");
		OP2_DISASM(VM_IDIV,		"idiv");
		OP2_DISASM(VM_MUL,		"mul");
#undef OP2_DISASM

#define OP1_DISASM(x) \
	msg.printf(TJS_W(x) TJS_W(" %%%d"), TJS_FROM_VM_REG_ADDR(CodeArea[i+1])); \
	size = 2
		// instructions that have one operand which represent a register,
		// except for inc, dec
		case VM_TT:			OP1_DISASM("tt");		break;
		case VM_TF:			OP1_DISASM("tf");		break;
		case VM_SETF:		OP1_DISASM("setf");		break;
		case VM_SETNF:		OP1_DISASM("setnf");	break;
		case VM_LNOT:		OP1_DISASM("lnot");		break;
		case VM_BNOT:		OP1_DISASM("bnot");		break;
		case VM_ASC:		OP1_DISASM("asc");		break;
		case VM_CHR:		OP1_DISASM("chr");		break;
		case VM_NUM:		OP1_DISASM("num");		break;
		case VM_CHS:		OP1_DISASM("chs");		break;
		case VM_CL:			OP1_DISASM("cl");		break;
		case VM_INV:		OP1_DISASM("inv");		break;
		case VM_CHKINV:		OP1_DISASM("chkinv");	break;
		case VM_TYPEOF:		OP1_DISASM("typeof");	break;
		case VM_EVAL:		OP1_DISASM("eval");		break;
		case VM_EEXP:		OP1_DISASM("eexp");		break;
		case VM_INT:		OP1_DISASM("int");		break;
		case VM_REAL:		OP1_DISASM("real");		break;
		case VM_STR:		OP1_DISASM("str");		break;
		case VM_OCTET:		OP1_DISASM("octet");	break;
#undef OP1_DISASM

		case VM_CCL:
			msg.printf(TJS_W("ccl %%%d-%%%d"), TJS_FROM_VM_REG_ADDR(CodeArea[i+1]),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+1]) + CodeArea[i+2] -1);
			size = 3;
			break;

#define OP1_DISASM(c, x) \
	case c: \
		msg.printf(TJS_W(x) TJS_W(" %%%d"), TJS_FROM_VM_REG_ADDR(CodeArea[i+1])); \
		size = 2; \
		break; \
	case c+1: \
		msg.printf(TJS_W(x) TJS_W("pd") TJS_W(" %%%d, %%%d.*%d"), \
			TJS_FROM_VM_REG_ADDR(CodeArea[i+1]), \
			TJS_FROM_VM_REG_ADDR(CodeArea[i+2]), \
			TJS_FROM_VM_REG_ADDR(CodeArea[i+3])); \
		if(DataArea) \
		{ \
			com.printf(TJS_W("*%d = %ls"), \
				TJS_FROM_VM_REG_ADDR(CodeArea[i+3]), \
				GetValueComment(TJS_GET_VM_REG(DataArea, CodeArea[i+3])).c_str()); \
		} \
		size = 4; \
		break; \
	case c+2: \
		msg.printf(TJS_W(x) TJS_W("pi") TJS_W(" %%%d, %%%d.%%%d"), \
			TJS_FROM_VM_REG_ADDR(CodeArea[i+1]), \
			TJS_FROM_VM_REG_ADDR(CodeArea[i+2]), \
			TJS_FROM_VM_REG_ADDR(CodeArea[i+3])); \
		size = 4; \
		break; \
	case c+3: \
		msg.printf(TJS_W(x) TJS_W("p") TJS_W(" %%%d, %%%d"), \
			TJS_FROM_VM_REG_ADDR(CodeArea[i+1]), \
			TJS_FROM_VM_REG_ADDR(CodeArea[i+2])); \
		size = 3; \
		break

		// inc and dec
		OP1_DISASM(VM_INC,	"inc");
		OP1_DISASM(VM_DEC,	"dec");
#undef OP1_DISASM



#define OP1A_DISASM(x) \
	msg.printf(TJS_W(x) TJS_W(" %09d"), TJS_FROM_VM_CODE_ADDR(CodeArea[i+1]) + i); \
	size = 2
		// instructions that have one operand which represents code area
		case VM_JF:		OP1A_DISASM("jf");		break;
		case VM_JNF:	OP1A_DISASM("jnf");		break;
		case VM_JMP:	OP1A_DISASM("jmp");		break;
#undef OP1A_DISASM

		case VM_CALL:
		case VM_CALLD:
		case VM_CALLI:
		case VM_NEW:
		  {
			// function call variants

			msg.printf(
				CodeArea[i] == VM_CALL  ?TJS_W("call %%%d, %%%d("):
				CodeArea[i] == VM_CALLD ?TJS_W("calld %%%d, %%%d.*%d("):
				CodeArea[i] == VM_CALLI ?TJS_W("calli %%%d, %%%d.%%%d("):
										 TJS_W("new %%%d, %%%d("),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+1]),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+2]),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+3]));
			tjs_int st; // start of arguments
			if(CodeArea[i] == VM_CALLD || CodeArea[i] == VM_CALLI)
				st = 5;
			else
				st = 4;
			tjs_int num = CodeArea[i+st-1];     // st-1 = argument count
			bool first = true;
			tjs_char buf[256];
			tjs_int c = 0;
			if(num == -1)
			{
				// omit arg
				size = st;
				msg += TJS_W("...");
			}
			else if(num == -2)
			{
				// expand arg
				st ++;
				num = CodeArea[i+st-1];
				size = st + num * 2;
				for(tjs_int j = 0; j < num; j++)
				{
					if(!first) msg += TJS_W(", ");
					first = false;
					switch(CodeArea[i+st+j*2])
					{
					case fatNormal:
						TJS_snprintf(buf, sizeof(buf)/sizeof(tjs_char), TJS_W("%%%d"),
							TJS_FROM_VM_REG_ADDR(CodeArea[i+st+j*2+1]));
						break;
					case fatExpand:
						TJS_snprintf(buf, sizeof(buf)/sizeof(tjs_char), TJS_W("%%%d*"),
							TJS_FROM_VM_REG_ADDR(CodeArea[i+st+j*2+1]));
						break;
					case fatUnnamedExpand:
						TJS_strcpy(buf, TJS_W("*"));
						break;
					}
					msg += buf;
				}
			}
			else
			{
				// normal operation
				size = st + num;
				while(num--)
				{
					if(!first) msg += TJS_W(", ");
					first = false;
					TJS_snprintf(buf, sizeof(buf)/sizeof(tjs_char), TJS_W("%%%d"),
						TJS_FROM_VM_REG_ADDR(CodeArea[i+c+st]));
					c++;
					msg += buf;
				}
			}

			msg += TJS_W(")");
			if(DataArea && CodeArea[i] == VM_CALLD)
			{
				com.printf(TJS_W("*%d = %ls"), TJS_FROM_VM_REG_ADDR(CodeArea[i+3]),
					GetValueComment(TJS_GET_VM_REG(DataArea, CodeArea[i+3])).c_str());
			}

			break;
		  }

		case VM_GPD:
		case VM_GPDS:
			// property get direct
			msg.printf(
				CodeArea[i] == VM_GPD?TJS_W("gpd %%%d, %%%d.*%d"):
									  TJS_W("gpds %%%d, %%%d.*%d"),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+1]),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+2]),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+3]));
			if(DataArea)
			{
				com.printf(TJS_W("*%d = %ls"), TJS_FROM_VM_REG_ADDR(CodeArea[i+3]),
					GetValueComment(TJS_GET_VM_REG(DataArea, CodeArea[i+3])).c_str());
			}
			size = 4;
			break;


		case VM_SPD:
		case VM_SPDE:
		case VM_SPDEH:
		case VM_SPDS:
			// property set direct
			msg.printf(
				CodeArea[i] == VM_SPD ? TJS_W("spd %%%d.*%d, %%%d"):
				CodeArea[i] == VM_SPDE? TJS_W("spde %%%d.*%d, %%%d"):
				CodeArea[i] == VM_SPDEH?TJS_W("spdeh %%%d.*%d, %%%d"):
										TJS_W("spds %%%d.*%d, %%%d"),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+1]),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+2]),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+3]));
			if(DataArea)
			{
				com.printf(TJS_W("*%d = %ls"), TJS_FROM_VM_REG_ADDR(CodeArea[i+2]),
					GetValueComment(TJS_GET_VM_REG(DataArea, CodeArea[i+2])).c_str());
			}

			size = 4;
			break;


		case VM_GPI:
		case VM_GPIS:
			// property get indirect
			msg.printf(
				CodeArea[i] == VM_GPI ?  TJS_W("gpi %%%d, %%%d.%%%d"):
										 TJS_W("gpis %%%d, %%%d.%%%d"),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+1]),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+2]),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+3]));
			size = 4;
			break;


		case VM_SPI:
		case VM_SPIE:
		case VM_SPIS:
			// property set indirect
			msg.printf(
				CodeArea[i] == VM_SPI  ?TJS_W("spi %%%d.%%%d, %%%d"):
				CodeArea[i] == VM_SPIE ?TJS_W("spie %%%d.%%%d, %%%d"):
										TJS_W("spis %%%d.%%%d, %%%d"),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+1]),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+2]),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+3]));
			size = 4;
			break;


		case VM_SETP:
			// property set
			msg.printf(
				TJS_W("setp %%%d, %%%d"),
					TJS_FROM_VM_REG_ADDR(CodeArea[i+1]),
					TJS_FROM_VM_REG_ADDR(CodeArea[i+2]));
			size = 3;
			break;

		case VM_GETP:
			// property get
			msg.printf(
				TJS_W("getp %%%d, %%%d"),
					TJS_FROM_VM_REG_ADDR(CodeArea[i+1]),
					TJS_FROM_VM_REG_ADDR(CodeArea[i+2]));
			size = 3;
			break;


		case VM_DELD:
		case VM_TYPEOFD:
			// member delete direct / typeof direct
			msg.printf(
				CodeArea[i] == VM_DELD   ?TJS_W("deld %%%d, %%%d.*%d"):
										  TJS_W("typeofd %%%d, %%%d.*%d"),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+1]),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+2]),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+3]));
			if(DataArea)
			{
				com.printf(TJS_W("*%d = %ls"), TJS_FROM_VM_REG_ADDR(CodeArea[i+3]),
					GetValueComment(TJS_GET_VM_REG(DataArea, CodeArea[i+3])).c_str());
			}
			size = 4;
			break;

		case VM_DELI:
		case VM_TYPEOFI:
			// member delete indirect / typeof indirect
			msg.printf(
				CodeArea[i] == VM_DELI   ?TJS_W("deli %%%d, %%%d.%%%d"):
										  TJS_W("typeofi %%%d, %%%d.%%%d"),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+1]),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+2]),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+3]));
			size = 4;
			break;

		case VM_SRV:
			// set return value
			msg.printf(TJS_W("srv %%%d"), TJS_FROM_VM_REG_ADDR(CodeArea[i+1]));
			size = 2;
			break;

		case VM_RET:
			// return
			msg.printf(TJS_W("ret"));
			size = 1;
			break;

		case VM_ENTRY:
			// enter try-protected block
			msg.printf(TJS_W("entry %09d, %%%d"),
				TJS_FROM_VM_CODE_ADDR(CodeArea[i+1]) + i,
				TJS_FROM_VM_REG_ADDR(CodeArea[i+2]));
			size = 3;
			break;


		case VM_EXTRY:
			// exit from try-protected block
			msg.printf(TJS_W("extry"));
			size = 1;
			break;

		case VM_THROW:
			msg.printf(TJS_W("throw %%%d"), TJS_FROM_VM_REG_ADDR(CodeArea[i+1]));
			size = 2;
			break;

		case VM_CHGTHIS:
			msg.printf(TJS_W("chgthis %%%d, %%%d"),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+1]),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+2]));
			size = 3;
			break;

		case VM_GLOBAL:
			msg.printf(TJS_W("global %%%d"),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+1]));
			size = 2;
			break;

		case VM_ADDCI:
			msg.printf(TJS_W("addci %%%d, %%%d"),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+1]),
				TJS_FROM_VM_REG_ADDR(CodeArea[i+2]));
			size = 3;
			break;

		case VM_REGMEMBER:
			msg.printf(TJS_W("regmember"));
			size = 1;
			break;

		case VM_DEBUGGER:
			msg.printf(TJS_W("debugger"));
			size = 1;
			break;

		default:
			msg.printf(TJS_W("unknown instruction %d"), CodeArea[i]);
			size = 1;
			break;
		} /* switch */

		output_func(msg.c_str(), com.c_str(), i,
			CodeArea + i, size, data);  // call the callback

		i+=size;
	}

}