@@ -39,6 +39,26 @@ static char* g_cwd_dir = NULL;
3939static const char * g_loading_extension_name = NULL ;
4040static const char * g_loading_scope_name = NULL ;
4141
42+ // Registered event handlers and periodic hooks
43+ typedef struct EventHandler {
44+ char * event_name ;
45+ prefix_event_fn fn ;
46+ char * owner ;
47+ struct EventHandler * next ;
48+ } EventHandler ;
49+
50+ typedef struct PeriodicHook {
51+ int n ;
52+ prefix_event_fn fn ;
53+ char * owner ;
54+ struct PeriodicHook * next ;
55+ } PeriodicHook ;
56+
57+ static EventHandler * g_event_handlers = NULL ;
58+ static PeriodicHook * g_periodic_hooks = NULL ;
59+ static prefix_repl_fn g_repl_handler = NULL ;
60+ static char * g_repl_owner = NULL ;
61+
4262static void set_error (char * * error_out , const char * msg ) {
4363 if (!error_out ) return ;
4464 free (* error_out );
@@ -389,19 +409,41 @@ static int ctx_register_operator(const char* name, prefix_operator_fn fn, int fl
389409}
390410
391411static int ctx_register_periodic_hook (int n , prefix_event_fn fn ) {
392- (void )n ;
393- (void )fn ;
412+ if (n <= 0 || !fn ) return -1 ;
413+ PeriodicHook * h = calloc (1 , sizeof (PeriodicHook ));
414+ if (!h ) return -1 ;
415+ h -> n = n ;
416+ h -> fn = fn ;
417+ h -> owner = g_loading_extension_name ? strdup (g_loading_extension_name ) : strdup ("extension" );
418+ if (!h -> owner ) { free (h ); return -1 ; }
419+ h -> next = g_periodic_hooks ;
420+ g_periodic_hooks = h ;
394421 return 0 ;
395422}
396423
397424static int ctx_register_event_handler (const char * event_name , prefix_event_fn fn ) {
398- (void )event_name ;
399- (void )fn ;
425+ if (!event_name || !fn ) return -1 ;
426+ EventHandler * h = calloc (1 , sizeof (EventHandler ));
427+ if (!h ) return -1 ;
428+ h -> event_name = strdup (event_name );
429+ if (!h -> event_name ) { free (h ); return -1 ; }
430+ h -> fn = fn ;
431+ h -> owner = g_loading_extension_name ? strdup (g_loading_extension_name ) : strdup ("extension" );
432+ if (!h -> owner ) { free (h -> event_name ); free (h ); return -1 ; }
433+ h -> next = g_event_handlers ;
434+ g_event_handlers = h ;
400435 return 0 ;
401436}
402437
403438static int ctx_register_repl_handler (prefix_repl_fn repl_fn ) {
404- (void )repl_fn ;
439+ if (!repl_fn ) return -1 ;
440+ g_repl_handler = repl_fn ;
441+ free (g_repl_owner );
442+ g_repl_owner = g_loading_extension_name ? strdup (g_loading_extension_name ) : strdup ("extension" );
443+ if (!g_repl_owner ) {
444+ // keep handler but owner strdup failed; set to NULL
445+ g_repl_owner = NULL ;
446+ }
405447 return 0 ;
406448}
407449
@@ -448,6 +490,35 @@ void extensions_set_runtime_dirs(const char* interpreter_dir, const char* cwd_di
448490 g_cwd_dir = cwd_dir ? strdup (cwd_dir ) : NULL ;
449491}
450492
493+ int extensions_fire_event (Interpreter * interp , const char * event_name ) {
494+ if (!event_name ) return 0 ;
495+ int invoked = 0 ;
496+ for (EventHandler * h = g_event_handlers ; h ; h = h -> next ) {
497+ if (h -> event_name && strcmp (h -> event_name , event_name ) == 0 ) {
498+ if (h -> fn ) h -> fn (interp , event_name );
499+ invoked ++ ;
500+ }
501+ }
502+ return invoked ;
503+ }
504+
505+ void extensions_run_periodic_hooks (Interpreter * interp ) {
506+ if (!interp ) return ;
507+ if (!g_periodic_hooks ) return ;
508+ int step_index = interp -> trace_next_step_index - 1 ;
509+ if (step_index < 0 ) return ;
510+ for (PeriodicHook * p = g_periodic_hooks ; p ; p = p -> next ) {
511+ if (p -> n > 0 && (step_index % p -> n ) == 0 ) {
512+ if (p -> fn ) p -> fn (interp , "periodic" );
513+ }
514+ }
515+ }
516+
517+ int extensions_call_repl_handler (void ) {
518+ if (!g_repl_handler ) return -1 ;
519+ return g_repl_handler ();
520+ }
521+
451522static int extension_register_exposure (LoadedExtension * le ,
452523 const char * ext_name ,
453524 const char * scope_name ,
@@ -647,4 +718,30 @@ void extensions_shutdown(void) {
647718
648719 g_loading_extension_name = NULL ;
649720 g_loading_scope_name = NULL ;
721+
722+ // Free registered event handlers
723+ EventHandler * eh = g_event_handlers ;
724+ while (eh ) {
725+ EventHandler * en = eh -> next ;
726+ free (eh -> event_name );
727+ free (eh -> owner );
728+ free (eh );
729+ eh = en ;
730+ }
731+ g_event_handlers = NULL ;
732+
733+ // Free periodic hooks
734+ PeriodicHook * ph = g_periodic_hooks ;
735+ while (ph ) {
736+ PeriodicHook * pn = ph -> next ;
737+ free (ph -> owner );
738+ free (ph );
739+ ph = pn ;
740+ }
741+ g_periodic_hooks = NULL ;
742+
743+ // Repl handler owner
744+ free (g_repl_owner );
745+ g_repl_owner = NULL ;
746+ g_repl_handler = NULL ;
650747}
0 commit comments