fix cr/lfs and remove trailing whitespaces...
[supertux.git] / src / squirrel / sqdbg / sqdbgserver.cpp
index c76ff0b..d6d141c 100644 (file)
-#include <squirrel.h>\r
-#include <assert.h>\r
-#include <sqstdblob.h>\r
-#include "sqrdbg.h"\r
-#include "sqdbgserver.h"\r
-\r
-\r
-#ifndef _UNICODE\r
-#define scstrcpy strcpy\r
-#else\r
-#define scstrcpy wcscpy\r
-#endif\r
-struct XMLEscape{\r
-       const SQChar c;\r
-       const SQChar *esc;\r
-};\r
-\r
-#define SQDBG_DEBUG_HOOK _SC("_sqdbg_debug_hook_")\r
-#define SQDBG_ERROR_HANDLER _SC("_sqdbg_error_handler_")\r
-\r
-XMLEscape g_escapes[]={\r
-       {_SC('<'),_SC("&lt;")},{'>',_SC("&gt;")},{_SC('&'),_SC("&amp;")},{_SC('\''),_SC("&apos;")},{_SC('\"'),_SC("&quot;")},{_SC('\n'),_SC("&quot;n")},{_SC('\r'),_SC("&quot;r")},{0, NULL}\r
-};\r
-\r
-const SQChar *IntToString(int n)\r
-{\r
-       static SQChar temp[256];\r
-       scsprintf(temp,_SC("%d"),n);\r
-       return temp;\r
-}\r
-\r
-int debug_hook(HSQUIRRELVM v);\r
-int error_handler(HSQUIRRELVM v);\r
-\r
-int beginelement(HSQUIRRELVM v)\r
-{\r
-       SQUserPointer up;\r
-       const SQChar *name;\r
-       sq_getuserpointer(v,-1,&up);\r
-       SQDbgServer *self = (SQDbgServer*)up;\r
-       sq_getuserpointer(v,-1,&up);\r
-       sq_getstring(v,2,&name);\r
-       self->BeginElement(name);\r
-       return 0;\r
-}\r
-\r
-int endelement(HSQUIRRELVM v)\r
-{\r
-       SQUserPointer up;\r
-       const SQChar *name;\r
-       sq_getuserpointer(v,-1,&up);\r
-       SQDbgServer *self = (SQDbgServer*)up;\r
-       sq_getuserpointer(v,-1,&up);\r
-       sq_getstring(v,2,&name);\r
-       self->EndElement(name);\r
-       return 0;\r
-}\r
-\r
-int attribute(HSQUIRRELVM v)\r
-{\r
-       SQUserPointer up;\r
-       const SQChar *name,*value;\r
-       sq_getuserpointer(v,-1,&up);\r
-       SQDbgServer *self = (SQDbgServer*)up;\r
-       sq_getuserpointer(v,-1,&up);\r
-       sq_getstring(v,2,&name);\r
-       sq_getstring(v,3,&value);\r
-       self->Attribute(name,value);\r
-       return 0;\r
-}\r
-\r
-const SQChar *EscapeXMLString(HSQUIRRELVM v,const SQChar *s)\r
-{\r
-       \r
-       SQChar *temp=sq_getscratchpad(v,((int)scstrlen(s)*6) + sizeof(SQChar));\r
-       SQChar *dest=temp;\r
-       while(*s!=_SC('\0')){\r
-               int i=0;\r
-               bool escaped=false;\r
-               while(g_escapes[i].esc!=NULL){\r
-                       if(*s==g_escapes[i].c){\r
-                               scstrcpy(dest,g_escapes[i].esc);\r
-                               dest+=scstrlen(g_escapes[i].esc);\r
-                               escaped=true;\r
-                               break;\r
-                       }\r
-                       i++;\r
-               }\r
-               if(!escaped){*dest=*s;*dest++;}\r
-               *s++;\r
-       }\r
-       *dest=_SC('\0');\r
-       return temp;\r
-}\r
-\r
-SQDbgServer::SQDbgServer(HSQUIRRELVM v)\r
-{\r
-       _ready = false;\r
-       _nestedcalls = 0;\r
-       _autoupdate = false;\r
-       _v = v;\r
-       _state = eDBG_Running;\r
-       _accept = INVALID_SOCKET;\r
-       _endpoint = INVALID_SOCKET;\r
-       _maxrecursion = 10;\r
-       sq_resetobject(&_debugroot);\r
-}\r
-\r
-SQDbgServer::~SQDbgServer()\r
-{\r
-       sq_release(_v,&_debugroot);\r
-       if(_accept != INVALID_SOCKET)\r
-               sqdbg_closesocket(_accept);\r
-       if(_endpoint != INVALID_SOCKET)\r
-               sqdbg_closesocket(_endpoint);\r
-}\r
-\r
-bool SQDbgServer::Init()\r
-{\r
-       //creates  an environment table for the debugger\r
-       \r
-       sq_newtable(_v);\r
-       sq_getstackobj(_v,-1,&_debugroot);\r
-       sq_addref(_v,&_debugroot);\r
-\r
-       //creates a emptyslot to store the watches\r
-       sq_pushstring(_v,_SC("watches"),-1);\r
-       sq_pushnull(_v);\r
-       sq_createslot(_v,-3);\r
-\r
-       sq_pushstring(_v,_SC("beginelement"),-1);\r
-       sq_pushuserpointer(_v,this);\r
-       sq_newclosure(_v,beginelement,1);\r
-       sq_setparamscheck(_v,2,_SC(".s"));\r
-       sq_createslot(_v,-3);\r
-\r
-       sq_pushstring(_v,_SC("endelement"),-1);\r
-       sq_pushuserpointer(_v,this);\r
-       sq_newclosure(_v,endelement,1);\r
-       sq_setparamscheck(_v,2,_SC(".s"));\r
-       sq_createslot(_v,-3);\r
-\r
-       sq_pushstring(_v,_SC("attribute"),-1);\r
-       sq_pushuserpointer(_v,this);\r
-       sq_newclosure(_v,attribute,1);\r
-       sq_setparamscheck(_v,3,_SC(".ss"));\r
-       sq_createslot(_v,-3);\r
-\r
-       sq_pop(_v,1);\r
-\r
-       //stores debug hook and error handler in the registry\r
-       sq_pushregistrytable(_v);\r
-\r
-       sq_pushstring(_v,SQDBG_DEBUG_HOOK,-1);\r
-       sq_pushuserpointer(_v,this);\r
-       sq_newclosure(_v,debug_hook,1);\r
-       sq_createslot(_v,-3);\r
-       \r
-       sq_pushstring(_v,SQDBG_ERROR_HANDLER,-1);\r
-       sq_pushuserpointer(_v,this);\r
-       sq_newclosure(_v,error_handler,1);\r
-       sq_createslot(_v,-3);\r
-\r
-       \r
-       sq_pop(_v,1);\r
-\r
-       //sets the error handlers\r
-       SetErrorHandlers();\r
-       return true;\r
-}\r
-\r
-bool SQDbgServer::ReadMsg()\r
-{\r
-       return false;\r
-}\r
-\r
-void SQDbgServer::BusyWait()\r
-{\r
-       while( !ReadMsg() )\r
-               sleep(0);\r
-}\r
-\r
-void SQDbgServer::SendChunk(const SQChar *chunk)\r
-{\r
-       char *buf=NULL;\r
-       int buf_len=0;\r
-#ifdef _UNICODE\r
-       buf_len=(int)scstrlen(chunk)+1;\r
-       buf=(char *)sq_getscratchpad(_v,(buf_len)*3);\r
-       wcstombs((char *)buf,chunk,buf_len);\r
-#else\r
-       buf_len=(int)scstrlen(chunk);\r
-       buf=(char *)chunk;\r
-#endif\r
-       send(_endpoint,(const char*)buf,(int)strlen((const char *)buf),0);\r
-}\r
-\r
-\r
-void SQDbgServer::Terminated()\r
-{\r
-       BeginElement(_SC("terminated"));\r
-       EndElement(_SC("terminated"));\r
-       ::usleep(200);\r
-}\r
-\r
-void SQDbgServer::Hook(int type,int line,const SQChar *src,const SQChar *func)\r
-{\r
-       switch(_state){\r
-       case eDBG_Running:\r
-               if(type==_SC('l') && _breakpoints.size()) {\r
-                       BreakPointSetItor itr = _breakpoints.find(BreakPoint(line,src));\r
-                       if(itr != _breakpoints.end()) {\r
-                               Break(line,src,_SC("breakpoint"));\r
-                               BreakExecution();\r
-                       }\r
-               }\r
-               break;\r
-       case eDBG_Suspended:\r
-               _nestedcalls=0;\r
-       case eDBG_StepOver:\r
-               switch(type){\r
-               case _SC('l'):\r
-                       if(_nestedcalls==0) {\r
-                               Break(line,src,_SC("step"));\r
-                               BreakExecution();\r
-                       }\r
-                       break;\r
-               case _SC('c'):\r
-                       _nestedcalls++;\r
-                       break;\r
-               case _SC('r'):\r
-                       if(_nestedcalls==0){\r
-                               _nestedcalls=0;\r
-                               \r
-                       }else{\r
-                               _nestedcalls--;\r
-                       }\r
-                       break;\r
-               }\r
-               break;\r
-       case eDBG_StepInto:\r
-               switch(type){\r
-               case _SC('l'):\r
-                       _nestedcalls=0;\r
-                       Break(line,src,_SC("step"));\r
-                       BreakExecution();\r
-                       break;\r
-               \r
-               }\r
-               break;\r
-       case eDBG_StepReturn:\r
-               switch(type){\r
-               case _SC('l'):\r
-                       break;\r
-               case _SC('c'):\r
-                       _nestedcalls++;\r
-                       break;\r
-               case _SC('r'):\r
-                       if(_nestedcalls==0){\r
-                               _nestedcalls=0;\r
-                               _state=eDBG_StepOver;\r
-                       }else{\r
-                               _nestedcalls--;\r
-                       }\r
-                       \r
-                       break;\r
-               }\r
-               break;\r
-       case eDBG_Disabled:\r
-               break;\r
-       }\r
-}\r
-\r
-\r
-#define MSG_ID(x,y) ((y<<8)|x)\r
-//ab Add Breakpoint\r
-//rb Remove Breakpoint\r
-//sp Suspend\r
-void SQDbgServer::ParseMsg(const char *msg)\r
-{\r
-       \r
-       switch(*((unsigned short *)msg)){\r
-               case MSG_ID('a','b'): {\r
-                       BreakPoint bp;\r
-                       if(ParseBreakpoint(msg+3,bp)){\r
-                               AddBreakpoint(bp);\r
-                               scprintf(_SC("added bp %d %s\n"),bp._line,bp._src.c_str());\r
-                       }\r
-                       else\r
-                               scprintf(_SC("error parsing add breakpoint"));\r
-                                                        }\r
-                       break;\r
-               case MSG_ID('r','b'): {\r
-                       BreakPoint bp;\r
-                       if(ParseBreakpoint(msg+3,bp)){\r
-                               RemoveBreakpoint(bp);\r
-                               scprintf(_SC("removed bp %d %s\n"),bp._line,bp._src.c_str());\r
-                       }else\r
-                               scprintf(_SC("error parsing remove breakpoint"));\r
-                                                       }\r
-                       break;\r
-               case MSG_ID('g','o'):\r
-                       if(_state!=eDBG_Running){\r
-                               _state=eDBG_Running;\r
-                               BeginDocument();\r
-                                       BeginElement(_SC("resumed"));\r
-                                       EndElement(_SC("resumed"));\r
-                               EndDocument();\r
-//                             Send(_SC("<resumed/>\r\n"));\r
-                               scprintf(_SC("go (execution resumed)\n"));\r
-                       }\r
-                       break;\r
-               case MSG_ID('s','p'):\r
-                       if(_state!=eDBG_Suspended){\r
-                               _state=eDBG_Suspended;\r
-                               scprintf(_SC("suspend\n"));\r
-                       }\r
-                       break;\r
-               case MSG_ID('s','o'):\r
-                       if(_state==eDBG_Suspended){\r
-                               _state=eDBG_StepOver;\r
-                       }\r
-                       break;\r
-               case MSG_ID('s','i'):\r
-                       if(_state==eDBG_Suspended){\r
-                               _state=eDBG_StepInto;\r
-                               scprintf(_SC("step into\n"));\r
-                       }\r
-                       break;\r
-               case MSG_ID('s','r'):\r
-                       if(_state==eDBG_Suspended){\r
-                               _state=eDBG_StepReturn;\r
-                               scprintf(_SC("step return\n"));\r
-                       }\r
-                       break;\r
-               case MSG_ID('d','i'):\r
-                       if(_state!=eDBG_Disabled){\r
-                               _state=eDBG_Disabled;\r
-                               scprintf(_SC("disabled\n"));\r
-                       }\r
-                       break;\r
-               case MSG_ID('a','w'): {\r
-                       Watch w;\r
-                       if(ParseWatch(msg+3,w))\r
-                       {\r
-                               AddWatch(w);\r
-                               scprintf(_SC("added watch %d %s\n"),w._id,w._exp.c_str());\r
-                       }\r
-                       else\r
-                               scprintf(_SC("error parsing add watch"));\r
-                                                               }\r
-                       break;\r
-               case MSG_ID('r','w'): {\r
-                       int id;\r
-                       if(ParseRemoveWatch(msg+3,id))\r
-                       {\r
-                               RemoveWatch(id);\r
-                               scprintf(_SC("added watch %d\n"),id);\r
-                       }\r
-                       else\r
-                               scprintf(_SC("error parsing remove watch"));\r
-                                                               }\r
-                       break;\r
-               case MSG_ID('t','r'):\r
-                       scprintf(_SC("terminate from user\n"));\r
-                       break;\r
-               case MSG_ID('r','d'):\r
-                       scprintf(_SC("ready\n"));\r
-                       _ready=true;\r
-                       break;\r
-               default:\r
-                       scprintf(_SC("unknown packet"));\r
-\r
-       }\r
-}\r
-\r
-/*\r
-       see copyright notice in sqrdbg.h\r
-*/\r
-bool SQDbgServer::ParseBreakpoint(const char *msg,BreakPoint &out)\r
-{\r
-       static char stemp[MAX_BP_PATH];\r
-       char *ep=NULL;\r
-       out._line=strtoul(msg,&ep,16);\r
-       if(ep==msg || (*ep)!=':')return false;\r
-       \r
-       char *dest=stemp;\r
-       ep++;\r
-       while((*ep)!='\n' && (*ep)!='\0')\r
-       {\r
-               *dest=*ep;\r
-               *dest++;*ep++;\r
-       }\r
-       *dest='\0';\r
-       *dest++;\r
-       *dest='\0';\r
-#ifdef _UNICODE\r
-       int len=(int)strlen(stemp);\r
-       SQChar *p=sq_getscratchpad(_v,(SQInteger)(mbstowcs(NULL,stemp,len)+2)*sizeof(SQChar));\r
-       size_t destlen=mbstowcs(p,stemp,len);\r
-       p[destlen]=_SC('\0');\r
-       out._src=p;\r
-#else\r
-       out._src=stemp;\r
-#endif\r
-       return true;\r
-}\r
-\r
-bool SQDbgServer::ParseWatch(const char *msg,Watch &out)\r
-{\r
-       char *ep=NULL;\r
-       out._id=strtoul(msg,&ep,16);\r
-       if(ep==msg || (*ep)!=':')return false;\r
-\r
-       //char *dest=out._src;\r
-       ep++;\r
-       while((*ep)!='\n' && (*ep)!='\0')\r
-       {\r
-               out._exp.append(1,*ep);\r
-               *ep++;\r
-       }\r
-       return true;\r
-}\r
-\r
-bool SQDbgServer::ParseRemoveWatch(const char *msg,int &id)\r
-{\r
-       char *ep=NULL;\r
-       id=strtoul(msg,&ep,16);\r
-       if(ep==msg)return false;\r
-       return true;\r
-}\r
-\r
-\r
-void SQDbgServer::BreakExecution()\r
-{\r
-       _state=eDBG_Suspended;\r
-       while(_state==eDBG_Suspended){\r
-               if(SQ_FAILED(sq_rdbg_update(this)))\r
-                       exit(0);\r
-               usleep(10);\r
-       }\r
-}\r
-\r
-//COMMANDS\r
-void SQDbgServer::AddBreakpoint(BreakPoint &bp)\r
-{\r
-       _breakpoints.insert(bp);\r
-       BeginDocument();\r
-               BeginElement(_SC("addbreakpoint"));\r
-                       Attribute(_SC("line"),IntToString(bp._line));\r
-                       Attribute(_SC("src"),bp._src.c_str());\r
-               EndElement(_SC("addbreakpoint"));\r
-       EndDocument();\r
-}\r
-\r
-void SQDbgServer::AddWatch(Watch &w)\r
-{\r
-       _watches.insert(w);\r
-}\r
-\r
-void SQDbgServer::RemoveWatch(int id)\r
-{\r
-       WatchSetItor itor=_watches.find(Watch(id,_SC("")));\r
-       if(itor==_watches.end()){\r
-               BeginDocument();\r
-               BeginElement(_SC("error"));\r
-                       Attribute(_SC("desc"),_SC("the watch does not exists"));\r
-               EndElement(_SC("error"));\r
-       EndDocument();\r
-       }\r
-       else{\r
-               _watches.erase(itor);\r
-               scprintf(_SC("removed watch %d\n"),id);\r
-       }\r
-}\r
-\r
-void SQDbgServer::RemoveBreakpoint(BreakPoint &bp)\r
-{\r
-       BreakPointSetItor itor=_breakpoints.find(bp);\r
-       if(itor==_breakpoints.end()){\r
-               BeginDocument();\r
-                       BeginElement(_SC("break"));\r
-                               Attribute(_SC("desc"),_SC("the breakpoint doesn't exists"));\r
-                       EndElement(_SC("break"));\r
-               EndDocument();\r
-       }\r
-       else{\r
-               BeginDocument();\r
-                       BeginElement(_SC("removebreakpoint"));\r
-                               Attribute(_SC("line"),IntToString(bp._line));\r
-                               Attribute(_SC("src"),bp._src.c_str());\r
-                       EndElement(_SC("removebreakpoint"));\r
-               EndDocument();\r
-               _breakpoints.erase(itor);\r
-       }\r
-}\r
-\r
-void SQDbgServer::Break(int line,const SQChar *src,const SQChar *type,const SQChar *error)\r
-{\r
-       if(!error){\r
-               BeginDocument();\r
-                       BeginElement(_SC("break"));\r
-                               Attribute(_SC("line"),IntToString(line));\r
-                               Attribute(_SC("src"),src);\r
-                               Attribute(_SC("type"),type);\r
-                               SerializeState();\r
-                       EndElement(_SC("break"));\r
-               EndDocument();\r
-       }else{\r
-               BeginDocument();\r
-                       BeginElement(_SC("break"));\r
-                               Attribute(_SC("line"),IntToString(line));\r
-                               Attribute(_SC("src"),src);\r
-                               Attribute(_SC("type"),type);\r
-                               Attribute(_SC("error"),error);\r
-                               SerializeState();\r
-                       EndElement(_SC("break"));\r
-               EndDocument();\r
-       }\r
-}\r
-\r
-void SQDbgServer::SerializeState()\r
-{\r
-       sq_pushnull(_v);\r
-       sq_setdebughook(_v);\r
-       sq_pushnull(_v);\r
-       sq_seterrorhandler(_v);\r
-       const SQChar *sz;\r
-       sq_pushobject(_v,_serializefunc);\r
-       sq_pushobject(_v,_debugroot);\r
-       sq_pushstring(_v,_SC("watches"),-1);\r
-       sq_newtable(_v);\r
-       for(WatchSetItor i=_watches.begin(); i!=_watches.end(); ++i)\r
-       {\r
-               sq_pushinteger(_v,i->_id);\r
-               sq_pushstring(_v,i->_exp.c_str(),(int)i->_exp.length());\r
-               sq_createslot(_v,-3);\r
-       }\r
-       sq_rawset(_v,-3);\r
-       if(SQ_SUCCEEDED(sq_call(_v,1,SQTrue,SQTrue))){\r
-               if(SQ_SUCCEEDED(sqstd_getblob(_v,-1,(SQUserPointer*)&sz)))\r
-                       SendChunk(sz);\r
-       }\r
-       sq_pop(_v,2);\r
-       \r
-       SetErrorHandlers();\r
-}\r
-\r
-\r
-void SQDbgServer::SetErrorHandlers()\r
-{\r
-       sq_pushregistrytable(_v);\r
-       sq_pushstring(_v,SQDBG_DEBUG_HOOK,-1);\r
-       sq_rawget(_v,-2);\r
-       sq_setdebughook(_v);\r
-       sq_pushstring(_v,SQDBG_ERROR_HANDLER,-1);\r
-       sq_rawget(_v,-2);\r
-       sq_seterrorhandler(_v);\r
-       sq_pop(_v,1);\r
-}\r
-\r
-void SQDbgServer::BeginElement(const SQChar *name)\r
-{\r
-       _xmlcurrentement++;\r
-       XMLElementState *self = &xmlstate[_xmlcurrentement];\r
-       scstrcpy(self->name,name);\r
-       self->haschildren = false;\r
-       if(_xmlcurrentement > 0) {\r
-               XMLElementState *parent = &xmlstate[_xmlcurrentement-1];\r
-               if(!parent->haschildren) {\r
-                       SendChunk(_SC(">")); // closes the parent tag\r
-                       parent->haschildren = true;\r
-               }\r
-       }\r
-       _scratchstring.resize(2+scstrlen(name));\r
-       scsprintf(&_scratchstring[0],_SC("<%s"),name);\r
-       SendChunk(&_scratchstring[0]);\r
-}\r
-\r
-void SQDbgServer::Attribute(const SQChar *name,const SQChar *value)\r
-{\r
-       XMLElementState *self = &xmlstate[_xmlcurrentement];\r
-       assert(!self->haschildren); //cannot have attributes if already has children\r
-       const SQChar *escval = escape_xml(value);\r
-       _scratchstring.resize(5+scstrlen(name)+scstrlen(escval));\r
-       scsprintf(&_scratchstring[0],_SC(" %s=\"%s\""),name,escval);\r
-       SendChunk(&_scratchstring[0]);\r
-}\r
-\r
-void SQDbgServer::EndElement(const SQChar *name)\r
-{\r
-       XMLElementState *self = &xmlstate[_xmlcurrentement];\r
-       assert(scstrcmp(self->name,name) == 0);\r
-       if(self->haschildren) {\r
-               _scratchstring.resize(4+scstrlen(name));\r
-               scsprintf(&_scratchstring[0],_SC("</%s>"),name);\r
-               SendChunk(&_scratchstring[0]);\r
-               \r
-       }\r
-       else {\r
-               SendChunk(_SC("/>"));\r
-       }\r
-       _xmlcurrentement--;\r
-}\r
-\r
-void SQDbgServer::EndDocument()\r
-{\r
-       SendChunk(_SC("\r\n"));\r
-}\r
-\r
-//this can be done much better/faster(do we need that?)\r
-const SQChar *SQDbgServer::escape_xml(const SQChar *s)\r
-{\r
-       SQChar *temp=sq_getscratchpad(_v,((int)scstrlen(s)*6) + sizeof(SQChar));\r
-       SQChar *dest=temp;\r
-       while(*s!=_SC('\0')){\r
-               int i=0;\r
-               bool escaped=false;\r
-               while(g_escapes[i].esc!=NULL){\r
-                       if(*s==g_escapes[i].c){\r
-                               scstrcpy(dest,g_escapes[i].esc);\r
-                               dest+=scstrlen(g_escapes[i].esc);\r
-                               escaped=true;\r
-                               break;\r
-                       }\r
-                       i++;\r
-               }\r
-               if(!escaped){*dest=*s;*dest++;}\r
-               *s++;\r
-       }\r
-       *dest=_SC('\0');\r
-       return temp;\r
-       \r
-}\r
+#include <squirrel.h>
+#include <assert.h>
+#include <sqstdblob.h>
+#include "sqrdbg.h"
+#include "sqdbgserver.h"
+
+
+#ifndef _UNICODE
+#define scstrcpy strcpy
+#else
+#define scstrcpy wcscpy
+#endif
+struct XMLEscape{
+       const SQChar c;
+       const SQChar *esc;
+};
+
+#define SQDBG_DEBUG_HOOK _SC("_sqdbg_debug_hook_")
+#define SQDBG_ERROR_HANDLER _SC("_sqdbg_error_handler_")
+
+XMLEscape g_escapes[]={
+       {_SC('<'),_SC("&lt;")},{'>',_SC("&gt;")},{_SC('&'),_SC("&amp;")},{_SC('\''),_SC("&apos;")},{_SC('\"'),_SC("&quot;")},{_SC('\n'),_SC("&quot;n")},{_SC('\r'),_SC("&quot;r")},{0, NULL}
+};
+
+const SQChar *IntToString(int n)
+{
+       static SQChar temp[256];
+       scsprintf(temp,_SC("%d"),n);
+       return temp;
+}
+
+int debug_hook(HSQUIRRELVM v);
+int error_handler(HSQUIRRELVM v);
+
+int beginelement(HSQUIRRELVM v)
+{
+       SQUserPointer up;
+       const SQChar *name;
+       sq_getuserpointer(v,-1,&up);
+       SQDbgServer *self = (SQDbgServer*)up;
+       sq_getuserpointer(v,-1,&up);
+       sq_getstring(v,2,&name);
+       self->BeginElement(name);
+       return 0;
+}
+
+int endelement(HSQUIRRELVM v)
+{
+       SQUserPointer up;
+       const SQChar *name;
+       sq_getuserpointer(v,-1,&up);
+       SQDbgServer *self = (SQDbgServer*)up;
+       sq_getuserpointer(v,-1,&up);
+       sq_getstring(v,2,&name);
+       self->EndElement(name);
+       return 0;
+}
+
+int attribute(HSQUIRRELVM v)
+{
+       SQUserPointer up;
+       const SQChar *name,*value;
+       sq_getuserpointer(v,-1,&up);
+       SQDbgServer *self = (SQDbgServer*)up;
+       sq_getuserpointer(v,-1,&up);
+       sq_getstring(v,2,&name);
+       sq_getstring(v,3,&value);
+       self->Attribute(name,value);
+       return 0;
+}
+
+const SQChar *EscapeXMLString(HSQUIRRELVM v,const SQChar *s)
+{
+
+       SQChar *temp=sq_getscratchpad(v,((int)scstrlen(s)*6) + sizeof(SQChar));
+       SQChar *dest=temp;
+       while(*s!=_SC('\0')){
+               int i=0;
+               bool escaped=false;
+               while(g_escapes[i].esc!=NULL){
+                       if(*s==g_escapes[i].c){
+                               scstrcpy(dest,g_escapes[i].esc);
+                               dest+=scstrlen(g_escapes[i].esc);
+                               escaped=true;
+                               break;
+                       }
+                       i++;
+               }
+               if(!escaped){*dest=*s;*dest++;}
+               *s++;
+       }
+       *dest=_SC('\0');
+       return temp;
+}
+
+SQDbgServer::SQDbgServer(HSQUIRRELVM v)
+{
+       _ready = false;
+       _nestedcalls = 0;
+       _autoupdate = false;
+       _v = v;
+       _state = eDBG_Running;
+       _accept = INVALID_SOCKET;
+       _endpoint = INVALID_SOCKET;
+       _maxrecursion = 10;
+       sq_resetobject(&_debugroot);
+}
+
+SQDbgServer::~SQDbgServer()
+{
+       sq_release(_v,&_debugroot);
+       if(_accept != INVALID_SOCKET)
+               sqdbg_closesocket(_accept);
+       if(_endpoint != INVALID_SOCKET)
+               sqdbg_closesocket(_endpoint);
+}
+
+bool SQDbgServer::Init()
+{
+       //creates  an environment table for the debugger
+
+       sq_newtable(_v);
+       sq_getstackobj(_v,-1,&_debugroot);
+       sq_addref(_v,&_debugroot);
+
+       //creates a emptyslot to store the watches
+       sq_pushstring(_v,_SC("watches"),-1);
+       sq_pushnull(_v);
+       sq_createslot(_v,-3);
+
+       sq_pushstring(_v,_SC("beginelement"),-1);
+       sq_pushuserpointer(_v,this);
+       sq_newclosure(_v,beginelement,1);
+       sq_setparamscheck(_v,2,_SC(".s"));
+       sq_createslot(_v,-3);
+
+       sq_pushstring(_v,_SC("endelement"),-1);
+       sq_pushuserpointer(_v,this);
+       sq_newclosure(_v,endelement,1);
+       sq_setparamscheck(_v,2,_SC(".s"));
+       sq_createslot(_v,-3);
+
+       sq_pushstring(_v,_SC("attribute"),-1);
+       sq_pushuserpointer(_v,this);
+       sq_newclosure(_v,attribute,1);
+       sq_setparamscheck(_v,3,_SC(".ss"));
+       sq_createslot(_v,-3);
+
+       sq_pop(_v,1);
+
+       //stores debug hook and error handler in the registry
+       sq_pushregistrytable(_v);
+
+       sq_pushstring(_v,SQDBG_DEBUG_HOOK,-1);
+       sq_pushuserpointer(_v,this);
+       sq_newclosure(_v,debug_hook,1);
+       sq_createslot(_v,-3);
+
+       sq_pushstring(_v,SQDBG_ERROR_HANDLER,-1);
+       sq_pushuserpointer(_v,this);
+       sq_newclosure(_v,error_handler,1);
+       sq_createslot(_v,-3);
+
+
+       sq_pop(_v,1);
+
+       //sets the error handlers
+       SetErrorHandlers();
+       return true;
+}
+
+bool SQDbgServer::ReadMsg()
+{
+       return false;
+}
+
+void SQDbgServer::BusyWait()
+{
+       while( !ReadMsg() )
+               sleep(0);
+}
+
+void SQDbgServer::SendChunk(const SQChar *chunk)
+{
+       char *buf=NULL;
+       int buf_len=0;
+#ifdef _UNICODE
+       buf_len=(int)scstrlen(chunk)+1;
+       buf=(char *)sq_getscratchpad(_v,(buf_len)*3);
+       wcstombs((char *)buf,chunk,buf_len);
+#else
+       buf_len=(int)scstrlen(chunk);
+       buf=(char *)chunk;
+#endif
+       send(_endpoint,(const char*)buf,(int)strlen((const char *)buf),0);
+}
+
+
+void SQDbgServer::Terminated()
+{
+       BeginElement(_SC("terminated"));
+       EndElement(_SC("terminated"));
+       ::usleep(200);
+}
+
+void SQDbgServer::Hook(int type,int line,const SQChar *src,const SQChar *func)
+{
+       switch(_state){
+       case eDBG_Running:
+               if(type==_SC('l') && _breakpoints.size()) {
+                       BreakPointSetItor itr = _breakpoints.find(BreakPoint(line,src));
+                       if(itr != _breakpoints.end()) {
+                               Break(line,src,_SC("breakpoint"));
+                               BreakExecution();
+                       }
+               }
+               break;
+       case eDBG_Suspended:
+               _nestedcalls=0;
+       case eDBG_StepOver:
+               switch(type){
+               case _SC('l'):
+                       if(_nestedcalls==0) {
+                               Break(line,src,_SC("step"));
+                               BreakExecution();
+                       }
+                       break;
+               case _SC('c'):
+                       _nestedcalls++;
+                       break;
+               case _SC('r'):
+                       if(_nestedcalls==0){
+                               _nestedcalls=0;
+
+                       }else{
+                               _nestedcalls--;
+                       }
+                       break;
+               }
+               break;
+       case eDBG_StepInto:
+               switch(type){
+               case _SC('l'):
+                       _nestedcalls=0;
+                       Break(line,src,_SC("step"));
+                       BreakExecution();
+                       break;
+
+               }
+               break;
+       case eDBG_StepReturn:
+               switch(type){
+               case _SC('l'):
+                       break;
+               case _SC('c'):
+                       _nestedcalls++;
+                       break;
+               case _SC('r'):
+                       if(_nestedcalls==0){
+                               _nestedcalls=0;
+                               _state=eDBG_StepOver;
+                       }else{
+                               _nestedcalls--;
+                       }
+
+                       break;
+               }
+               break;
+       case eDBG_Disabled:
+               break;
+       }
+}
+
+
+#define MSG_ID(x,y) ((y<<8)|x)
+//ab Add Breakpoint
+//rb Remove Breakpoint
+//sp Suspend
+void SQDbgServer::ParseMsg(const char *msg)
+{
+
+       switch(*((unsigned short *)msg)){
+               case MSG_ID('a','b'): {
+                       BreakPoint bp;
+                       if(ParseBreakpoint(msg+3,bp)){
+                               AddBreakpoint(bp);
+                               scprintf(_SC("added bp %d %s\n"),bp._line,bp._src.c_str());
+                       }
+                       else
+                               scprintf(_SC("error parsing add breakpoint"));
+                                                        }
+                       break;
+               case MSG_ID('r','b'): {
+                       BreakPoint bp;
+                       if(ParseBreakpoint(msg+3,bp)){
+                               RemoveBreakpoint(bp);
+                               scprintf(_SC("removed bp %d %s\n"),bp._line,bp._src.c_str());
+                       }else
+                               scprintf(_SC("error parsing remove breakpoint"));
+                                                       }
+                       break;
+               case MSG_ID('g','o'):
+                       if(_state!=eDBG_Running){
+                               _state=eDBG_Running;
+                               BeginDocument();
+                                       BeginElement(_SC("resumed"));
+                                       EndElement(_SC("resumed"));
+                               EndDocument();
+//                             Send(_SC("<resumed/>\r\n"));
+                               scprintf(_SC("go (execution resumed)\n"));
+                       }
+                       break;
+               case MSG_ID('s','p'):
+                       if(_state!=eDBG_Suspended){
+                               _state=eDBG_Suspended;
+                               scprintf(_SC("suspend\n"));
+                       }
+                       break;
+               case MSG_ID('s','o'):
+                       if(_state==eDBG_Suspended){
+                               _state=eDBG_StepOver;
+                       }
+                       break;
+               case MSG_ID('s','i'):
+                       if(_state==eDBG_Suspended){
+                               _state=eDBG_StepInto;
+                               scprintf(_SC("step into\n"));
+                       }
+                       break;
+               case MSG_ID('s','r'):
+                       if(_state==eDBG_Suspended){
+                               _state=eDBG_StepReturn;
+                               scprintf(_SC("step return\n"));
+                       }
+                       break;
+               case MSG_ID('d','i'):
+                       if(_state!=eDBG_Disabled){
+                               _state=eDBG_Disabled;
+                               scprintf(_SC("disabled\n"));
+                       }
+                       break;
+               case MSG_ID('a','w'): {
+                       Watch w;
+                       if(ParseWatch(msg+3,w))
+                       {
+                               AddWatch(w);
+                               scprintf(_SC("added watch %d %s\n"),w._id,w._exp.c_str());
+                       }
+                       else
+                               scprintf(_SC("error parsing add watch"));
+                                                               }
+                       break;
+               case MSG_ID('r','w'): {
+                       int id;
+                       if(ParseRemoveWatch(msg+3,id))
+                       {
+                               RemoveWatch(id);
+                               scprintf(_SC("added watch %d\n"),id);
+                       }
+                       else
+                               scprintf(_SC("error parsing remove watch"));
+                                                               }
+                       break;
+               case MSG_ID('t','r'):
+                       scprintf(_SC("terminate from user\n"));
+                       break;
+               case MSG_ID('r','d'):
+                       scprintf(_SC("ready\n"));
+                       _ready=true;
+                       break;
+               default:
+                       scprintf(_SC("unknown packet"));
+
+       }
+}
+
+/*
+       see copyright notice in sqrdbg.h
+*/
+bool SQDbgServer::ParseBreakpoint(const char *msg,BreakPoint &out)
+{
+       static char stemp[MAX_BP_PATH];
+       char *ep=NULL;
+       out._line=strtoul(msg,&ep,16);
+       if(ep==msg || (*ep)!=':')return false;
+
+       char *dest=stemp;
+       ep++;
+       while((*ep)!='\n' && (*ep)!='\0')
+       {
+               *dest=*ep;
+               *dest++;*ep++;
+       }
+       *dest='\0';
+       *dest++;
+       *dest='\0';
+#ifdef _UNICODE
+       int len=(int)strlen(stemp);
+       SQChar *p=sq_getscratchpad(_v,(SQInteger)(mbstowcs(NULL,stemp,len)+2)*sizeof(SQChar));
+       size_t destlen=mbstowcs(p,stemp,len);
+       p[destlen]=_SC('\0');
+       out._src=p;
+#else
+       out._src=stemp;
+#endif
+       return true;
+}
+
+bool SQDbgServer::ParseWatch(const char *msg,Watch &out)
+{
+       char *ep=NULL;
+       out._id=strtoul(msg,&ep,16);
+       if(ep==msg || (*ep)!=':')return false;
+
+       //char *dest=out._src;
+       ep++;
+       while((*ep)!='\n' && (*ep)!='\0')
+       {
+               out._exp.append(1,*ep);
+               *ep++;
+       }
+       return true;
+}
+
+bool SQDbgServer::ParseRemoveWatch(const char *msg,int &id)
+{
+       char *ep=NULL;
+       id=strtoul(msg,&ep,16);
+       if(ep==msg)return false;
+       return true;
+}
+
+
+void SQDbgServer::BreakExecution()
+{
+       _state=eDBG_Suspended;
+       while(_state==eDBG_Suspended){
+               if(SQ_FAILED(sq_rdbg_update(this)))
+                       exit(0);
+               usleep(10);
+       }
+}
+
+//COMMANDS
+void SQDbgServer::AddBreakpoint(BreakPoint &bp)
+{
+       _breakpoints.insert(bp);
+       BeginDocument();
+               BeginElement(_SC("addbreakpoint"));
+                       Attribute(_SC("line"),IntToString(bp._line));
+                       Attribute(_SC("src"),bp._src.c_str());
+               EndElement(_SC("addbreakpoint"));
+       EndDocument();
+}
+
+void SQDbgServer::AddWatch(Watch &w)
+{
+       _watches.insert(w);
+}
+
+void SQDbgServer::RemoveWatch(int id)
+{
+       WatchSetItor itor=_watches.find(Watch(id,_SC("")));
+       if(itor==_watches.end()){
+               BeginDocument();
+               BeginElement(_SC("error"));
+                       Attribute(_SC("desc"),_SC("the watch does not exists"));
+               EndElement(_SC("error"));
+       EndDocument();
+       }
+       else{
+               _watches.erase(itor);
+               scprintf(_SC("removed watch %d\n"),id);
+       }
+}
+
+void SQDbgServer::RemoveBreakpoint(BreakPoint &bp)
+{
+       BreakPointSetItor itor=_breakpoints.find(bp);
+       if(itor==_breakpoints.end()){
+               BeginDocument();
+                       BeginElement(_SC("break"));
+                               Attribute(_SC("desc"),_SC("the breakpoint doesn't exists"));
+                       EndElement(_SC("break"));
+               EndDocument();
+       }
+       else{
+               BeginDocument();
+                       BeginElement(_SC("removebreakpoint"));
+                               Attribute(_SC("line"),IntToString(bp._line));
+                               Attribute(_SC("src"),bp._src.c_str());
+                       EndElement(_SC("removebreakpoint"));
+               EndDocument();
+               _breakpoints.erase(itor);
+       }
+}
+
+void SQDbgServer::Break(int line,const SQChar *src,const SQChar *type,const SQChar *error)
+{
+       if(!error){
+               BeginDocument();
+                       BeginElement(_SC("break"));
+                               Attribute(_SC("line"),IntToString(line));
+                               Attribute(_SC("src"),src);
+                               Attribute(_SC("type"),type);
+                               SerializeState();
+                       EndElement(_SC("break"));
+               EndDocument();
+       }else{
+               BeginDocument();
+                       BeginElement(_SC("break"));
+                               Attribute(_SC("line"),IntToString(line));
+                               Attribute(_SC("src"),src);
+                               Attribute(_SC("type"),type);
+                               Attribute(_SC("error"),error);
+                               SerializeState();
+                       EndElement(_SC("break"));
+               EndDocument();
+       }
+}
+
+void SQDbgServer::SerializeState()
+{
+       sq_pushnull(_v);
+       sq_setdebughook(_v);
+       sq_pushnull(_v);
+       sq_seterrorhandler(_v);
+       const SQChar *sz;
+       sq_pushobject(_v,_serializefunc);
+       sq_pushobject(_v,_debugroot);
+       sq_pushstring(_v,_SC("watches"),-1);
+       sq_newtable(_v);
+       for(WatchSetItor i=_watches.begin(); i!=_watches.end(); ++i)
+       {
+               sq_pushinteger(_v,i->_id);
+               sq_pushstring(_v,i->_exp.c_str(),(int)i->_exp.length());
+               sq_createslot(_v,-3);
+       }
+       sq_rawset(_v,-3);
+       if(SQ_SUCCEEDED(sq_call(_v,1,SQTrue,SQTrue))){
+               if(SQ_SUCCEEDED(sqstd_getblob(_v,-1,(SQUserPointer*)&sz)))
+                       SendChunk(sz);
+       }
+       sq_pop(_v,2);
+
+       SetErrorHandlers();
+}
+
+
+void SQDbgServer::SetErrorHandlers()
+{
+       sq_pushregistrytable(_v);
+       sq_pushstring(_v,SQDBG_DEBUG_HOOK,-1);
+       sq_rawget(_v,-2);
+       sq_setdebughook(_v);
+       sq_pushstring(_v,SQDBG_ERROR_HANDLER,-1);
+       sq_rawget(_v,-2);
+       sq_seterrorhandler(_v);
+       sq_pop(_v,1);
+}
+
+void SQDbgServer::BeginElement(const SQChar *name)
+{
+       _xmlcurrentement++;
+       XMLElementState *self = &xmlstate[_xmlcurrentement];
+       scstrcpy(self->name,name);
+       self->haschildren = false;
+       if(_xmlcurrentement > 0) {
+               XMLElementState *parent = &xmlstate[_xmlcurrentement-1];
+               if(!parent->haschildren) {
+                       SendChunk(_SC(">")); // closes the parent tag
+                       parent->haschildren = true;
+               }
+       }
+       _scratchstring.resize(2+scstrlen(name));
+       scsprintf(&_scratchstring[0],_SC("<%s"),name);
+       SendChunk(&_scratchstring[0]);
+}
+
+void SQDbgServer::Attribute(const SQChar *name,const SQChar *value)
+{
+       XMLElementState *self = &xmlstate[_xmlcurrentement];
+       assert(!self->haschildren); //cannot have attributes if already has children
+       const SQChar *escval = escape_xml(value);
+       _scratchstring.resize(5+scstrlen(name)+scstrlen(escval));
+       scsprintf(&_scratchstring[0],_SC(" %s=\"%s\""),name,escval);
+       SendChunk(&_scratchstring[0]);
+}
+
+void SQDbgServer::EndElement(const SQChar *name)
+{
+       XMLElementState *self = &xmlstate[_xmlcurrentement];
+       assert(scstrcmp(self->name,name) == 0);
+       if(self->haschildren) {
+               _scratchstring.resize(4+scstrlen(name));
+               scsprintf(&_scratchstring[0],_SC("</%s>"),name);
+               SendChunk(&_scratchstring[0]);
+
+       }
+       else {
+               SendChunk(_SC("/>"));
+       }
+       _xmlcurrentement--;
+}
+
+void SQDbgServer::EndDocument()
+{
+       SendChunk(_SC("\r\n"));
+}
+
+//this can be done much better/faster(do we need that?)
+const SQChar *SQDbgServer::escape_xml(const SQChar *s)
+{
+       SQChar *temp=sq_getscratchpad(_v,((int)scstrlen(s)*6) + sizeof(SQChar));
+       SQChar *dest=temp;
+       while(*s!=_SC('\0')){
+               int i=0;
+               bool escaped=false;
+               while(g_escapes[i].esc!=NULL){
+                       if(*s==g_escapes[i].c){
+                               scstrcpy(dest,g_escapes[i].esc);
+                               dest+=scstrlen(g_escapes[i].esc);
+                               escaped=true;
+                               break;
+                       }
+                       i++;
+               }
+               if(!escaped){*dest=*s;*dest++;}
+               *s++;
+       }
+       *dest=_SC('\0');
+       return temp;
+
+}