7bf3b382a6cac1c55261b0b1738952edebcd149a
[supertux.git] / external / squirrel / sqdbg / sqrdbg.cpp
1 /*
2         see copyright notice in sqrdbg.h
3 */
4 #include <squirrel.h>
5 #include "sqrdbg.h"
6 #include "sqdbgserver.h"
7 SQInteger debug_hook(HSQUIRRELVM v);
8 SQInteger error_handler(HSQUIRRELVM v);
9
10 #include "serialize_state.inl"
11
12 HSQREMOTEDBG sq_rdbg_init(HSQUIRRELVM v,unsigned short port,SQBool autoupdate)
13 {
14         sockaddr_in bindaddr;
15 #ifdef _WIN32
16         WSADATA wsadata;
17         if (WSAStartup (MAKEWORD(1,1), &wsadata) != 0){
18                 return NULL;
19         }
20 #endif
21
22         SQDbgServer *rdbg = new SQDbgServer(v);
23         rdbg->_autoupdate = autoupdate?true:false;
24         rdbg->_accept = socket(AF_INET,SOCK_STREAM,0);
25         bindaddr.sin_family = AF_INET;
26         bindaddr.sin_port = htons(port);
27         bindaddr.sin_addr.s_addr = htonl (INADDR_ANY);
28         if(bind(rdbg->_accept,(sockaddr*)&bindaddr,sizeof(bindaddr))==SOCKET_ERROR){
29                 delete rdbg;
30                 sq_throwerror(v,_SC("failed to bind the socket"));
31                 return NULL;
32         }
33         if(!rdbg->Init()) {
34                 delete rdbg;
35                 sq_throwerror(v,_SC("failed to initialize the debugger"));
36                 return NULL;
37         }
38
39     return rdbg;
40 }
41
42 SQRESULT sq_rdbg_waitforconnections(HSQREMOTEDBG rdbg)
43 {
44         if(SQ_FAILED(sq_compilebuffer(rdbg->_v,serialize_state_nut,(SQInteger)scstrlen(serialize_state_nut),_SC("SERIALIZE_STATE"),SQFalse))) {
45                 sq_throwerror(rdbg->_v,_SC("error compiling the serialization function"));
46         }
47         sq_getstackobj(rdbg->_v,-1,&rdbg->_serializefunc);
48         sq_addref(rdbg->_v,&rdbg->_serializefunc);
49         sq_pop(rdbg->_v,1);
50
51         sockaddr_in cliaddr;
52         socklen_t addrlen=sizeof(cliaddr);
53         if(listen(rdbg->_accept,0)==SOCKET_ERROR)
54                 return sq_throwerror(rdbg->_v,_SC("error on listen(socket)"));
55         rdbg->_endpoint = accept(rdbg->_accept,(sockaddr*)&cliaddr,&addrlen);
56         //do not accept any other connection
57         sqdbg_closesocket(rdbg->_accept);
58         rdbg->_accept = INVALID_SOCKET;
59         if(rdbg->_endpoint==INVALID_SOCKET){
60                 return sq_throwerror(rdbg->_v,_SC("error accept(socket)"));
61         }
62         while(!rdbg->_ready){
63                 sq_rdbg_update(rdbg);
64         }
65         return SQ_OK;
66 }
67
68 SQRESULT sq_rdbg_update(HSQREMOTEDBG rdbg)
69 {
70         TIMEVAL time;
71         time.tv_sec=0;
72         time.tv_usec=0;
73         fd_set read_flags;
74     FD_ZERO(&read_flags);
75         FD_SET(rdbg->_endpoint, &read_flags);
76         select(FD_SETSIZE, &read_flags, NULL, NULL, &time);
77
78         if(FD_ISSET(rdbg->_endpoint,&read_flags)){
79                 char temp[1024];
80                 int size=0;
81                 char c,prev=0;
82                 memset(&temp,0,sizeof(temp));
83                 int res;
84                 FD_CLR(rdbg->_endpoint, &read_flags);
85                 while((res = recv(rdbg->_endpoint,&c,1,0))>0){
86
87                         if(c=='\n')break;
88                         if(c!='\r'){
89                                 temp[size]=c;
90                                 prev=c;
91                                 size++;
92                         }
93                 }
94                 switch(res){
95                 case 0:
96                         return sq_throwerror(rdbg->_v,_SC("disconnected"));
97                 case SOCKET_ERROR:
98                         return sq_throwerror(rdbg->_v,_SC("socket error"));
99         }
100
101                 temp[size]=0;
102                 temp[size+1]=0;
103                 rdbg->ParseMsg(temp);
104         }
105         return SQ_OK;
106 }
107
108 SQInteger debug_hook(HSQUIRRELVM v)
109 {
110         SQUserPointer up;
111         SQInteger event_type,line;
112         const SQChar *src,*func;
113         sq_getinteger(v,2,&event_type);
114         sq_getstring(v,3,&src);
115         sq_getinteger(v,4,&line);
116         sq_getstring(v,5,&func);
117         sq_getuserpointer(v,-1,&up);
118         HSQREMOTEDBG rdbg = (HSQREMOTEDBG)up;
119         rdbg->Hook(event_type,line,src,func);
120         if(rdbg->_autoupdate) {
121                 if(SQ_FAILED(sq_rdbg_update(rdbg)))
122                         return sq_throwerror(v,_SC("socket failed"));
123         }
124         return 0;
125 }
126
127 SQInteger error_handler(HSQUIRRELVM v)
128 {
129         SQUserPointer up;
130         const SQChar *sErr=NULL;
131         const SQChar *fn=_SC("unknown");
132         const SQChar *src=_SC("unknown");
133         int line=-1;
134         SQStackInfos si;
135         sq_getuserpointer(v,-1,&up);
136         HSQREMOTEDBG rdbg=(HSQREMOTEDBG)up;
137         if(SQ_SUCCEEDED(sq_stackinfos(v,1,&si)))
138         {
139                 if(si.funcname)fn=si.funcname;
140                 if(si.source)src=si.source;
141                 line=si.line;
142                 scprintf(_SC("*FUNCTION [%s] %s line [%d]\n"),fn,src,si.line);
143         }
144         if(sq_gettop(v)>=1){
145                 if(SQ_SUCCEEDED(sq_getstring(v,2,&sErr)))       {
146                         scprintf(_SC("\nAN ERROR HAS OCCURED [%s]\n"),sErr);
147                         rdbg->Break(si.line,src,_SC("error"),sErr);
148                 }
149                 else{
150                         scprintf(_SC("\nAN ERROR HAS OCCURED [unknown]\n"));
151                         rdbg->Break(si.line,src,_SC("error"),_SC("unknown"));
152                 }
153         }
154         rdbg->BreakExecution();
155         return 0;
156 }
157
158
159 SQRESULT sq_rdbg_shutdown(HSQREMOTEDBG rdbg)
160 {
161         delete rdbg;
162 #ifdef _WIN32
163         WSACleanup();
164 #endif
165         return SQ_OK;
166 }