aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbuisson2003-03-14 16:37:29 +0000
committerbuisson2003-03-14 16:37:29 +0000
commit4f5b107bbeca639a0a507ece0ac589ab3fe6a34c (patch)
tree99337ca802b0f9c82047e2ee96f154862049d08d
parent23abb4b87c7e40ed259dd02f653516f60e55ade4 (diff)
downloadivy-ada-4f5b107bbeca639a0a507ece0ac589ab3fe6a34c.zip
ivy-ada-4f5b107bbeca639a0a507ece0ac589ab3fe6a34c.tar.gz
ivy-ada-4f5b107bbeca639a0a507ece0ac589ab3fe6a34c.tar.bz2
ivy-ada-4f5b107bbeca639a0a507ece0ac589ab3fe6a34c.tar.xz
Initial revision
-rw-r--r--README29
-rw-r--r--copyright7
-rw-r--r--src/Makefile31
-rw-r--r--src/ivy.adb243
-rw-r--r--src/ivy.ads178
-rw-r--r--src/send.adb71
-rw-r--r--src/spy.adb86
-rw-r--r--src/spy_cb.adb22
-rw-r--r--src/spy_cb.ads10
9 files changed, 677 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..f81af7a
--- /dev/null
+++ b/README
@@ -0,0 +1,29 @@
+--------------------------------------------------------------------
+Read Me first !
+--------------------------------------------------------------------
+To use this ivy-c ada wrapper, you must have ivy-c installed on your system.
+(requires /usr/lib/libivy.so(.....) )
+
+To compile "my_prog" (only if ivy.ads and ivy.adb are in current directory):
+
+%:gnatmake my_prog -largs -livy
+
+For instance, you will find in the src directory, to little examples
+of how to use ivy in your programs : spy and send.
+
+just compile them by ready-to-use makefile :
+
+%:make or make spy or make send
+%:make clean
+
+--------------------------------------------------------------------
+A lire avant de compiler !
+--------------------------------------------------------------------
+Pour utiliser Ivy en Ada, Ivy-c doit etre installe
+(presence de /usr/lib/libivy.so(.....) obligatoire)
+
+Pour compiler "my_prog":
+(si ivy.ads et ivy.adb sont dans le repertoire courant)
+
+gnatmake my_prog -largs -livy
+
diff --git a/copyright b/copyright
new file mode 100644
index 0000000..4c688a7
--- /dev/null
+++ b/copyright
@@ -0,0 +1,7 @@
+This is open source software distributed under the terms of the GNU
+Lesser General Public License. See the
+/usr/share/common-licenses/LGPL-2.1 file for details. Some included
+utilities are distributed under the terms of the GNU General Public
+License, a copy of which is included in the file
+/usr/share/common-licenses/GPL.
+
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..d63f55c
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,31 @@
+#
+# Ivy, C interface
+#
+# Copyright (C) 1997-2002
+# Centre d'Études de la Navigation Aérienne
+#
+# Makefile
+#
+# Authors: François-Régis Colin <fcolin@cena.fr>
+# Stéphane Chatty <chatty@cena.fr>
+#
+# $Id$
+#
+# Please refer to file version.h for the
+# copyright notice regarding this software
+#
+
+TARGETS = spy send
+
+all: commands
+
+commands: $(TARGETS)
+
+spy:
+ gnatmake spy.adb -largs -livy
+
+send:
+ gnatmake send.adb -largs -livy
+
+clean:
+ -rm -f $(TARGETS) *.o *.ali *~
diff --git a/src/ivy.adb b/src/ivy.adb
new file mode 100644
index 0000000..ae3dec9
--- /dev/null
+++ b/src/ivy.adb
@@ -0,0 +1,243 @@
+package body Ivy is
+
+
+Type Dummy is null record;
+Type Proc_Ptr is access procedure;
+
+--------------------------- routines de Ivy-c ------------------------------
+procedure C_IvyInit (Appname : C.Strings.chars_ptr;
+ Ready : C.Strings.chars_ptr;
+ AppCallback : AppCallback_T;
+ AppData : UserData_T;
+ DieCallback : DieCallback_T;
+ DieData : UserData_T);
+pragma Import (C, C_IvyInit, "IvyInit");
+
+procedure C_IvyStart ( Bus : C.Strings.chars_ptr );
+pragma Import (C, C_IvyStart, "IvyStart");
+
+function C_IvyBindMsg (MsgCallback : MsgCallback_T;
+ Data : UserData_T;
+ Mess : C.char_array)
+ return Subscription_Id_T;
+pragma Import (C, C_IvyBindMsg, "IvyBindMsg");
+
+procedure C_IvyBindMsg (MsgCallback : MsgCallback_T;
+ Data : UserData_T;
+ Mess : C.char_array) is
+
+Dummy : Subscription_Id_T;
+begin
+ Dummy:= C_IvyBindMsg (MsgCallback, Data, Mess);
+end C_IvyBindMsg;
+-- pragma Import (C, C_IvyBindMsg, "IvyBindMsg"); Non autorise en version 3.12
+-- de gnat (import multiple avec profils differents !?)
+
+-- Il faudrait traiter va_list ....
+-- ou utiliser _BindMsg
+
+function C_IvySendMsg (Format : C.char_array := C.To_C("%s");
+ Mess : C.char_array) return C.int;
+pragma Import (C, C_IvySendMsg, "IvySendMsg");
+
+procedure C_IvySendMsg (Format : C.char_array := C.To_C("%s");
+ Mess : C.char_array) is
+Dummy : C.int;
+begin
+ Dummy:=C_IvySendMsg (Format, Mess);
+end C_IvySendMsg;
+-- pragma Import (C, C_IvySendMsg, "IvySendMsg"); Non autorise en version 3.12
+-- de gnat (import multiple avec profils differents !?)
+
+procedure C_IvySendDieMsg ( app : AppClientPtr_T);
+pragma Import (C, C_IvySendDieMsg,"IvySendDieMsg");
+
+procedure C_IvyUnbindMsg( Id : Subscription_Id_T);
+pragma import (C, C_IvyUnbindMsg,"IvyUnbindMsg");
+
+procedure C_IvyMainLoop ( Hook : Proc_Ptr := null); -- Hook inutile en Ada
+pragma Import (C, C_IvyMainLoop, "IvyMainLoop");
+
+-------------------------------------------------------------------------
+
+-- Objet protege pour garantir l'exclusion sur l'utilisation des
+-- routines C (non re-entrantes) fournies par la lib Ivy.
+-- Autorise aussi les appels en fonction du contexte:
+-- Configure une seule fois, et les autres quand le bus est en
+-- regime de croisiere....
+
+Protected API is
+ entry Configure (
+ AppName : String; -- nom de l'application
+ Ready : String; -- ready Message peut etre NULL
+ Bus : String := Default_Bus;
+ -- valeur par defaut de la lib Ivy C
+ AppCallback : AppCallback_T := null;
+ AppData : UserData_T := Null_Data;
+ DieCallback : DieCallback_T := null;
+ DieData : UserData_T:= Null_Data);
+
+ entry SendMsg (Mess : String; Nb : out Nombre_T);
+ entry SendMsg (Mess : String);
+ entry SendDieMsg ( app : AppClientPtr_T);
+ entry Wait_BusReady;
+ entry BindMsg ( MsgCallback : MsgCallback_T;
+ user_data : UserData_T;
+ regexp : String;
+ Id : out Subscription_Id_T);
+ entry BindMsg ( MsgCallback : MsgCallback_T;
+ user_data : UserData_T;
+ regexp : String);
+ entry UnbindMsg ( Id : Subscription_Id_T);
+private
+ BusReady : Boolean :=False;
+end API;
+
+protected body API is
+
+entry Configure(
+ AppName : String; -- nom de l'application
+ Ready : String; -- ready Message peut etre NULL
+ Bus : String := Default_Bus;
+ -- valeur par defaut de la lib Ivy C
+ AppCallback : AppCallback_T :=null;
+ AppData : UserData_T := Null_Data;
+ DieCallback: DieCallback_T := null;
+ DieData : UserData_T:= Null_Data)
+ when not(BusReady) is
+begin
+ C_IvyInit (Appname => C.Strings.New_String(AppName),
+ Ready => C.Strings.New_String(Ready),
+ AppCallback => AppCallback,
+ AppData => AppData,
+ DieCallback => DieCallback,
+ DieData => DieData);
+ C_IvyStart(C.Strings.New_String(Bus));
+ BusReady:= True;
+end configure;
+
+entry SendMsg (Mess : String; Nb : out Nombre_T) when BusReady is
+begin
+ Nb:=Nombre_T(C_IvySendMsg( Mess => C.To_C(Mess)));
+end SendMsg;
+
+entry SendMsg (Mess : String) when BusReady is
+begin
+ C_IvySendMsg( Mess => C.To_C(Mess));
+end SendMsg;
+
+entry SendDieMsg ( app : AppClientPtr_T) when BusReady is
+begin
+ C_IvySendDieMsg(app);
+end SendDieMsg;
+
+entry BindMsg ( MsgCallback : MsgCallback_T;
+ User_data : UserData_T;
+ Regexp : String;
+ Id : out Subscription_Id_T) when BusReady is
+begin
+ Id:=C_IvyBindMsg( MsgCallback, user_data, C.To_C(regexp));
+end BindMsg;
+
+entry BindMsg ( MsgCallback : MsgCallback_T;
+ user_data : UserData_T;
+ Regexp : String) when BusReady is
+begin
+ C_IvyBindMsg( MsgCallback, user_data, C.To_C(regexp));
+end BindMsg;
+
+entry UnbindMsg ( Id : Subscription_Id_T) when BusReady is
+begin
+ C_IvyUnbindMsg(Id);
+end UnbindMsg;
+
+entry Wait_BusReady when BusReady is
+begin
+ null;
+end Wait_BusReady;
+
+end API;
+
+-----------------------------------------------------------
+-- Tache qui encapsule la mainloop C (qui ne retourne jamais)
+
+Task Ivy_Run;
+Task body Ivy_Run is
+begin
+ API.Wait_BusReady;
+ C_IvyMainloop;
+end Ivy_Run;
+
+------------------- Configure ------------------------
+
+procedure Configure (
+ AppName : String; -- nom de l'application
+ Ready : String; -- ready Message peut etre NULL
+ Bus : String := Default_Bus;
+ AppCallback : AppCallback_T := null;
+ AppData : UserData_T := Null_Data;
+ DieCallback : DieCallback_T := null;
+ DieData : UserData_T:= Null_Data) is
+begin
+ API.Configure(AppName, Ready, Bus, AppCallback, AppData,
+ DieCallback, DieData);
+end Configure;
+
+------------------- SendMsg --------------------------
+
+function SendMsg (Mess : String) return Nombre_T is
+
+Nb : Nombre_T;
+begin
+ API.SendMsg(Mess,Nb);
+ return Nb;
+end SendMsg;
+
+procedure SendMsg (Mess : String) is
+Dummy : Nombre_T;
+begin
+ API.SendMsg(Mess,Dummy);
+end SendMsg;
+
+
+------------------ SendDieMsg -------------------------
+
+procedure SendDieMsg ( app : AppClientPtr_T) is
+begin
+ API.SendDieMsg( App);
+end SendDieMsg;
+
+------------------ BindMsg ----------------------------
+
+function BindMsg ( MsgCallback : MsgCallback_T;
+ user_data : UserData_T;
+ regexp : String) return Subscription_Id_T is
+Id : Subscription_Id_T;
+begin
+ API.BindMsg(MsgCallback, user_data, regexp, Id);
+ return Id;
+end BindMsg;
+
+procedure BindMsg ( MsgCallback : MsgCallback_T;
+ user_data : UserData_T;
+ regexp : String) is
+Dummy : Subscription_Id_T;
+begin
+ API.BindMsg(MsgCallback, user_data, regexp, Dummy);
+end BindMsg;
+
+------------------- UnbindMsg ----------------------------
+
+procedure UnbindMsg ( Id : Subscription_Id_T) is
+begin
+ API. UnbindMsg ( Id);
+end UnbindMsg;
+
+-------------------- Kill -----------------------------------
+
+procedure Kill is
+begin
+ -- Massacre sauvage de la main loop!
+ abort Ivy_Run;
+end Kill;
+end ivy;
diff --git a/src/ivy.ads b/src/ivy.ads
new file mode 100644
index 0000000..e77b7b0
--- /dev/null
+++ b/src/ivy.ads
@@ -0,0 +1,178 @@
+
+-- Ajouter commentaires sur le binding
+-- pas d'exeptions a cause du C
+
+--
+-- Portage rapide pour utiliser Ivy en mode minimal en Ada
+-- (Interfaces avec les routines C)
+--
+
+with Interfaces.C;
+with Interfaces.C.Strings;
+with Interfaces.C.Pointers;
+
+
+package Ivy is
+
+
+Default_Bus : constant String := ":2010";
+
+-------------------------------------------------------------------
+-- Interface avec C
+-------------------------------------------------------------------
+package C renames Interfaces.C;
+
+type chars_ptr_array is array(C.size_t range <>)
+ of aliased C.Strings.chars_ptr;
+
+-- Package pour les char ** de C
+Package chars_ptr_pointers is new Interfaces.C.Pointers(
+ Index => C.size_t,
+ Element => C.Strings.chars_ptr,
+ Element_array => chars_ptr_array,
+ Default_Terminator => C.Strings.Null_Ptr);
+
+-- les types char * et char ** de C
+Type C_Char_Etoile_T is new C.Strings.chars_ptr;
+
+--Type C_Char_Etoile_Etoile_T is new chars_ptr_pointers.Pointer;
+subType C_Char_Etoile_Etoile_T is chars_ptr_pointers.Pointer;
+
+-- Transformation Chaine de caracteres C -> String Ada
+Function Value ( V : C.Strings.chars_ptr) return String
+ renames C.Strings.Value;
+
+-------------------------------------------------------------------
+--
+-- Les Types necessaires pour interfacer avec les routines Ivy C
+--
+-------------------------------------------------------------------
+
+subtype C_Int_T is C.int;
+Subtype Nombre_T is C.int;
+Type UserData_T is new Integer;
+Null_Data : constant UserData_T := 0;
+Type Id_T is new C.int;
+
+Type AppEvent_T is (AppConnected, AppDisconnected);
+for AppEvent_T use (AppConnected => C.int(0),
+ AppDisconnected => C.int(1));
+
+Type AppClientPtr_T is private;
+Type Subscription_Id_T is private; -- identificateur quand on s'abonne
+
+-- Type de callback appele sur connexion deconnexion d'une appli
+Type AppCallback_T is access procedure (
+ app : AppClientPtr_T;
+ user_data : UserData_T;
+ event : AppEvent_T);
+
+-- Type de callback appele sur reception de die
+Type DieCallback_T is access procedure(
+ app : AppClientPtr_T;
+ user_data : UserData_T;
+ id : Id_T);
+
+-- Type de callback appele sur reception de messages normaux
+Type MsgCallback_T is access procedure(
+ app : AppClientPtr_T;
+ user_data : UserData_T;
+ argc : C_Int_T;
+ argv : C_Char_Etoile_Etoile_T);
+
+-- Type de callback appele sur reception de messages directs
+Type MsgDirectCallback_T is access procedure(
+ app : AppClientPtr_T;
+ user_data : UserData_T;
+ id : Id_T;
+ msg : C_Char_Etoile_T);
+
+-- filtrage des regexps
+-- procedure Classes( ) a implementer avec operateur +
+-- pour pouvoir ecrire: Classes("avion"+"....."+"....");
+
+--------------------------------------------------------------------------
+--
+-- Les Procedure et fonctions principales d'Ivy
+--
+--------------------------------------------------------------------------
+
+-- Procedure de configuration qui appelle IvyInit, IvyStart,
+-- (IvyBindMsg si neccessaire) et IvyMainloop
+
+procedure Configure (
+ AppName : String; -- nom de l'application
+ Ready : String; -- ready Message peut etre NULL
+ Bus : String := Default_Bus;
+ -- valeur par defaut de la lib Ivy C
+ AppCallback : AppCallback_T := null;
+ AppData : UserData_T := Null_Data;
+ DieCallback : DieCallback_T := null;
+ DieData : UserData_T:= Null_Data);
+
+function SendMsg (Mess : String) return Nombre_T ;
+-- emission d'un message
+-- rend le nombre de messages effectivement envoyes
+
+procedure SendMsg (Mess : String);
+-- emission d'un message sans compte-rendu
+
+procedure SendDieMsg ( app : AppClientPtr_T);
+-- emission d'un message die pour terminer l'application
+
+-- Abonnement avec une regexp
+-- La fonction rend un identificateur utile pour se desabonner
+function BindMsg ( MsgCallback : MsgCallback_T;
+ user_data : UserData_T;
+ regexp : String) return Subscription_Id_T;
+
+procedure BindMsg ( MsgCallback : MsgCallback_T;
+ user_data : UserData_T;
+ regexp : String);
+
+-- Annulation abonnement
+procedure UnbindMsg ( Id : Subscription_Id_T);
+
+-- Tue la main loop Ivy (definitif avant un exit ....)
+Procedure Kill;
+
+---------------------------------------------------------------------------
+private
+
+Type Dummy;
+Type AppClientPtr_T is access Dummy;
+Type Subscription_Id_T is access Dummy; -- identificateur quand on s'abonne
+
+-- Les procedures ou fonctions de la lib ivy en C utilisent ces types
+-- pointeurs sur des structures ad hoc.
+-- En Ada, pour ce binding, on a juste besoin de recuperer des variables
+-- de ces types pour les fournir a d'autres procedures sans intervenir
+-- directement sur les donnees sur lesquelles elles pointent, d'ou le
+-- typage utilise.
+
+
+-- Autres infos pour poursuivre le portage
+
+--typedef struct _clnt_lst *IvyClientPtr;
+--/* identifiant d'une expression reguliere ( Bind/Unbind ) */
+--typedef struct _msg_rcv *MsgRcvPtr;
+
+
+--/* query sur les applications connectees */
+--char *IvyGetApplicationName( IvyClientPtr app );
+--char *IvyGetApplicationHost( IvyClientPtr app );
+--IvyClientPtr IvyGetApplication( char *name );
+--char *IvyGetApplicationList();
+--char **IvyGetApplicationMessages( IvyClientPtr app); /* demande de reception d'un message */
+
+
+--/* emission d'un message d'erreur */
+--void IvySendError( IvyClientPtr app, int id, const char *fmt, ... );
+
+
+--/* Message Direct Inter-application */
+
+--void IvyBindDirectMsg( MsgDirectCallback callback, void *user_data);
+--void IvySendDirectMsg( IvyClientPtr app, int id, char *msg );
+
+end Ivy;
diff --git a/src/send.adb b/src/send.adb
new file mode 100644
index 0000000..6e65025
--- /dev/null
+++ b/src/send.adb
@@ -0,0 +1,71 @@
+with Ivy; use Ivy;
+with Ada.Text_Io; use Ada.Text_Io;
+
+with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
+with GNAT.Command_Line; use GNAT.Command_Line;
+with GNAT.OS_Lib;
+
+Procedure Send is
+
+--| Envoi sur le bus des lignes tapees au clavier
+--| (l'envoi d'une ligne a lieu sur le "Return")
+
+Buffer: String(1..128);
+Last: Natural;
+
+Bus : Unbounded_String := To_Unbounded_String(Ivy.Default_Bus);
+IvyBus : GNAT.OS_Lib.String_Access;
+--| Pour recuperer la variable d'environnement IVYBUS
+
+
+-- Mode d'emploi
+Procedure Print_Usage is
+begin
+ Put_Line("send accepte:");
+ Put_Line(" -b arg : Port Ivy");
+ Put_Line(" -h : help");
+end Print_Usage;
+
+begin -- send
+
+--|
+--| Variables d'environnement
+--|
+
+IvyBus:= GNAT.OS_Lib.Getenv("IVYBUS");
+if IvyBus.all'length /= 0 then --| La variable existe
+ Bus:= To_Unbounded_string(IvyBus.all);
+end if;
+
+--|
+--| Recuperation ligne de commande
+--|
+
+loop
+ case Getopt ("b: h ") is
+ when Ascii.NUL => exit;
+ when 'b' =>
+ Bus := To_Unbounded_String(Parameter);
+ Ada.Text_Io.Put_Line ("Bus : " & To_String(Bus));
+ when 'h' =>
+ Print_Usage;
+ return;
+ when others =>
+ null; -- cannot occur!
+ end case;
+end loop;
+
+-- Initialisation Bus
+
+Ivy.Configure( AppName => "Send",
+ Ready => "Hello",
+ Bus => To_String(Bus));
+
+-- envoi de messages saisis au clavier
+
+loop
+ Get_Line(Buffer,last);
+ Ivy.SendMsg(Buffer(1..Last));
+end loop;
+
+end Send;
diff --git a/src/spy.adb b/src/spy.adb
new file mode 100644
index 0000000..1b7f785
--- /dev/null
+++ b/src/spy.adb
@@ -0,0 +1,86 @@
+with Ivy;
+with Spy_Cb;
+
+with Ada.Text_Io; use Ada.Text_Io;
+with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
+with GNAT.Command_Line; use GNAT.Command_Line;
+with GNAT.OS_Lib;
+
+-- Exemple message rejeu 2.00:
+-- TrackMovedEvent Flight=8182 CallSign=AF261DO Ssr=0464 Sector=TW
+-- Layers=M,I X=52.70 Y=55.88 Vx=133 Vy=436 Afl=175 Rate=-2760 Heading=17
+-- GroundSpeed=456 Tendency=-1 Time=10:00:00
+
+procedure spy is
+
+--| Equivalent de Ivyprobe en Ada en reception
+
+Bus : Unbounded_String := To_Unbounded_String(Ivy.Default_Bus);
+IvyBus : GNAT.OS_Lib.String_Access;
+--| Pour recuperer la variable d'environnement IVYBUS
+
+Regexp: Unbounded_String;
+Default_Regexp: Unbounded_String :=To_Unbounded_String("(.*)");
+--| tous les messages
+
+
+-- Mode d'emploi
+Procedure Print_Usage is
+begin
+ Put_Line("spy accepte:");
+ Put_Line(" -b arg : Port Ivy");
+ Put_Line(" -h : help");
+ Put_Line(" regexp : Regexp pour abonnement - '(.*)' par defaut");
+end Print_Usage;
+
+begin -- Spy
+
+--|
+--| Variables d'environnement
+--|
+
+IvyBus:= GNAT.OS_Lib.Getenv("IVYBUS");
+if IvyBus.all'length /= 0 then --| La variable existe
+ Bus:= To_Unbounded_string(IvyBus.all);
+end if;
+
+--|
+--| Recuperation ligne de commande
+--|
+
+loop
+ case Getopt ("b: h") is
+ when Ascii.NUL => exit;
+ when 'b' =>
+ Bus := To_Unbounded_String(Parameter);
+ Ada.Text_Io.Put_Line ("Bus : " & To_String(Bus));
+ when 'h' =>
+ Print_Usage;
+ return;
+ when others =>
+ null; -- cannot occur!
+ end case;
+end loop;
+
+Regexp:= To_Unbounded_String(Get_Argument);
+if Regexp=Null_Unbounded_String then
+ Regexp:=Default_Regexp;
+end if;
+
+--|
+--| Initialisation Bus
+--|
+
+
+ Ivy.Configure( AppName => "Spy",
+ Ready => "Hello",
+ Bus => To_String(Bus));
+
+ Ivy.BindMsg( MsgCallback => Spy_Cb.Print'access,
+ User_Data => 0,
+ Regexp => To_String(Regexp) );
+-- exemples:
+-- Regexp => "^AIRCRAFT:(.*) heading=([0-9]*) (.*)");
+-- Regexp => "^AIRCRAFT:([A-Z]*[0-9]*)" );
+-- Regexp => "^AIRCRAFT:(.*)");
+end Spy;
diff --git a/src/spy_cb.adb b/src/spy_cb.adb
new file mode 100644
index 0000000..9335876
--- /dev/null
+++ b/src/spy_cb.adb
@@ -0,0 +1,22 @@
+with Ada.Text_Io;
+use Ada.Text_Io;
+
+package body Spy_Cb is
+
+procedure Print(app : AppClientPtr_T;
+ user_data : UserData_T;
+ argc : C_Int_T;
+ argv : C_Char_Etoile_Etoile_T) is
+
+Tab_arg : C_Char_Etoile_Etoile_T := argv;
+
+begin
+ for I in 1..argc loop
+ Put( " |- " & C_Int_T'Image(I) & " -| "&
+ Value(Tab_arg.all));
+ Chars_ptr_pointers.Increment(Tab_arg);
+ end loop;
+ New_Line;
+end Print;
+
+end Spy_Cb;
diff --git a/src/spy_cb.ads b/src/spy_cb.ads
new file mode 100644
index 0000000..8600287
--- /dev/null
+++ b/src/spy_cb.ads
@@ -0,0 +1,10 @@
+with Ivy; use Ivy;
+
+package Spy_Cb is
+
+procedure Print(app : AppClientPtr_T;
+ user_data : UserData_T;
+ argc : C_Int_T;
+ argv : C_Char_Etoile_Etoile_T);
+
+end Spy_Cb;