1 /*
2  * Copyright (c) 2009 Mat Sutcliffe (oktal@gmx.co.uk)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
18  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23  * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "EXTERN.h"
27 #include "perl.h"
28 #include "XSUB.h"
29 
30 #include <agar/core.h>
31 #include <agar/gui.h>
32 #include "perl_agar.h"
33 
34 /* How many event args belong to perl? */
35 static const int apNumOurArgs = 1;
36 
37 /* Store a coderef with an event handler and increment its reference count. */
AP_StoreEventPV(AG_Event * event,SV * pv)38 void AP_StoreEventPV(AG_Event *event, SV *pv)
39 {
40 	if (event != NULL) {
41 		AG_EventPushPointer(event, "perl.pv", pv);
42 		SvREFCNT_inc(pv);
43 	}
44 }
45 
46 /* An event handler routine that calls the coderef stored in its argv[1]. */
AP_EventHandler(AG_Event * event)47 void AP_EventHandler(AG_Event *event)
48 {
49 	dSP;
50 	SV *pv = AP_RetrieveEventPV(event);
51 	if (pv == NULL) { return; }
52 
53 	ENTER;
54 	SAVETMPS;
55 
56 	PUSHMARK(SP);
57 	XPUSHs(sv_setref_iv(sv_newmortal(), "Agar::Event", PTR2IV(event)));
58 	PUTBACK;
59 
60 	call_sv(pv, G_VOID);
61 
62 	FREETMPS;
63 	LEAVE;
64 }
65 
66 /* A variant of the above that decrements the reference count of the coderef. */
AP_EventHandlerDecRef(AG_Event * event)67 void AP_EventHandlerDecRef(AG_Event *event)
68 {
69 	AP_EventHandler(event);
70 	AP_DecRefEventPV(event);
71 }
72 
73 /* Safely retrieves a coderef stored in an event handler. */
AP_RetrieveEventPV(AG_Event * event)74 SV * AP_RetrieveEventPV(AG_Event *event)
75 {
76 	if (event == NULL) { return NULL; }
77 	if (event->handler == AP_EventHandler ||
78 	    event->handler == AP_EventHandlerDecRef) {
79 		return AG_PTR(1);
80 	}
81 	return NULL;
82 }
83 
84 /* Safely decrements the reference count of an event handler coderef. */
AP_DecRefEventPV(AG_Event * event)85 void AP_DecRefEventPV(AG_Event *event)
86 {
87 	SV *pv = AP_RetrieveEventPV(event);
88 	if (pv != NULL) {
89 		SvREFCNT_dec(pv);
90 	}
91 }
92 
93 MODULE = Agar::Event	PACKAGE = Agar::Event	PREFIX = AG_
94 PROTOTYPES: ENABLE
95 VERSIONCHECK: DISABLE
96 
97 const char *
98 name(event)
99 	Agar::Event event
100 CODE:
101 	RETVAL = event->name;
102 OUTPUT:
103 	RETVAL
104 
105 Agar::Object
106 receiver(event)
107 	Agar::Event event
108 CODE:
109 	RETVAL = AG_SELF();
110 OUTPUT:
111 	RETVAL
112 
113 Agar::Object
114 sender(event)
115 	Agar::Event event
116 CODE:
117 	if ((RETVAL = AG_SENDER()) == NULL) {
118 		XSRETURN_UNDEF;
119 	}
120 OUTPUT:
121 	RETVAL
122 
123 IV
124 ptr(event, index)
125 	Agar::Event event
126 	int index
127 PREINIT:
128 	static const enum ag_variable_type argtype = AG_VARIABLE_POINTER;
129 CODE:
130 	index += apNumOurArgs;
131 	if (index <= apNumOurArgs || index >= event->argc ||
132 	    event->argv[index].type != argtype) {
133 		XSRETURN_UNDEF;
134 	}
135 	RETVAL = PTR2IV(AG_PTR(index));
136 OUTPUT:
137 	RETVAL
138 
139 IV
140 ptrNamed(event, name)
141 	Agar::Event event
142 	const char *name
143 PREINIT:
144 	static const enum ag_variable_type argtype = AG_VARIABLE_POINTER;
145 CODE:
146 	RETVAL = PTR2IV(AG_PTR_NAMED(name));
147 OUTPUT:
148 	RETVAL
149 
150 Agar::Object
151 object(event, index, classSpec)
152 	Agar::Event event
153 	int index
154 	const char * classSpec
155 PREINIT:
156 	static const enum ag_variable_type argtype = AG_VARIABLE_POINTER;
157 CODE:
158 	index += apNumOurArgs;
159 	if (index <= apNumOurArgs || index >= event->argc ||
160 	    event->argv[index].type != argtype) {
161 		XSRETURN_UNDEF;
162 	}
163 	RETVAL = AG_OBJECT(index, classSpec);
164 OUTPUT:
165 	RETVAL
166 
167 SV *
168 string(event, index)
169 	Agar::Event event
170 	int index
171 PREINIT:
172 	static const enum ag_variable_type argtype = AG_VARIABLE_STRING;
173 CODE:
174 	index += apNumOurArgs;
175 	if (index <= apNumOurArgs || index >= event->argc ||
176 	    event->argv[index].type != argtype) {
177 		XSRETURN_UNDEF;
178 	}
179 	RETVAL = newSVpv(AG_STRING(index), 0);
180 OUTPUT:
181 	RETVAL
182 
183 int
184 int(event, index)
185 	Agar::Event event
186 	int index
187 PREINIT:
188 	static const enum ag_variable_type argtype = AG_VARIABLE_INT;
189 CODE:
190 	index += apNumOurArgs;
191 	if (index <= apNumOurArgs || index >= event->argc ||
192 	    event->argv[index].type != argtype) {
193 		XSRETURN_UNDEF;
194 	}
195 	RETVAL = AG_INT(index);
196 OUTPUT:
197 	RETVAL
198 
199 Uint
200 Uint(event, index)
201 	Agar::Event event
202 	int index
203 PREINIT:
204 	static const enum ag_variable_type argtype = AG_VARIABLE_UINT;
205 CODE:
206 	index += apNumOurArgs;
207 	if (index <= apNumOurArgs || index >= event->argc ||
208 	    event->argv[index].type != argtype) {
209 		XSRETURN_UNDEF;
210 	}
211 	RETVAL = AG_UINT(index);
212 OUTPUT:
213 	RETVAL
214 
215 long
216 long(event, index)
217 	Agar::Event event
218 	int index
219 PREINIT:
220 	static const enum ag_variable_type argtype = AG_VARIABLE_SINT32;
221 CODE:
222 	index += apNumOurArgs;
223 	if (index <= apNumOurArgs || index >= event->argc ||
224 	    event->argv[index].type != argtype) {
225 		XSRETURN_UNDEF;
226 	}
227 	RETVAL = AG_LONG(index);
228 OUTPUT:
229 	RETVAL
230 
231 Ulong
232 Ulong(event, index)
233 	Agar::Event event
234 	int index
235 PREINIT:
236 	static const enum ag_variable_type argtype = AG_VARIABLE_UINT32;
237 CODE:
238 	index += apNumOurArgs;
239 	if (index <= apNumOurArgs || index >= event->argc ||
240 	    event->argv[index].type != argtype) {
241 		XSRETURN_UNDEF;
242 	}
243 	RETVAL = AG_ULONG(index);
244 OUTPUT:
245 	RETVAL
246 
247 float
248 float(event, index)
249 	Agar::Event event
250 	int index
251 PREINIT:
252 	static const enum ag_variable_type argtype = AG_VARIABLE_FLOAT;
253 CODE:
254 	index += apNumOurArgs;
255 	if (index <= apNumOurArgs || index >= event->argc ||
256 	    event->argv[index].type != argtype) {
257 		XSRETURN_UNDEF;
258 	}
259 	RETVAL = AG_FLOAT(index);
260 OUTPUT:
261 	RETVAL
262 
263 double
264 double(event, index)
265 	Agar::Event event
266 	int index
267 PREINIT:
268 	static const enum ag_variable_type argtype = AG_VARIABLE_DOUBLE;
269 CODE:
270 	index += apNumOurArgs;
271 	if (index <= apNumOurArgs || index >= event->argc ||
272 	    event->argv[index].type != argtype) {
273 		XSRETURN_UNDEF;
274 	}
275 	RETVAL = AG_DOUBLE(index);
276 OUTPUT:
277 	RETVAL
278 
279