1 #include "apricot.h"
2 #include <ctype.h>
3 #include "Component.h"
4 #include "Application.h"
5 #include <Component.inc>
6
7 #ifdef __cplusplus
8 extern "C" {
9 #endif
10
11
12 #undef my
13 #define inherited CObject->
14 #define my ((( PComponent) self)-> self)
15 #define var (( PComponent) self)
16
17 typedef Bool ActionProc ( Handle self, Handle item, void * params);
18 typedef ActionProc *PActionProc;
19
20 void
Component_init(Handle self,HV * profile)21 Component_init( Handle self, HV * profile)
22 {
23 dPROFILE;
24 SV * res;
25 HV * hv;
26 HE * he;
27 inherited init( self, profile);
28 if ( !my-> validate_owner( self, &var-> owner, profile)) {
29 var-> stage = csDeadInInit;
30 croak( "Illegal 'owner' reference passed to %s::%s%s", my-> className, "init",
31 application ? "" : ". Probably you forgot to include 'use Prima::Application' in your code. Error");
32 }
33 if ( var-> owner)
34 ((( PComponent) var-> owner)-> self)-> attach( var-> owner, self);
35 my-> set_name( self, pget_sv( name));
36 my-> set_delegations( self, pget_sv( delegations));
37 var-> evQueue = plist_create( 8, 8);
38 apc_component_create( self);
39
40 res = my-> notification_types( self);
41 hv = ( HV *) SvRV( res);
42 hv_iterinit( hv);
43 while (( he = hv_iternext( hv)) != NULL) {
44 char buf[ 1024];
45 SV ** holder;
46 int len = snprintf( buf, 1023, "on%s", HeKEY( he));
47 holder = hv_fetch( profile, buf, len, 0);
48 if ( holder == NULL || SvTYPE( *holder) == SVt_NULL) continue;
49 my-> add_notification( self, HeKEY( he), *holder, self, -1);
50 }
51 sv_free( res);
52 }
53
54 void
Component_setup(Handle self)55 Component_setup( Handle self)
56 {
57 Event ev = {cmCreate};
58 ev. gen. source = self;
59 my-> message( self, &ev);
60
61 if ( var-> owner) {
62 ev. cmd = cmChildEnter;
63 ev. gen. source = var-> owner;
64 ev. gen. H = self;
65 CComponent( var-> owner)-> message( var-> owner, &ev);
66 }
67 }
68
bring_by_name(Handle self,PComponent item,char * name)69 static Bool bring_by_name( Handle self, PComponent item, char * name)
70 {
71 return strcmp( name, item-> name) == 0;
72 }
73
74 Handle
Component_bring(Handle self,char * componentName)75 Component_bring( Handle self, char * componentName)
76 {
77 return my-> first_that_component( self, (void*)bring_by_name, componentName);
78 }
79
80 static Bool
detach_all(Handle child,Handle self)81 detach_all( Handle child, Handle self)
82 {
83 my-> detach( self, child, true);
84 return false;
85 }
86
87 void
Component_cleanup(Handle self)88 Component_cleanup( Handle self)
89 {
90 Event ev = {cmDestroy};
91
92 if ( var-> owner) {
93 Event ev = {cmChildLeave};
94 ev. gen. source = var-> owner;
95 ev. gen. H = self;
96 CComponent( var-> owner)-> message( var-> owner, &ev);
97 }
98
99 if ( var-> components != NULL)
100 list_first_that( var-> components, (void*)detach_all, ( void*) self);
101
102 ev. gen. source = self;
103 my-> message( self, &ev);
104 }
105
106 static Bool
free_private_posts(PostMsg * msg,void * dummy)107 free_private_posts( PostMsg * msg, void * dummy)
108 {
109 sv_free( msg-> info1);
110 sv_free( msg-> info2);
111 free( msg);
112 return false;
113 }
114
115 static Bool
free_queue(PEvent event,void * dummy)116 free_queue( PEvent event, void * dummy)
117 {
118 free( event);
119 return false;
120 }
121
122 static Bool
free_eventref(Handle self,Handle * org)123 free_eventref( Handle self, Handle * org)
124 {
125 if ( var-> refs) list_delete( var-> refs, *org);
126 my-> unlink_notifier( self, *org);
127 return false;
128 }
129
130 void
Component_done(Handle self)131 Component_done( Handle self)
132 {
133 if ( var-> owner)
134 CComponent( var-> owner)-> detach( var-> owner, self, false);
135 if ( var-> eventIDs) {
136 int i;
137 PList list = var-> events;
138 hash_destroy( var-> eventIDs, false);
139 var-> eventIDs = NULL;
140 for ( i = 0; i < var-> eventIDCount; i++) {
141 int j;
142 for ( j = 0; j < list-> count; j += 2)
143 sv_free(( SV *) list-> items[ j + 1]);
144 list_destroy( list++);
145 }
146 free( var-> events);
147 var-> events = NULL;
148 }
149
150
151 if ( var-> refs) {
152 Handle * pself = &self;
153 list_first_that( var-> refs, (void*)free_eventref, pself);
154 plist_destroy( var-> refs);
155 var-> refs = NULL;
156 }
157
158 if ( var-> postList != NULL) {
159 list_first_that( var-> postList, (void*)free_private_posts, NULL);
160 list_destroy( var-> postList);
161 free( var-> postList);
162 var-> postList = NULL;
163 }
164 if ( var-> evQueue != NULL)
165 {
166 list_first_that( var-> evQueue, (void*)free_queue, NULL);
167 list_destroy( var-> evQueue);
168 free( var-> evQueue);
169 var-> evQueue = NULL;
170 }
171 if ( var-> components != NULL) {
172 list_destroy( var-> components);
173 free( var-> components);
174 var-> components = NULL;
175 }
176 apc_component_destroy( self);
177 free( var-> name);
178 var-> name = NULL;
179 free( var-> evStack);
180 var-> evStack = NULL;
181 inherited done( self);
182 }
183
184 void
Component_attach(Handle self,Handle object)185 Component_attach( Handle self, Handle object)
186 {
187 if ( var-> stage > csNormal) return;
188
189 if ( object && kind_of( object, CComponent)) {
190 if ( var-> components == NULL)
191 var-> components = plist_create( 8, 8);
192 else
193 if ( list_index_of( var-> components, object) >= 0) {
194 warn( "Object attach failed");
195 return;
196 }
197 list_add( var-> components, object);
198 SvREFCNT_inc( SvRV(( PObject( object))-> mate));
199 } else
200 warn( "Object attach failed");
201 }
202
203 void
Component_detach(Handle self,Handle object,Bool kill)204 Component_detach( Handle self, Handle object, Bool kill)
205 {
206 if ( object && ( var-> components != NULL)) {
207 int index = list_index_of( var-> components, object);
208 if ( index >= 0) {
209 list_delete_at( var-> components, index);
210 --SvREFCNT( SvRV(( PObject( object))-> mate));
211 if ( kill) Object_destroy( object);
212 }
213 }
214 }
215
216 SV *
Component_name(Handle self,Bool set,SV * name)217 Component_name( Handle self, Bool set, SV * name)
218 {
219 if ( set) {
220 free( var-> name);
221 var-> name = NULL;
222 var-> name = duplicate_string( SvPV_nolen( name));
223 opt_assign( optUTF8_name, prima_is_utf8_sv(name));
224 if ( var-> stage >= csNormal)
225 apc_component_fullname_changed_notify( self);
226 } else {
227 name = newSVpv( var-> name ? var-> name : "", 0);
228 if ( is_opt( optUTF8_name)) SvUTF8_on( name);
229 return name;
230 }
231 return NULL_SV;
232 }
233
234 Handle
Component_owner(Handle self,Bool set,Handle owner)235 Component_owner( Handle self, Bool set, Handle owner)
236 {
237 HV * profile;
238 if ( !set)
239 return var-> owner;
240 profile = newHV();
241 pset_H( owner, owner);
242 my-> set( self, profile);
243 sv_free(( SV *) profile);
244 return NULL_HANDLE;
245 }
246
247
248 void
Component_set(Handle self,HV * profile)249 Component_set( Handle self, HV * profile)
250 {
251 /* this can eliminate unwilling items */
252 /* from HV before indirect Object::set */
253 my-> update_sys_handle( self, profile);
254
255 if ( pexist( owner)) {
256 Handle owner, oldOwner = var-> owner;
257 if ( !my-> validate_owner( self, &owner, profile))
258 croak( "Illegal 'owner' reference passed to %s::%s", my-> className, "set");
259
260 if ( oldOwner && oldOwner != owner) {
261 Event ev;
262 ev. cmd = cmChildLeave;
263 ev. gen. source = oldOwner;
264 ev. gen. H = self;
265 if ( oldOwner)
266 CComponent( oldOwner)-> message( oldOwner, &ev);
267 }
268
269 my-> migrate( self, owner);
270 var-> owner = owner;
271 pdelete( owner);
272
273 if ( oldOwner != owner) {
274 Event ev;
275
276 ev. cmd = cmChildEnter;
277 ev. gen. source = owner;
278 ev. gen. H = self;
279 if ( owner)
280 CComponent( owner)-> message( owner, &ev);
281
282 ev. cmd = cmChangeOwner;
283 ev. gen. source = self;
284 ev. gen. H = oldOwner;
285 my-> message( self, &ev);
286 }
287 }
288
289 inherited set ( self, profile);
290 }
291
292 static Bool
find_dup_msg(PEvent event,int * cmd)293 find_dup_msg( PEvent event, int * cmd)
294 {
295 return event-> cmd == *cmd;
296 }
297
298 Bool
Component_message(Handle self,PEvent event)299 Component_message( Handle self, PEvent event)
300 {
301 Bool ret = false;
302 if ( var-> stage == csNormal) {
303 if ( var-> evQueue) goto Constructing;
304 ForceProcess:
305 protect_object( self);
306 my-> push_event( self);
307 my-> handle_event( self, event);
308 ret = my-> pop_event( self);
309 if ( !ret) event-> cmd = 0;
310 unprotect_object( self);
311 } else if ( var-> stage == csConstructing) {
312 if ( var-> evQueue == NULL)
313 croak("Object set twice to constructing stage");
314 Constructing:
315 switch ( event-> cmd & ctQueueMask) {
316 case ctDiscardable:
317 break;
318 case ctPassThrough:
319 goto ForceProcess;
320 case ctSingle:
321 event-> cmd = ( event-> cmd & ~ctQueueMask) | ctSingleResponse;
322 if ( list_first_that( var-> evQueue, (void*)find_dup_msg, &event-> cmd) >= 0)
323 break;
324 default:
325 {
326 void * ev = malloc( sizeof( Event));
327 if ( ev)
328 list_add( var-> evQueue, ( Handle) memcpy( ev, event, sizeof( Event)));
329 }
330 }
331 } else if (( var-> stage < csFinalizing) && ( event-> cmd & ctNoInhibit))
332 goto ForceProcess;
333 return ret;
334 }
335
336
337 Bool
Component_can_event(Handle self)338 Component_can_event( Handle self)
339 {
340 return var-> stage == csNormal;
341 }
342
343 void
Component_clear_event(Handle self)344 Component_clear_event( Handle self)
345 {
346 my-> set_eventFlag( self, 0);
347 }
348
349 void
Component_push_event(Handle self)350 Component_push_event( Handle self)
351 {
352 if ( var-> stage == csDead)
353 return;
354 if ( var-> evPtr == var-> evLimit) {
355 char * newStack = allocs( 16 + var-> evLimit);
356 if ( !newStack) croak("Not enough memory");
357 if ( var-> evStack) {
358 memcpy( newStack, var-> evStack, var-> evLimit);
359 free( var-> evStack);
360 }
361 var-> evStack = newStack;
362 var-> evLimit += 16;
363 }
364 var-> evStack[ var-> evPtr++] = 1;
365 }
366
367 Bool
Component_pop_event(Handle self)368 Component_pop_event( Handle self)
369 {
370 if ( var-> stage == csDead)
371 return false;
372 if ( !var-> evStack || var-> evPtr <= 0) {
373 warn("Component::pop_event call not within message()");
374 return false;
375 }
376 return var-> evStack[ --var-> evPtr];
377 }
378
379
380 Bool
Component_eventFlag(Handle self,Bool set,Bool eventFlag)381 Component_eventFlag( Handle self, Bool set, Bool eventFlag)
382 {
383 if ( var-> stage == csDead)
384 return false;
385 if ( !var-> evStack || var-> evPtr <= 0) {
386 warn("Component::eventFlag call not within message()");
387 return false;
388 }
389 if ( set)
390 var-> evStack[ var-> evPtr - 1] = eventFlag;
391 return set ? eventFlag : var-> evStack[ var-> evPtr - 1];
392 }
393
394 void
Component_event_error(Handle self)395 Component_event_error( Handle self)
396 {
397 apc_beep( mbWarning);
398 }
399
400 SV *
Component_get_handle(Handle self)401 Component_get_handle( Handle self)
402 {
403 return newSVsv( NULL_SV);
404 }
405
406 static Bool
oversend(PEvent event,Handle self)407 oversend( PEvent event, Handle self)
408 {
409 my-> message( self, event);
410 free( event);
411 return false;
412 }
413
414 void
Component_handle_event(Handle self,PEvent event)415 Component_handle_event( Handle self, PEvent event)
416 {
417 switch ( event-> cmd)
418 {
419 case cmCreate:
420 my-> notify( self, "<s", "Create");
421 if ( var-> stage == csNormal && var-> evQueue) {
422 PList q = var-> evQueue;
423 var-> evQueue = NULL;
424 if ( q-> count > 0)
425 list_first_that( q, (void*)oversend, ( void*) self);
426 list_destroy( q);
427 free( q);
428 }
429 break;
430 case cmDestroy:
431 opt_set( optcmDestroy);
432 my-> notify( self, "<s", "Destroy");
433 opt_clear( optcmDestroy);
434 break;
435 case cmPost:
436 {
437 PPostMsg p = ( PPostMsg) event-> gen. p;
438 list_delete( var-> postList, ( Handle) p);
439 my-> notify( self, "<sSS", "PostMessage", p-> info1, p-> info2);
440 if ( p-> info1) sv_free( p-> info1);
441 if ( p-> info2) sv_free( p-> info2);
442 free( p);
443 }
444 break;
445 case cmChangeOwner:
446 my-> notify( self, "<sH", "ChangeOwner", event-> gen. H);
447 break;
448 case cmChildEnter:
449 my-> notify( self, "<sH", "ChildEnter", event-> gen. H);
450 break;
451 case cmChildLeave:
452 my-> notify( self, "<sH", "ChildLeave", event-> gen. H);
453 break;
454 case cmSysHandle:
455 my-> notify( self, "<s", "SysHandle");
456 break;
457 }
458 }
459
460 int
Component_is_owner(Handle self,Handle objectHandle)461 Component_is_owner( Handle self, Handle objectHandle)
462 {
463 int depth = 1;
464 if ( !objectHandle || !kind_of( objectHandle, CComponent))
465 return 0;
466 if ( objectHandle == self) return -1;
467 while ( PComponent(objectHandle)-> owner) {
468 if ( PComponent(objectHandle)-> owner == self)
469 return depth;
470 objectHandle = PComponent(objectHandle)-> owner;
471 depth++;
472 }
473 return 0;
474 }
475
476 Bool
Component_migrate(Handle self,Handle attachTo)477 Component_migrate( Handle self, Handle attachTo)
478 {
479 Handle detachFrom = var-> owner;
480
481 if ( detachFrom != attachTo) {
482 if ( attachTo)
483 PComponent(attachTo) -> self-> attach( attachTo, self);
484 if ( detachFrom)
485 PComponent(detachFrom)-> self-> detach( detachFrom, self, false);
486 }
487
488 return detachFrom != attachTo;
489 }
490
491 void
Component_recreate(Handle self)492 Component_recreate( Handle self)
493 {
494 HV * profile = newHV();
495 pset_H( owner, var-> owner);
496 my-> update_sys_handle( self, profile);
497 sv_free(( SV *) profile);
498 }
499
500 Handle
Component_first_that_component(Handle self,void * actionProc,void * params)501 Component_first_that_component( Handle self, void * actionProc, void * params)
502 {
503 Handle child = NULL_HANDLE;
504 int i, count;
505 Handle * list = NULL;
506
507 if ( actionProc == NULL || var-> components == NULL)
508 return NULL_HANDLE;
509 count = var-> components-> count;
510 if ( count == 0) return NULL_HANDLE;
511 if ( !( list = allocn( Handle, count))) return NULL_HANDLE;
512 memcpy( list, var-> components-> items, sizeof( Handle) * count);
513
514 for ( i = 0; i < count; i++)
515 {
516 if ((( PActionProc) actionProc)( self, list[ i], params))
517 {
518 child = list[ i];
519 break;
520 }
521 }
522 free( list);
523 return child;
524 }
525
526 void
Component_post_message(Handle self,SV * info1,SV * info2)527 Component_post_message( Handle self, SV * info1, SV * info2)
528 {
529 PPostMsg p;
530 Event ev = { cmPost};
531 if ( !application ) return;
532 if ( var-> stage > csNormal) return;
533 if (!( p = alloc1( PostMsg))) return;
534 p-> info1 = newSVsv( info1);
535 p-> info2 = newSVsv( info2);
536 p-> h = self;
537 if ( var-> postList == NULL)
538 list_create( var-> postList = ( List*) malloc( sizeof( List)), 8, 8);
539 list_add( var-> postList, ( Handle) p);
540 ev. gen. p = p;
541 ev. gen. source = ev. gen. H = self;
542 apc_message( application, &ev, true);
543 }
544
545
546 void
Component_update_sys_handle(Handle self,HV * profile)547 Component_update_sys_handle( Handle self, HV * profile)
548 {
549 }
550
551 Bool
Component_validate_owner(Handle self,Handle * owner,HV * profile)552 Component_validate_owner( Handle self, Handle * owner, HV * profile)
553 {
554 dPROFILE;
555 *owner = pget_H( owner);
556
557 if ( *owner != NULL_HANDLE) {
558 Handle x = *owner;
559
560 if (((( PObject) x)-> stage > csNormal) || !kind_of( x, CComponent))
561 return false;
562
563 while ( x) {
564 if ( x == self)
565 return false;
566 x = PComponent( x)-> owner;
567 }
568 }
569
570 return true;
571 }
572
573 void
Component_on_create(Handle self)574 Component_on_create( Handle self)
575 {
576 }
577
578 void
Component_on_destroy(Handle self)579 Component_on_destroy( Handle self)
580 {
581 }
582
583 void
Component_on_postmessage(Handle self,SV * info1,SV * info2)584 Component_on_postmessage( Handle self, SV * info1, SV * info2)
585 {
586 }
587
XS(Component_event_hook_FROMPERL)588 XS( Component_event_hook_FROMPERL)
589 {
590 dXSARGS;
591 SV *hook;
592
593 if ( items == 0) {
594 GET_CASE:
595 if ( eventHook)
596 XPUSHs( sv_2mortal( newSVsv(( SV *) eventHook)));
597 else
598 XPUSHs( &PL_sv_undef);
599 PUTBACK;
600 return;
601 }
602
603 hook = ST(0);
604 /* shift unless ref $_[0] */
605 if ( SvPOK(hook) && !SvROK(hook)) {
606 if ( items == 1) goto GET_CASE;
607 hook = ST(1);
608 }
609
610 if ( SvTYPE(hook) == SVt_NULL) {
611 if ( eventHook) sv_free( eventHook);
612 eventHook = NULL;
613 PUTBACK;
614 return;
615 }
616
617 if ( !SvROK( hook) || ( SvTYPE( SvRV( hook)) != SVt_PVCV)) {
618 warn("Not a CODE reference passed to Prima::Component::event_hook");
619 PUTBACK;
620 return;
621 }
622
623 if ( eventHook) sv_free( eventHook);
624 eventHook = newSVsv( hook);
625 PUTBACK;
626 return;
627 }
628
XS(Component_notify_FROMPERL)629 XS( Component_notify_FROMPERL)
630 {
631 dXSARGS;
632 Handle self;
633 SV * res;
634 HV * hv;
635 char * name, * s;
636 int nameLen, rnt, i, ret = -1, evPtr;
637 SV ** argsv;
638 int argsc = items - 1;
639 char buf[ 1024];
640 SV * privMethod;
641 Handle * sequence;
642 int seqCount = 0, stage = csNormal;
643 PList list = NULL;
644
645 if ( items < 2) {
646 exception_remember("Invalid usage of Component.notify");
647 return;
648 }
649 SP -= items;
650 self = gimme_the_mate( ST( 0));
651 name = ( char*) SvPV_nolen( ST( 1));
652 if ( self == NULL_HANDLE) {
653 exception_remember( "Illegal object reference passed to Component.notify");
654 return;
655 }
656
657 if ( eventHook) {
658 dSP;
659 dG_EVAL_ARGS;
660
661 int flag;
662 ENTER;
663 SAVETMPS;
664 PUSHMARK( sp);
665 EXTEND( sp, items);
666 for ( i = 0; i < items; i++) PUSHs( ST( i));
667 PUTBACK;
668 OPEN_G_EVAL;
669 perl_call_sv( eventHook, G_SCALAR | G_EVAL);
670 SPAGAIN;
671 if ( SvTRUE( GvSV( PL_errgv))) {
672 (void)POPs;
673 CLOSE_G_EVAL;
674 exception_remember(SvPV_nolen( GvSV( PL_errgv)));
675 return;
676 }
677 CLOSE_G_EVAL;
678 SPAGAIN;
679 flag = POPi;
680 FREETMPS;
681 LEAVE;
682 SPAGAIN;
683 if ( !flag) XSRETURN_IV(0);
684 }
685
686 if ( var-> stage != csNormal) {
687 if ( !is_opt( optcmDestroy)) XSRETURN_IV(1);
688 opt_clear( optcmDestroy);
689 stage = var-> stage;
690 }
691
692 res = my-> notification_types( self);
693 hv = ( HV *) SvRV( res);
694 SPAGAIN;
695
696 /* fetching notification type */
697 nameLen = strlen( name);
698 if ( hv_exists( hv, name, nameLen)) {
699 SV ** holder = hv_fetch( hv, name, nameLen, 0);
700 if ( !holder || !SvOK(*holder) || SvTYPE(*holder) == SVt_NULL) {
701 char buf[1024];
702 snprintf(buf, 1024, "Inconsistent storage in %s::notification_types for %s during Component.notify", var-> self-> className, name);
703 exception_remember(buf);
704 return;
705 }
706 rnt = SvIV( *holder);
707 } else {
708 warn("Unknown notification:%s", name);
709 rnt = ntDefault;
710 }
711 sv_free( res);
712 SPAGAIN;
713
714 /* searching private on_xxx method */
715 strncat( strcpy( buf, "on_"), name, 1020);
716 for ( s = buf; *s; s++) *s = tolower(*s);
717 privMethod = ( SV *) query_method( self, buf, 0);
718 if ( privMethod) {
719 privMethod = newRV( privMethod);
720 seqCount++;
721 }
722 SPAGAIN;
723
724 /* searching dynamic onXxxx subs */
725 if ( var-> eventIDs) {
726 void * ret;
727 ret = hash_fetch( var-> eventIDs, name, nameLen);
728 if ( ret != NULL) {
729 list = var-> events + PTR2UV( ret) - 1;
730 seqCount += list-> count;
731 }
732 }
733
734 if ( seqCount == 0) XSRETURN_IV(1);
735
736 /* filling calling sequence */
737 sequence = ( Handle *) malloc( seqCount * 2 * sizeof( void *));
738 if ( !sequence) XSRETURN_IV(1);
739
740 i = 0;
741 if ( privMethod && (( rnt & ntCustomFirst) == 0)) {
742 sequence[ i++] = self;
743 sequence[ i++] = ( Handle) privMethod;
744 }
745 if ( list) {
746 int j;
747 if ( rnt & ntFluxReverse) {
748 for ( j = list-> count - 1; j > 0; j -= 2) {
749 sequence[ i++] = list-> items[ j - 1];
750 sequence[ i++] = list-> items[ j];
751 }
752 } else
753 memcpy( sequence + i, list-> items, list-> count * sizeof( Handle));
754 }
755 if ( privMethod && ( rnt & ntCustomFirst)) {
756 sequence[ i++] = self;
757 sequence[ i++] = ( Handle) privMethod;
758 }
759
760 /* copying arguments passed from perl */
761 argsv = ( SV **) malloc( argsc * sizeof( SV *));
762 if ( !argsv) {
763 free( sequence);
764 XSRETURN_IV(1);
765 }
766
767 for ( i = 0; i < argsc; i++) argsv[ i] = ST( i + 1);
768 argsv[ 0] = ST( 0);
769
770 /* entering event */
771 my-> push_event( self);
772 SPAGAIN;
773
774 /* cycling subs */
775 rnt &= ntMultiple | ntEvent;
776 evPtr = var-> evPtr;
777 for ( i = 0; i < seqCount; i += 2) {
778 dSP;
779 dG_EVAL_ARGS;
780 int j;
781
782 ENTER;
783 SAVETMPS;
784 PUSHMARK( sp);
785 EXTEND( sp, argsc + (( sequence[ i] == self) ? 0 : 1));
786 if ( sequence[ i] != self)
787 PUSHs((( PAnyObject)( sequence[i]))-> mate);
788 for ( j = 0; j < argsc; j++) PUSHs( argsv[ j]);
789 PUTBACK;
790 OPEN_G_EVAL;
791 perl_call_sv(( SV*) sequence[ i + 1], G_DISCARD | G_EVAL);
792 if ( SvTRUE( GvSV( PL_errgv))) {
793 CLOSE_G_EVAL;
794 if ( privMethod) sv_free( privMethod);
795 free( argsv);
796 free( sequence);
797 exception_remember(SvPV_nolen( GvSV( PL_errgv)));
798 return;
799 }
800 CLOSE_G_EVAL;
801 SPAGAIN;
802 FREETMPS;
803 LEAVE;
804 if (( var-> stage != stage) ||
805 ( var-> evPtr != evPtr) ||
806 ( rnt == ntSingle) ||
807 (( rnt == ntEvent) && ( var-> evStack[ var-> evPtr - 1] == 0))
808 ) break;
809 }
810 SPAGAIN;
811
812 /* leaving */
813 if ( privMethod) sv_free( privMethod);
814 if ( var-> stage < csDead) ret = my-> pop_event( self);
815 SPAGAIN;
816 SP -= items;
817 XPUSHs( sv_2mortal( newSViv( ret)));
818 free( argsv);
819 free( sequence);
820 PUTBACK;
821 }
822
823 Bool
Component_notify(Handle self,char * format,...)824 Component_notify( Handle self, char * format, ...)
825 {
826 Bool r;
827 SV * ret;
828 va_list args;
829 va_start( args, format);
830 ENTER;
831 SAVETMPS;
832 ret = call_perl_indirect( self, "notify", format, true, false, args);
833 va_end( args);
834 r = ( ret && SvIOK( ret)) ? (SvIV( ret) != 0) : 0;
835 if ( ret) my-> set_eventFlag( self, r);
836 FREETMPS;
837 LEAVE;
838 return r;
839 }
840
841 Bool
Component_notify_REDEFINED(Handle self,char * format,...)842 Component_notify_REDEFINED( Handle self, char * format, ...)
843 {
844 Bool r;
845 SV * ret;
846 va_list args;
847 va_start( args, format);
848 ENTER;
849 SAVETMPS;
850 ret = call_perl_indirect( self, "notify", format, true, false, args);
851 va_end( args);
852 r = ( ret && SvIOK( ret)) ? (SvIV( ret) != 0) : 0;
853 if ( ret) my-> set_eventFlag( self, r);
854 FREETMPS;
855 LEAVE;
856 return r;
857 }
858
XS(Component_get_components_FROMPERL)859 XS( Component_get_components_FROMPERL)
860 {
861 dXSARGS;
862 Handle self;
863 Handle * list;
864 int i, count;
865
866 if ( items != 1)
867 croak ("Invalid usage of Component.get_components");
868 SP -= items;
869 self = gimme_the_mate( ST( 0));
870 if ( self == NULL_HANDLE)
871 croak( "Illegal object reference passed to Component.get_components");
872 if ( var-> components) {
873 count = var-> components-> count;
874 list = var-> components-> items;
875 EXTEND( sp, count);
876 for ( i = 0; i < count; i++)
877 PUSHs( sv_2mortal( newSVsv((( PAnyObject) list[ i])-> mate)));
878 }
879 PUTBACK;
880 return;
881 }
882
Component_get_components(Handle self)883 void Component_get_components ( Handle self) { warn("Invalid call of Component::get_components"); }
Component_get_components_REDEFINED(Handle self)884 void Component_get_components_REDEFINED( Handle self) { warn("Invalid call of Component::get_components"); }
885
886 UV
Component_add_notification(Handle self,char * name,SV * subroutine,Handle referer,int index)887 Component_add_notification( Handle self, char * name, SV * subroutine, Handle referer, int index)
888 {
889 UV ret;
890 PList list;
891 int nameLen = strlen( name);
892 SV * res;
893
894 res = my-> notification_types( self);
895 if ( !hv_exists(( HV *) SvRV( res), name, nameLen)) {
896 sv_free( res);
897 warn("No such event %s", name);
898 return 0;
899 }
900 sv_free( res);
901
902 if ( !subroutine || !SvROK( subroutine) || ( SvTYPE( SvRV( subroutine)) != SVt_PVCV)) {
903 warn("Not a CODE reference passed to %s to Component::add_notification", name);
904 return 0;
905 }
906
907 if ( referer == NULL_HANDLE) referer = self;
908
909 if ( var-> eventIDs == NULL) {
910 var-> eventIDs = hash_create();
911 ret = 0;
912 } else
913 ret = PTR2UV(hash_fetch( var-> eventIDs, name, nameLen));
914
915 if ( ret == 0) {
916 hash_store( var-> eventIDs, name, nameLen, INT2PTR(void*, var-> eventIDCount + 1));
917 if ( var-> events == NULL)
918 var-> events = ( List*) malloc( sizeof( List));
919 else {
920 void * cf = realloc( var-> events, ( var-> eventIDCount + 1) * sizeof( List));
921 if ( cf == NULL) free( var-> events);
922 var-> events = ( List*) cf;
923 }
924 if ( var-> events == NULL) croak("Not enough memory");
925 list = var-> events + var-> eventIDCount++;
926 list_create( list, 2, 2);
927 } else
928 list = var-> events + PTR2UV( ret) - 1;
929
930 ret = PTR2UV(newSVsv( subroutine));
931 index = list_insert_at( list, referer, index);
932 list_insert_at( list, ( Handle) ret, index + 1);
933
934 if ( referer != self) {
935 if ( PComponent( referer)-> refs == NULL)
936 PComponent( referer)-> refs = plist_create( 2, 2);
937 else
938 if ( list_index_of( PComponent( referer)-> refs, self) >= 0) goto NO_ADDREF;
939 list_add( PComponent( referer)-> refs, self);
940 NO_ADDREF:;
941 if ( var-> refs == NULL)
942 var-> refs = plist_create( 2, 2);
943 else
944 if ( list_index_of( var-> refs, referer) >= 0) goto NO_SELFREF;
945 list_add( var-> refs, referer);
946 NO_SELFREF:;
947 }
948 return ret;
949 }
950
951 void
Component_remove_notification(Handle self,UV id)952 Component_remove_notification( Handle self, UV id)
953 {
954 int i = var-> eventIDCount;
955 PList list = var-> events;
956
957 if ( list == NULL) return;
958
959 while ( i--) {
960 int j;
961 for ( j = 0; j < list-> count; j += 2) {
962 if ((( UV ) list-> items[ j + 1]) != id) continue;
963 sv_free(( SV *) list-> items[ j + 1]);
964 list_delete_at( list, j + 1);
965 list_delete_at( list, j);
966 return;
967 }
968 list++;
969 }
970 }
971
972 void
Component_unlink_notifier(Handle self,Handle referer)973 Component_unlink_notifier( Handle self, Handle referer)
974 {
975 int i = var-> eventIDCount;
976 PList list = var-> events;
977
978 if ( list == NULL) return;
979
980 while ( i--) {
981 int j;
982 AGAIN:
983 for ( j = 0; j < list-> count; j += 2) {
984 if ( list-> items[ j] != referer) continue;
985 sv_free(( SV *) list-> items[ j + 1]);
986 list_delete_at( list, j + 1);
987 list_delete_at( list, j);
988 goto AGAIN;
989 }
990 list++;
991 }
992 }
993
XS(Component_get_notification_FROMPERL)994 XS( Component_get_notification_FROMPERL)
995 {
996 dXSARGS;
997 Handle self;
998 char * event;
999 void * ret;
1000 PList list;
1001
1002 if ( items < 2)
1003 croak ("Invalid usage of Component.get_notification");
1004
1005 SP -= items;
1006 self = gimme_the_mate( ST( 0));
1007 if ( self == NULL_HANDLE)
1008 croak( "Illegal object reference passed to Component.get_notification");
1009
1010 if ( var-> eventIDs == NULL) XSRETURN_EMPTY;
1011 event = ( char *) SvPV_nolen( ST( 1));
1012 ret = hash_fetch( var-> eventIDs, event, strlen( event));
1013 if ( ret == NULL) XSRETURN_EMPTY;
1014 list = var-> events + PTR2UV( ret) - 1;
1015
1016 if ( items < 3) {
1017 int i;
1018 if ( GIMME_V == G_ARRAY) {
1019 int count = (int)( list-> count * 1.5);
1020 EXTEND( sp, count);
1021 for ( i = 0; i < list-> count; i += 2) {
1022 PUSHs( sv_2mortal( newSVsv((( PAnyObject)( list-> items[i]))-> mate)));
1023 PUSHs( sv_2mortal( newSVsv(( SV *) list->items[i + 1])));
1024 PUSHs( sv_2mortal( newSViv(( long) list->items[i + 1])));
1025 }
1026 } else
1027 XPUSHs( sv_2mortal( newSViv( list-> count / 2)));
1028 PUTBACK;
1029 } else {
1030 int index = SvIV( ST( 2));
1031 int count = list-> count / 2;
1032 if ( index >= count || index < -count) XSRETURN_EMPTY;
1033 if ( index < 0) index = count + index;
1034 EXTEND( sp, 3);
1035 PUSHs( sv_2mortal( newSVsv((( PAnyObject) list->items[index * 2])-> mate)));
1036 PUSHs( sv_2mortal( newSVsv(( SV *) list->items[index * 2 + 1])));
1037 PUSHs( sv_2mortal( newSViv(( long) list->items[index * 2 + 1])));
1038 PUTBACK;
1039 }
1040 }
1041
Component_get_notification(Handle self,char * name,int index)1042 void Component_get_notification ( Handle self, char * name, int index) { warn("Invalid call of Component::get_notification"); }
Component_get_notification_REDEFINED(Handle self,char * name,int index)1043 void Component_get_notification_REDEFINED( Handle self, char * name, int index) { warn("Invalid call of Component::get_notification"); }
1044
XS(Component_set_notification_FROMPERL)1045 XS( Component_set_notification_FROMPERL)
1046 {
1047 dXSARGS;
1048 GV * gv;
1049 SV * sub;
1050 char * name, * convname;
1051 Handle self;
1052
1053 if ( items < 1)
1054 croak ("Invalid usage of Component::notification property");
1055 self = gimme_the_mate( ST( 0));
1056 if ( self == NULL_HANDLE)
1057 croak( "Illegal object reference passed to Component::notification property");
1058 if ( CvANON( cv) || !( gv = CvGV( cv))) croak("Cannot be called as anonymous sub");
1059
1060 sub = sv_newmortal();
1061 gv_efullname3( sub, gv, NULL);
1062 name = SvPVX( sub);
1063 if ( items < 2)
1064 croak( "Attempt to read write-only property %s", name);
1065 convname = name;
1066 while ( *(name++)) {
1067 if ( *name == ':') convname = name + 1;
1068 }
1069
1070 sub = ST( 1);
1071 if ( convname[0] == 'o' && convname[1] == 'n')
1072 my-> add_notification( self, convname + 2, sub, self, -1);
1073 XSRETURN_EMPTY;
1074 }
1075
Component_set_notification(Handle self,char * name,SV * subroutine)1076 void Component_set_notification ( Handle self, char * name, SV * subroutine) { warn("Invalid call of Component::set_notification"); }
Component_set_notification_REDEFINED(Handle self,char * name,SV * subroutine)1077 void Component_set_notification_REDEFINED( Handle self, char * name, SV * subroutine) { warn("Invalid call of Component::set_notification"); }
1078
1079 SV *
Component_delegations(Handle self,Bool set,SV * delegations)1080 Component_delegations( Handle self, Bool set, SV * delegations)
1081 {
1082 if ( set) {
1083 int i, len;
1084 AV * av;
1085 Handle referer;
1086 char *name;
1087
1088 if ( var-> stage > csNormal) return NULL_SV;
1089 if ( !SvROK( delegations) || SvTYPE( SvRV( delegations)) != SVt_PVAV) return NULL_SV;
1090
1091 referer = var-> owner;
1092 name = var-> name;
1093 av = ( AV *) SvRV( delegations);
1094 len = av_len( av);
1095 for ( i = 0; i <= len; i++) {
1096 SV **holder = av_fetch( av, i, 0);
1097 if ( !holder) continue;
1098 if ( SvROK( *holder)) {
1099 Handle mate = gimme_the_mate( *holder);
1100 if (( mate == NULL_HANDLE) || !kind_of( mate, CComponent)) continue;
1101 referer = mate;
1102 } else if ( SvPOK( *holder)) {
1103 CV * sub;
1104 SV * subref;
1105 char buf[ 1024];
1106 char * event = SvPV_nolen( *holder);
1107
1108 if ( referer == NULL_HANDLE)
1109 croak("Event delegations for objects without owners must be provided with explicit referer");
1110 snprintf( buf, 1023, "%s_%s", name, event);
1111 sub = query_method( referer, buf, 0);
1112 if ( sub == NULL) continue;
1113 my-> add_notification( self, event, subref = newRV(( SV*) sub), referer, -1);
1114 sv_free( subref);
1115 }
1116 }
1117 } else {
1118 HE * he;
1119 AV * av = newAV();
1120 Handle last = NULL_HANDLE;
1121 if ( var-> stage > csNormal || var-> eventIDs == NULL)
1122 return newRV_noinc(( SV*) av);
1123
1124 hv_iterinit( var-> eventIDs);
1125 while (( he = hv_iternext( var-> eventIDs)) != NULL) {
1126 int i;
1127 char * event = ( char *) HeKEY( he);
1128 PList list = var-> events + PTR2UV( HeVAL( he)) - 1;
1129 for ( i = 0; i < list-> count; i += 2) {
1130 if ( list-> items[i] != last) {
1131 last = list-> items[i];
1132 av_push( av, newSVsv((( PAnyObject) last)-> mate));
1133 }
1134 av_push( av, newSVpv( event, 0));
1135 }
1136 }
1137 return newRV_noinc(( SV*) av);
1138 }
1139 return NULL_SV;
1140 }
1141
1142 #ifdef __cplusplus
1143 }
1144 #endif
1145