1 /*	Public domain	*/
2 
3 #include <agar/core/begin.h>
4 
5 #define AG_EVENT_ARGS_MAX 16
6 #define AG_EVENT_NAME_MAX 32
7 
8 #ifdef AG_DEBUG
9 # define AG_PTR(v)	(event->argv[v].type==AG_VARIABLE_POINTER ? event->argv[v].data.p : AG_PtrMismatch())
10 # define AG_OBJECT(v,t)	(AG_OfClass(event->argv[v].data.p,(t))) ? event->argv[v].data.p : AG_ObjectMismatch(AGOBJECT(event->argv[v].data.p)->cls->hier,(t))
11 # define AG_STRING(v)	(event->argv[v].type==AG_VARIABLE_STRING ? event->argv[v].data.s : (char *)AG_PtrMismatch())
12 # define AG_INT(v)	(event->argv[v].type==AG_VARIABLE_INT ? event->argv[v].data.i : AG_IntMismatch())
13 # define AG_UINT(v)	(event->argv[v].type==AG_VARIABLE_UINT ? event->argv[v].data.u : (Uint)AG_IntMismatch())
14 # define AG_LONG(v)	(event->argv[v].type==AG_VARIABLE_SINT32 ? event->argv[v].data.s32 : (Sint32)AG_IntMismatch())
15 # define AG_ULONG(v)	(event->argv[v].type==AG_VARIABLE_UINT32 ? event->argv[v].data.u32 : (Uint32)AG_IntMismatch())
16 # define AG_FLOAT(v)	(event->argv[v].type==AG_VARIABLE_FLOAT ? event->argv[v].data.flt : AG_FloatMismatch())
17 # define AG_DOUBLE(v)	(event->argv[v].type==AG_VARIABLE_DOUBLE ? event->argv[v].data.dbl : (double)AG_FloatMismatch())
18 #else /* !AG_DEBUG */
19 # define AG_PTR(v)	(event->argv[v].data.p)
20 # define AG_OBJECT(v,t)	(event->argv[v].data.p)
21 # define AG_STRING(v)	(event->argv[v].data.s)
22 # define AG_INT(v)	(event->argv[v].data.i)
23 # define AG_UINT(v)	(event->argv[v].data.u)
24 # define AG_LONG(v)	((long)event->argv[v].data.s32)
25 # define AG_ULONG(v)	((Ulong)event->argv[v].data.u32)
26 # define AG_FLOAT(v)	((float)event->argv[v].data.flt)
27 # define AG_DOUBLE(v)	(event->argv[v].data.dbl)
28 #endif /* AG_DEBUG */
29 
30 #define AG_SELF()	AG_PTR(0)
31 #define AG_SENDER()	AG_PTR(event->argc)
32 
33 #define AG_PTR_NAMED(k)		AG_GetNamedPtr(event,(k))
34 #define AG_OBJECT_NAMED(k,cls)	AG_GetNamedObject(event,(k),(cls))
35 #define AG_STRING_NAMED(k)	AG_GetNamedString(event,(k))
36 #define AG_INT_NAMED(k)		AG_GetNamedInt(event,(k))
37 #define AG_UINT_NAMED(k)	AG_GetNamedUint(event,(k))
38 #define AG_LONG_NAMED(k)	AG_GetNamedLong(event,(k))
39 #define AG_ULONG_NAMED(k)	AG_GetNamedUlong(event,(k))
40 #define AG_FLOAT_NAMED(k)	AG_GetNamedFlt(event,(k))
41 #define AG_DOUBLE_NAMED(k)	AG_GetNamedDbl(event,(k))
42 
43 struct ag_timer;
44 struct ag_event_sink;
45 
46 /* Event handler / virtual function */
47 typedef struct ag_event {
48 	char name[AG_EVENT_NAME_MAX];		/* String identifier */
49 	Uint flags;
50 #define	AG_EVENT_ASYNC     0x01			/* Service in separate thread */
51 #define AG_EVENT_PROPAGATE 0x02			/* Forward to child objs */
52 	union ag_function fn;			/* Callback function */
53 	int argc, argc0;			/* Argument count & offset */
54 	AG_Variable argv[AG_EVENT_ARGS_MAX];	/* Argument values */
55 	AG_TAILQ_ENTRY(ag_event) events;	/* Entry in Object */
56 } AG_Event, AG_Function;
57 
58 /* Low-level event sink */
59 enum ag_event_sink_type {
60 	AG_SINK_NONE,
61 	AG_SINK_PROLOGUE,		/* Special event loop prologue */
62 	AG_SINK_EPILOGUE,		/* Special event sink epilogue */
63 	AG_SINK_SPINNER,		/* Special non-blocking sink */
64 	AG_SINK_TERMINATOR,		/* Quit request */
65 	AG_SINK_TIMER,			/* Timer expiration */
66 	AG_SINK_READ,			/* Data available on fd */
67 	AG_SINK_WRITE,			/* Write buffer available on fd */
68 	AG_SINK_FSEVENT,		/* Filesystem event */
69 	AG_SINK_PROCEVENT,		/* Process event */
70 	AG_SINK_LAST
71 };
72 
73 typedef int (*AG_EventSinkFn)(struct ag_event_sink *, AG_Event *);
74 
75 typedef struct ag_event_sink {
76 	enum ag_event_sink_type type;		/* Event filter type */
77 	int ident;				/* Identifier / fd */
78 	Uint flags, flagsMatched;
79 #define AG_FSEVENT_DELETE	0x0001		/* Referenced file deleted */
80 #define AG_FSEVENT_WRITE	0x0002		/* Write occured */
81 #define AG_FSEVENT_EXTEND	0x0004		/* File extended */
82 #define AG_FSEVENT_ATTRIB	0x0008		/* File attributes changed */
83 #define AG_FSEVENT_LINK		0x0010		/* Link count changed */
84 #define AG_FSEVENT_RENAME	0x0020		/* Referenced file renamed */
85 #define AG_FSEVENT_REVOKE	0x0040		/* Filesystem unmount / revoke() */
86 #define AG_PROCEVENT_EXIT	0x1000		/* Process exited */
87 #define AG_PROCEVENT_FORK	0x2000		/* Process forked */
88 #define AG_PROCEVENT_EXEC	0x4000		/* Process exec'd */
89 	AG_EventSinkFn fn;			/* Sink function */
90 	AG_Event fnArgs;			/* Sink function arguments */
91 	AG_TAILQ_ENTRY(ag_event_sink) sinks;    /* Epilogue "sinks" */
92 } AG_EventSink;
93 
94 /* Low-level event source */
95 typedef struct ag_event_source {
96 	int  caps[AG_SINK_LAST];		/* Capabilities */
97 	Uint flags;
98 	int  breakReq;				/* Break from event loop */
99 	int  returnCode;			/* AG_EventLoop() return code */
100 	int  (*sinkFn)(void);
101 	int  (*addTimerFn)(struct ag_timer *, Uint32, int);
102 	void (*delTimerFn)(struct ag_timer *);
103 	int  (*resetTimerFn)(struct ag_timer *, Uint32, int);
104 	AG_TAILQ_HEAD_(ag_event_sink) prologues;   /* Event prologues */
105 	AG_TAILQ_HEAD_(ag_event_sink) epilogues;   /* Event sink epilogues */
106 	AG_TAILQ_HEAD_(ag_event_sink) spinners;	   /* Spinning sinks */
107 	AG_TAILQ_HEAD_(ag_event_sink) sinks;	   /* Normal event sinks */
108 } AG_EventSource;
109 
110 /* Queue of events */
111 typedef struct ag_event_queue {
112 	Uint     nEvents;
113 	AG_Event *events;
114 } AG_EventQ;
115 
116 typedef void (*AG_EventFn)(AG_Event *);
117 
118 #ifdef AG_DEBUG
119 #define AG_EVENT_BOUNDARY_CHECK(ev) \
120 	if ((ev)->argc >= AG_EVENT_ARGS_MAX-1) \
121 		AG_FatalError("Too many AG_Event(3) arguments");
122 #else
123 #define AG_EVENT_BOUNDARY_CHECK(ev)
124 #endif
125 
126 #define AG_EVENT_INS_VAL(eev,tname,aname,member,val) {			\
127 	AG_EVENT_BOUNDARY_CHECK(eev)					\
128 	(eev)->argv[(eev)->argc].type = (tname);			\
129 	if ((aname) != NULL) {						\
130 		AG_Strlcpy((eev)->argv[(eev)->argc].name, (aname),	\
131 		        AG_VARIABLE_NAME_MAX);				\
132 	} else {							\
133 		(eev)->argv[(eev)->argc].name[0] = '\0';		\
134 	}								\
135 	(eev)->argv[(eev)->argc].mutex = NULL;				\
136 	(eev)->argv[(eev)->argc].data.member = (val);			\
137 	(eev)->argv[(eev)->argc].fn.fnVoid = NULL;			\
138 	(eev)->argc++;							\
139 }
140 #define AG_EVENT_INS_ARG(eev,ap,tname,member,t) { 			\
141 	V = &(eev)->argv[(eev)->argc];					\
142 	AG_EVENT_BOUNDARY_CHECK(eev)					\
143 	V->type = (tname);						\
144 	V->mutex = NULL;						\
145 	V->data.member = va_arg(ap,t);					\
146 	V->fn.fnVoid = NULL;						\
147 	(eev)->argc++;							\
148 }
149 #define AG_EVENT_PUSH_ARG(ap,ev) {					\
150 	AG_Variable *V;							\
151 									\
152 	switch (*c) {							\
153 	case 'p':							\
154 		AG_EVENT_INS_ARG((ev),ap,AG_VARIABLE_POINTER,p,void *);	\
155 		break;							\
156 	case 'i':							\
157 		AG_EVENT_INS_ARG((ev),ap,AG_VARIABLE_INT,i,int);	\
158 		break;							\
159 	case 'u':							\
160 		AG_EVENT_INS_ARG((ev),ap,AG_VARIABLE_UINT,i,int);	\
161 		break;							\
162 	case 'f':							\
163 		AG_EVENT_INS_ARG((ev),ap,AG_VARIABLE_FLOAT,flt,double);	\
164 		break;							\
165 	case 'd':							\
166 		AG_EVENT_INS_ARG((ev),ap,AG_VARIABLE_DOUBLE,dbl,double);\
167 		break;							\
168 	case 's':							\
169 		AG_EVENT_INS_ARG((ev),ap,AG_VARIABLE_STRING,s,char *);	\
170 		break;							\
171 	case 'l':							\
172 		switch (c[1]) {						\
173 		case 'i':						\
174 			AG_EVENT_INS_ARG((ev),ap,			\
175 			    AG_VARIABLE_SINT32,				\
176 			    s32,long);					\
177 			break;						\
178 		case 'u':						\
179 			AG_EVENT_INS_ARG((ev),ap,			\
180 			    AG_VARIABLE_UINT32,				\
181 			    u32,unsigned long);				\
182 			break;						\
183 		default:						\
184 			AG_FatalError("Bad AG_Event(3) arguments");	\
185 			continue;					\
186 		}							\
187 		c++;							\
188 		break;							\
189 	case 'C':							\
190 		switch (c[1]) {						\
191 		case 's':						\
192 			AG_EVENT_INS_ARG((ev),ap,			\
193 			    AG_VARIABLE_CONST_STRING,			\
194 			    Cs,const char *);				\
195 			break;						\
196 		case 'p':						\
197 			AG_EVENT_INS_ARG((ev),ap,			\
198 			    AG_VARIABLE_CONST_POINTER,			\
199 			    Cp,const void *);				\
200 			break;						\
201 		default:						\
202 			AG_FatalError("Bad AG_Event(3) arguments");	\
203 			continue;					\
204 		}							\
205 		c++;							\
206 		break;							\
207 	case ' ':							\
208 	case ',':							\
209 	case '%':							\
210 		c++;							\
211 		continue;						\
212 	default:							\
213 		AG_FatalError("Bad AG_Event(3) argument: `%c'", *c);	\
214 		c++;							\
215 		continue;						\
216 	}								\
217 	c++;								\
218 	if (*c == '(' && c[1] != '\0') {				\
219 		char *cEnd;						\
220 		AG_Strlcpy(V->name, &c[1], sizeof(V->name));		\
221 		for (cEnd = V->name; *cEnd != '\0'; cEnd++) {		\
222 			if (*cEnd == ')') {				\
223 				*cEnd = '\0';				\
224 				c+=2;					\
225 				break;					\
226 			}						\
227 			c++;						\
228 		}							\
229 	} else {							\
230 		V->name[0] = '\0';					\
231 	}								\
232 }
233 
234 #define AG_EVENT_GET_ARGS(ev, fmtp)					\
235 	if (fmtp != NULL) {						\
236 		const char *c = (const char *)fmtp;			\
237 		va_list ap;						\
238 									\
239 		va_start(ap, fmtp);					\
240 		while (*c != '\0') {					\
241 			AG_EVENT_PUSH_ARG(ap,(ev));			\
242 		}							\
243 		va_end(ap);						\
244 	}
245 
246 __BEGIN_DECLS
247 int       AG_InitEventSubsystem(Uint);
248 void      AG_DestroyEventSubsystem(void);
249 void      AG_EventInit(AG_Event *);
250 void      AG_EventArgs(AG_Event *, const char *, ...);
251 
252 AG_Event *AG_SetEvent(void *, const char *, AG_EventFn, const char *, ...);
253 AG_Event *AG_AddEvent(void *, const char *, AG_EventFn, const char *, ...);
254 
255 AG_Function *AG_SetVoidFn(void *, AG_VoidFn, const char *, ...);
256 AG_Function *AG_SetIntFn(void *, AG_IntFn, const char *, ...);
257 AG_Function *AG_SetUintFn(void *, AG_UintFn, const char *, ...);
258 AG_Function *AG_SetUint8Fn(void *, AG_Uint8Fn, const char *, ...);
259 AG_Function *AG_SetSint8Fn(void *, AG_Sint8Fn, const char *, ...);
260 AG_Function *AG_SetUint16Fn(void *, AG_Uint16Fn, const char *, ...);
261 AG_Function *AG_SetSint16Fn(void *, AG_Sint16Fn, const char *, ...);
262 AG_Function *AG_SetUint32Fn(void *, AG_Uint32Fn, const char *, ...);
263 AG_Function *AG_SetSint32Fn(void *, AG_Sint32Fn, const char *, ...);
264 #ifdef AG_HAVE_64BIT
265 AG_Function *AG_SetUint64Fn(void *, AG_Uint64Fn, const char *, ...);
266 AG_Function *AG_SetSint64Fn(void *, AG_Sint64Fn, const char *, ...);
267 #endif
268 AG_Function *AG_SetFloatFn(void *, AG_FloatFn, const char *, ...);
269 AG_Function *AG_SetDoubleFn(void *, AG_DoubleFn, const char *, ...);
270 #ifdef AG_HAVE_LONG_DOUBLE
271 AG_Function *AG_SetLongDoubleFn(void *, AG_LongDoubleFn, const char *, ...);
272 #endif
273 AG_Function *AG_SetStringFn(void *, AG_StringFn, const char *, ...);
274 AG_Function *AG_SetPointerFn(void *, AG_PointerFn, const char *, ...);
275 AG_Function *AG_SetConstPointerFn(void *, AG_ConstPointerFn, const char *, ...);
276 AG_Function *AG_SetTextFn(void *, AG_TextFn, const char *, ...);
277 
278 void      AG_UnsetEvent(void *, const char *);
279 void      AG_PostEvent(void *, void *, const char *, const char *, ...);
280 void      AG_PostEventByPtr(void *, void *, AG_Event *, const char *, ...);
281 AG_Event *AG_FindEventHandler(void *, const char *);
282 
283 void      AG_InitEventQ(AG_EventQ *);
284 void      AG_FreeEventQ(AG_EventQ *);
285 void      AG_QueueEvent(AG_EventQ *, const char *, const char *, ...);
286 
287 int       AG_SchedEvent(void *, void *, Uint32, const char *,
288                         const char *, ...);
289 void      AG_ForwardEvent(void *, void *, AG_Event *);
290 
291 int             AG_EventLoop(void);
292 AG_EventSource *AG_GetEventSource(void);
293 AG_EventSink   *AG_AddEventPrologue(AG_EventSinkFn, const char *, ...);
294 AG_EventSink   *AG_AddEventEpilogue(AG_EventSinkFn, const char *, ...);
295 AG_EventSink   *AG_AddEventSpinner(AG_EventSinkFn, const char *, ...);
296 AG_EventSink   *AG_AddEventSink(enum ag_event_sink_type, int, Uint,
297                                 AG_EventSinkFn, const char *, ...);
298 void            AG_DelEventPrologue(AG_EventSink *);
299 void            AG_DelEventEpilogue(AG_EventSink *);
300 void            AG_DelEventSpinner(AG_EventSink *);
301 void            AG_DelEventSink(AG_EventSink *);
302 void            AG_DelEventSinksByIdent(enum ag_event_sink_type, int, Uint);
303 void            AG_Terminate(int);
304 void            AG_TerminateEv(AG_Event *);
305 
306 int             AG_AddTimerKQUEUE(struct ag_timer *, Uint32, int);
307 void            AG_DelTimerKQUEUE(struct ag_timer *);
308 int             AG_AddTimerTIMERFD(struct ag_timer *, Uint32, int);
309 void            AG_DelTimerTIMERFD(struct ag_timer *);
310 int             AG_EventSinkKQUEUE(void);
311 int             AG_EventSinkTIMERFD(void);
312 int             AG_EventSinkTIMEDSELECT(void);
313 int             AG_EventSinkSELECT(void);
314 int             AG_EventSinkSPINNER(void);
315 
316 /* Push arguments onto an Event structure. */
AG_EventPushPointer(AG_Event * ev,const char * key,void * val)317 static __inline__ void AG_EventPushPointer(AG_Event *ev, const char *key, void *val) { AG_EVENT_INS_VAL(ev, AG_VARIABLE_POINTER, key, p, val); }
AG_EventPushString(AG_Event * ev,const char * key,char * val)318 static __inline__ void AG_EventPushString(AG_Event *ev, const char *key, char *val)  { AG_EVENT_INS_VAL(ev, AG_VARIABLE_STRING, key, s, val); }
AG_EventPushInt(AG_Event * ev,const char * key,int val)319 static __inline__ void AG_EventPushInt(AG_Event *ev, const char *key, int val)       { AG_EVENT_INS_VAL(ev, AG_VARIABLE_INT, key, i, val); }
AG_EventPushUint(AG_Event * ev,const char * key,Uint val)320 static __inline__ void AG_EventPushUint(AG_Event *ev, const char *key, Uint val)     { AG_EVENT_INS_VAL(ev, AG_VARIABLE_UINT, key, i, (int)val); }
AG_EventPushLong(AG_Event * ev,const char * key,long val)321 static __inline__ void AG_EventPushLong(AG_Event *ev, const char *key, long val)     { AG_EVENT_INS_VAL(ev, AG_VARIABLE_SINT32, key, s32, (Sint32)val); }
AG_EventPushUlong(AG_Event * ev,const char * key,Ulong val)322 static __inline__ void AG_EventPushUlong(AG_Event *ev, const char *key, Ulong val)   { AG_EVENT_INS_VAL(ev, AG_VARIABLE_UINT32, key, u32, (Uint32)val); }
AG_EventPushFloat(AG_Event * ev,const char * key,float val)323 static __inline__ void AG_EventPushFloat(AG_Event *ev, const char *key, float val)   { AG_EVENT_INS_VAL(ev, AG_VARIABLE_FLOAT, key, flt, val); }
AG_EventPushDouble(AG_Event * ev,const char * key,double val)324 static __inline__ void AG_EventPushDouble(AG_Event *ev, const char *key, double val) { AG_EVENT_INS_VAL(ev, AG_VARIABLE_DOUBLE, key, dbl, val); }
AG_EventPopArgument(AG_Event * ev)325 static __inline__ void AG_EventPopArgument(AG_Event *ev) { ev->argc--; }
326 
327 /*
328  * Accessor functions for AG_FOO_NAMED() macros.
329  */
330 static __inline__ AG_Variable *
AG_GetNamedEventArg(AG_Event * ev,const char * key)331 AG_GetNamedEventArg(AG_Event *ev, const char *key)
332 {
333 	int i;
334 
335 	for (i = 0; i < ev->argc; i++) {
336 		if (strcmp(ev->argv[i].name, key) == 0)
337 			return (&ev->argv[i]);
338 	}
339 	AG_FatalError("No such AG_Event argument: \"%s\"", key);
340 	return (NULL);
341 }
342 static __inline__ void *
AG_GetNamedPtr(AG_Event * event,const char * key)343 AG_GetNamedPtr(AG_Event *event, const char *key)
344 {
345 	AG_Variable *V = AG_GetNamedEventArg(event, key);
346 	return (V->data.p);
347 }
348 static __inline__ char *
AG_GetNamedString(AG_Event * event,const char * key)349 AG_GetNamedString(AG_Event *event, const char *key)
350 {
351 	AG_Variable *V = AG_GetNamedEventArg(event, key);
352 	return (V->data.s);
353 }
354 static __inline__ int
AG_GetNamedInt(AG_Event * event,const char * key)355 AG_GetNamedInt(AG_Event *event, const char *key)
356 {
357 	AG_Variable *V = AG_GetNamedEventArg(event, key);
358 	return (V->data.i);
359 }
360 static __inline__ Uint
AG_GetNamedUint(AG_Event * event,const char * key)361 AG_GetNamedUint(AG_Event *event, const char *key)
362 {
363 	AG_Variable *V = AG_GetNamedEventArg(event, key);
364 	return (V->data.u);
365 }
366 static __inline__ long
AG_GetNamedLong(AG_Event * event,const char * key)367 AG_GetNamedLong(AG_Event *event, const char *key)
368 {
369 	AG_Variable *V = AG_GetNamedEventArg(event, key);
370 	return ((long)V->data.s32);
371 }
372 static __inline__ Ulong
AG_GetNamedUlong(AG_Event * event,const char * key)373 AG_GetNamedUlong(AG_Event *event, const char *key)
374 {
375 	AG_Variable *V = AG_GetNamedEventArg(event, key);
376 	return ((Ulong)V->data.u32);
377 }
378 static __inline__ float
AG_GetNamedFlt(AG_Event * event,const char * key)379 AG_GetNamedFlt(AG_Event *event, const char *key)
380 {
381 	AG_Variable *V = AG_GetNamedEventArg(event, key);
382 	return (V->data.flt);
383 }
384 static __inline__ double
AG_GetNamedDbl(AG_Event * event,const char * key)385 AG_GetNamedDbl(AG_Event *event, const char *key)
386 {
387 	AG_Variable *V = AG_GetNamedEventArg(event, key);
388 	return (V->data.dbl);
389 }
390 
391 #ifdef AG_LEGACY
392 # define AG_EVENT_SCHEDULED 0x04 /* Obsolete since AG_Timer(3) */
393 # define AG_CHAR(v) ((char)event->argv[v].data.i)
394 # define AG_UCHAR(v) ((Uchar)event->argv[v].data.u)
395 # define AG_EventPushChar(ev,key,val) AG_EventPushInt((ev),(key),(int)(val))
396 # define AG_EventPushUchar(ev,key,val) AG_EventPushUint((ev),(key),(Uint)(val))
397 #endif
398 __END_DECLS
399 
400 #include <agar/core/close.h>
401