summaryrefslogtreecommitdiff
path: root/src/ivy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ivy.c')
-rw-r--r--src/ivy.c1045
1 files changed, 419 insertions, 626 deletions
diff --git a/src/ivy.c b/src/ivy.c
index 63de4b4..5231f0d 100644
--- a/src/ivy.c
+++ b/src/ivy.c
@@ -7,8 +7,7 @@
*
* Main functions
*
- * Authors: Francois-Regis Colin <fcolin@cena.fr>
- * Stephane Chatty <chatty@cena.fr>
+ * Authors: Francois-Regis Colin,Stephane Chatty
*
* $Id$
*
@@ -16,31 +15,37 @@
* copyright notice regarding this software
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <fcntl.h>
+#include <stdlib.h>
#ifdef WIN32
-#include <crtdbg.h>
#include <windows.h>
#else
-#include <arpa/inet.h>
#include <sys/time.h>
-#include <unistd.h>
-#include <netdb.h>
+#include <arpa/inet.h>
#endif
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+#include "intervalRegexp.h"
#include "ivychannel.h"
-#include "ivybind.h"
#include "ivysocket.h"
#include "list.h"
-#include "hash.h"
+#include "ivybuffer.h"
+#include "ivydebug.h"
+#include "ivybind.h"
#include "ivy.h"
-#define VERSION 4
+#define VERSION 3
+
+#define MAX_MATCHING_ARGS 40
+
+#define ARG_START "\002"
+#define ARG_END "\003"
+
#define DEFAULT_DOMAIN 127.255.255.255
/* stringification et concatenation du domaine et du port en 2 temps :
@@ -50,37 +55,28 @@
#define GenerateIvyBus(domain,bus) str(domain)":"str(bus)
static char* DefaultIvyBus = GenerateIvyBus(DEFAULT_DOMAIN,DEFAULT_BUS);
-/* syntaxe des messages */
-#define MSGTYPE 0
-#define MSGID 1
-#define ARG_0 2
-
typedef enum {
- Bye, /* l'application emettrice se termine */
- AddRegexp, /* expression reguliere d'un client */
- Msg, /* message reel */
- Error, /* error message */
- DelRegexp, /* Remove expression reguliere */
- EndRegexp, /* end of the regexp list */
+ Bye, /* l'application emettrice se termine */
+ AddRegexp, /* expression reguliere d'un client */
+ Msg, /* message reel */
+ Error, /* error message */
+ DelRegexp, /* Remove expression reguliere */
+ EndRegexp, /* end of the regexp list */
StartRegexp, /* debut des expressions */
- DirectMsg, /* message direct a destination de l'appli */
- Die, /* demande de terminaison de l'appli */
- Ping = 9, /* checks the presence of the other */
- Pong = 10, /* checks the presence of the other */
- AddBinding = 11, /* other methods for binding message based on hash table */
- DelBinding = 12, /* other methods for binding message based on hash table */
- ApplicationId = 13, /* on start send my ID and priority */
-
+ DirectMsg, /* message direct a destination de l'appli */
+ Die, /* demande de terminaison de l'appli */
+ Ping, /* message de controle ivy */
+ Pong /* ivy doit renvoyer ce message à la reception d'un ping */
} MsgType;
typedef struct _msg_snd *MsgSndPtr;
struct _msg_rcv { /* requete d'emission d'un client */
- IvyBindingType type;
+ MsgRcvPtr next;
int id;
- char *regexp; /* regexp du message a recevoir */
- MsgCallback callback; /* callback a declanche a la reception */
+ const char *regexp; /* regexp du message a recevoir */
+ MsgCallback callback; /* callback a declanche a la reception */
void *user_data; /* stokage d'info client */
};
@@ -88,7 +84,7 @@ struct _msg_snd { /* requete de reception d'un client */
MsgSndPtr next;
int id;
char *str_regexp; /* la regexp sous forme inhumaine */
- IvyBinding bind;
+ IvyBinding binding; /* la regexp sous forme machine */
};
struct _clnt_lst {
@@ -96,11 +92,12 @@ struct _clnt_lst {
Client client; /* la socket client */
MsgSndPtr msg_send; /* liste des requetes recues */
char *app_name; /* nom de l'application */
- char *app_id; /* identificateur unique de l'application (time-ip-port) */
- int priority; /* client priority */
unsigned short app_port; /* port de l'application */
};
+/* flag pour le debug en cas de Filter de regexp */
+int debug_filter = 0;
+
/* server pour la socket application */
static Server server;
@@ -114,17 +111,19 @@ static unsigned short SupervisionPort;
static Client broadcast;
static const char *ApplicationName = 0;
+static const char *ApplicationID = 0;
+
/* callback appele sur reception d'un message direct */
static MsgDirectCallback direct_callback = 0;
static void *direct_user_data = 0;
/* callback appele sur changement d'etat d'application */
-static IvyApplicationCallback application_callback = 0;
+static IvyApplicationCallback application_callback;
static void *application_user_data = 0;
/* callback appele sur ajout suppression de regexp */
-static IvyBindCallback application_bind_callback = 0;
+static IvyBindCallback application_bind_callback;
static void *application_bind_data = 0;
/* callback appele sur demande de terminaison d'application */
@@ -132,241 +131,114 @@ static IvyDieCallback application_die_callback;
static void *application_die_user_data = 0;
/* liste des messages a recevoir */
-//static MsgRcvPtr msg_recv = 0;
-static HASHTABLE msg_recv= NULL;
-
+static MsgRcvPtr msg_recv = 0;
/* liste des clients connectes */
static IvyClientPtr clients = 0;
static const char *ready_message = 0;
+static void substituteInterval (IvyBuffer *src);
-static char *applicationUniqueId = 0;
-static int applicationPriority = DEFAULT_PRIORITY;
-
-/* get Current Time in milliseconds */
-static long currentTime()
-{
- unsigned long current;
-#ifdef WIN32
- current = GetTickCount();
-#else
- struct timeval stamp;
- gettimeofday( &stamp, NULL );
- current = stamp.tv_sec * 1000 + stamp.tv_usec/1000;
-#endif
- return current;
-}
-
-
-// fonction de formtage a la printf d'un buffer avec reallocation dynamique
-#define MESSAGE_SIZE 4096 /* taille buffer initiale on multiple pas deux a chaque realloc */
-
-static int make_message(char ** buffer, int *size, int offset, const char *fmt, va_list ap)
-{
- /* Guess we need no more than BUFFER_INIT_SIZE bytes. */
- long n;
- if ( *size == 0 || *buffer == NULL )
- {
- *size = MESSAGE_SIZE;
- *buffer = malloc (MESSAGE_SIZE);
- if ( *buffer == NULL )
- return -1;
- }
- while (1) {
- /* Try to print in the allocated space. */
-#ifdef WIN32
- n = _vsnprintf (*buffer + offset, *size - offset, fmt, ap);
-#else
- n = vsnprintf (*buffer + offset, *size - offset, fmt, ap);
-#endif
- /* If that worked, return the string size. */
- if (n > -1 && n < *size)
- return n;
- /* Else try again with more space. */
- if (n > -1) /* glibc 2.1 */
- *size = n+1; /* precisely what is needed */
- else /* glibc 2.0 */
- *size *= 2; /* twice the old size */
- if ((*buffer = realloc (*buffer, *size)) == NULL)
- return -1;
- }
-}
-
-static char *DupArg( int len, void *s)
-{
- char *ptr;
- ptr = malloc( len+1 );
- if (!ptr )
- {
- fprintf(stderr,"DupArg Buffer Memory Alloc Error\n");
- exit(-1);
- }
- memcpy( ptr, s, len );
- ptr[len] = '\0';
- return ptr;
-}
-/* returns < 0 if *p sorts lower than *q */
-static int keycmp (IvyClientPtr p, IvyClientPtr q)
-{
- return p->priority - q->priority;
-}
-
-/* merge 2 lists under dummy head item */
-static IvyClientPtr lmerge (IvyClientPtr p, IvyClientPtr q)
-{
- IvyClientPtr r;
- struct _clnt_lst head;
-
- for ( r = &head; p && q; )
- {
- if ( keycmp(p, q) < 0 )
- {
- r = r->next = p;
- p = p->next;
- }
- else
- {
- r = r->next = q;
- q = q->next;
- }
- }
- r->next = (p ? p : q);
- return head.next;
-}
-
-/* split list into 2 parts, sort each recursively, merge */
-static IvyClientPtr lsort (IvyClientPtr p)
-{
- IvyClientPtr q, r;
-
- if ( p )
- {
- q = p;
- for ( r = q->next; r && (r = r->next) != NULL; r = r->next )
- q = q->next;
- r = q->next;
- q->next = NULL;
- if ( r )
- p = lmerge(lsort(r), lsort(p));
- }
- return p;
-}
-
-
-static void SortClients()
-{
- // sort client list again priority!
- lsort( clients );
-}
-static void MsgSendTo( Client client, MsgType msgtype, int id, int len_arg, const void *arg )
+/*
+ * function like strok but do not eat consecutive separator
+ * */
+static char * nextArg( char *s, const char *separator )
{
- unsigned short header[3];
-
-#ifdef DEBUG
- printf( "Sending message type=%d id=%d '%.*s'\n",msgtype,id,len_arg,(char*)arg);
-#endif
- header[0] = htons( (unsigned short)msgtype );
- header[1] = htons( (unsigned short)id );
- header[2] = htons( (unsigned short)len_arg );
- SocketSend( client, (char *)header, sizeof(header) );
- if ( len_arg )
+ static char *start = NULL;
+ static char *end = NULL;
+ if ( s )
{
- SocketSend( client, arg, len_arg );
+ end = s;
}
- SocketFlush( client );
-}
-
-static int MsgSendCallTo (Client client, const char *message, MsgSndPtr msg )
-{
- void * buffer = NULL;
- int buf_len = 0;
- int len;
- IvyArgument args;
-
-
- int rc = IvyBindingExec( msg->bind, message );
-
- if (rc<1) return 0; /* no match */
-#ifdef DEBUG
- printf( "Sending message id=%d '%s'\n",msg->id,message);
-#endif
- // il faut essayer d'envoyer le message en une seule fois sur la socket
- // pour eviter au maximun de passer dans le select plusieur fois par message du protocole Ivy
- // pour eviter la latence ( PB de perfo detecte par ivyperf ping roudtrip )
+ start = end;
-#ifdef DEBUG
- printf( "Send matching args count %d\n",rc);
-#endif
- args = IvyBindingMatch( msg->bind, message );
- /* serialize into buffer */
- len = IvyArgumentSerialize(args, &buf_len, &buffer, 0);
-
- MsgSendTo( client, Msg, msg->id, len, buffer );
- IvyArgumentFree( args ); /* TODO supress malloc /free */
- free( buffer );
- return 1;
+ while ( *end && *end != *separator )
+ end++;
+ if ( *end == *separator ) *end++ = '\0';
+ if ( end == start ) return NULL;
+ return start;
}
-static BOOL RemoveBinding(HASHKEYTYPE key, void *data, va_list args)
+static int MsgSendTo( Client client, MsgType msgtype, int id, const char *message )
{
- MsgRcvPtr msg = (MsgRcvPtr)data;
- free( msg->regexp );
- free ( msg );
- return FALSE; /* iter throught all hash table */
+ return SocketSend( client, "%d %d" ARG_START "%s\n", msgtype, id, message);
}
+
static void IvyCleanup()
{
IvyClientPtr clnt,next;
- MsgSndPtr msg,msg_next;
+
/* destruction des connexions clients */
IVY_LIST_EACH_SAFE( clients, clnt, next )
{
/* on dit au revoir */
- MsgSendTo( clnt->client, Bye, 0, 0, "" );
+ MsgSendTo( clnt->client, Bye, 0, "" );
SocketClose( clnt->client );
- IVY_LIST_EACH_SAFE( clnt->msg_send, msg, msg_next )
- {
- free( msg->str_regexp );
- IvyBindingFree( msg->bind );
- }
IVY_LIST_EMPTY( clnt->msg_send );
}
IVY_LIST_EMPTY( clients );
- /* destruction de mes bindings */
- hash_search( msg_recv, RemoveBinding);
- hash_destroy( msg_recv );
- free( applicationUniqueId );
+
/* destruction des sockets serveur et supervision */
SocketServerClose( server );
SocketClose( broadcast );
}
-static int ClientCall (IvyClientPtr clnt, const char *message)
+static int MsgCall (const char *message, MsgSndPtr msg, IvyClientPtr client)
+{
+ int waiting = 0;
+ static IvyBuffer buffer = { NULL, 0, 0 }; /* Use satic mem to eliminate multiple call to malloc /free */
+ int err;
+ int index;
+ int arglen;
+ const char *arg;
+
+ int rc= IvyBindingExec( msg->binding, message );
+
+ if (rc<1) return 0; /* no match */
+
+ TRACE( "Sending message id=%d '%s'\n",msg->id,message);
+
+ buffer.offset = 0;
+ // il faut essayer d'envoyer le message en une seule fois sur la socket
+ // pour eviter au maximun de passer dans le select plusieur fois par message du protocole Ivy
+ // pour eviter la latence ( PB de perfo detecte par ivyperf ping roudtrip )
+ err = make_message_var( &buffer, "%d %d" ARG_START ,Msg, msg->id);
+
+ TRACE( "Send matching args count %d\n",rc);
+
+ for( index=1; index < rc ; index++ )
+ {
+ IvyBindingMatch( msg->binding, message, index, &arglen, & arg );
+ err = make_message_var( &buffer, "%.*s" ARG_END , arglen, arg );
+ }
+ err = make_message_var( &buffer, "\n");
+ waiting = SocketSendRaw(client->client, buffer.data , buffer.offset);
+ if ( waiting )
+ fprintf(stderr, "Ivy: Slow client : %s\n", client->app_name );
+ return 1;
+}
+
+
+static int
+ClientCall (IvyClientPtr clnt, const char *message)
{
MsgSndPtr msg;
int match_count = 0;
- /* for simple binding message syntax msg arg1=val1 arg2=val2 ... argn=valn */
- IvyBindingParseMessage( message );
/* recherche dans la liste des requetes recues de ce client */
IVY_LIST_EACH (clnt->msg_send, msg) {
- match_count+= MsgSendCallTo (clnt->client, message, msg );
+ match_count+= MsgCall (message, msg, clnt);
}
return match_count;
}
-
static int CheckConnected( IvyClientPtr clnt )
{
IvyClientPtr client;
struct in_addr *addr1;
struct in_addr *addr2;
- /* TODO check multiple instance of the same application name */
-
if ( clnt->app_port == 0 ) /* Old Ivy Protocol Dont check */
return 0;
/* recherche dans la liste des clients de la presence de clnt */
- /* TODO check based on appid not on the copule host:port */
IVY_LIST_EACH( clients, client )
{
/* client different mais port identique */
@@ -378,193 +250,140 @@ static int CheckConnected( IvyClientPtr clnt )
if ( addr1->s_addr == addr2->s_addr )
return 1;
}
+ /* client different mais applicationID identique */
+ /* TODO est-ce utile ??? verif dans UDP
+ if ( (client != clnt) && (clnt->app_id == client->app_id) )
+ {
+ return 1;
+ }
+ */
}
return 0;
}
-static char* Receive( Client client, void *data, char *message, unsigned int len )
+static void Receive( Client client, void *data, char *line )
{
IvyClientPtr clnt;
- int id;
- unsigned short len_args;
+ int err,id;
MsgSndPtr snd;
MsgRcvPtr rcv;
- IvyArgument arguments;
+ int argc = 0;
+ char *argv[MAX_MATCHING_ARGS];
+ char *arg;
int kind_of_msg = Bye;
IvyBinding bind;
- char *ptr_end;
- void *args =NULL;
- char *str_regexp;
- int adv_buffer;
-
- ptr_end = message;
-
- if ( len < 6 ) return NULL; /* incomplete message */
- kind_of_msg = ntohs( *((unsigned short *) ptr_end)++ );
- id = ntohs( *((unsigned short *) ptr_end)++ );
- len_args = ntohs( *((unsigned short *) ptr_end)++ );
-
- if ( len_args )
- {
- if ( len < (6 + len_args) ) return NULL; /* incomplete message */
- args = ptr_end;
- ptr_end += len_args;
- }
-#ifdef DEBUG
- printf("Receive Message type=%d id=%d arg=%.*s\n", kind_of_msg, id, len_args, (char*)args);
-#endif //DEBUG
+ const char *errbuf;
+ int erroffset;
+ err = sscanf( line ,"%d %d", &kind_of_msg, &id );
+ arg = strstr( line , ARG_START );
+ if ( (err != 2) || (arg == 0) )
+ {
+ printf("Quitting bad format %s\n", line);
+ MsgSendTo( client, Error, Error, "bad format request expected 'type id ...'" );
+ MsgSendTo( client, Bye, 0, "" );
+ SocketClose( client );
+ return;
+ }
+ arg++;
clnt = (IvyClientPtr)data;
switch( kind_of_msg )
{
case Bye:
-#ifdef DEBUG
- printf("Quitting Bye %.*s\n", len_args, (char*)args);
-#endif //DEBUG
+ TRACE("Quitting %s\n", line);
SocketClose( client );
break;
case Error:
- /*TODO Callback */
- fprintf (stderr, "Received error %d %.*s from %s\n", id, len_args, (char*)args, clnt->app_name);
+ printf ("Received error %d %s\n", id, arg);
break;
case AddRegexp:
-#ifdef DEBUG
- printf("AddRegexp id=%d exp='%.*s'\n", id, len_args, (char*)args);
-#endif //DEBUG
- if ( !IvyBindingFilter( IvyBindRegexp, len_args, args ) )
- {
-#ifdef DEBUG
- printf("Warning: regexp '%.*s' illegal, removing from %s\n",len_args,(char*)args,ApplicationName);
-#endif //DEBUG
- return ptr_end;
- }
- str_regexp = DupArg( len_args, args );
-
- bind = IvyBindingCompile( IvyBindRegexp, str_regexp );
- if ( bind != NULL )
- {
- IVY_LIST_ADD( clnt->msg_send, snd )
- if ( snd )
- {
- snd->id = id;
- snd->str_regexp = str_regexp; /* should be Freeed on remove */
- snd->bind = bind;
- if ( application_bind_callback )
- {
- (*application_bind_callback)( clnt, application_bind_data, IvyAddBind, snd->str_regexp );
- }
- }
- }
- else
- {
- int offset;
- const char *errbuf;
- IvyBindingGetCompileError( &offset, &errbuf );
- MsgSendTo( client, Error, offset, strlen(errbuf), errbuf );
- free( str_regexp ); /* not used so Free it */
- }
-
- break;
- case DelRegexp:
-#ifdef DEBUG
- printf("DelRegexp id=%d\n", id);
-#endif //DEBUG
- IVY_LIST_ITER( clnt->msg_send, snd, ( id != snd->id ));
- if ( snd )
+ TRACE("Regexp id=%d exp='%s'\n", id, arg);
+
+ if ( !IvyBindingFilter( arg ) )
{
- if ( application_bind_callback )
- {
- (*application_bind_callback)( clnt, application_bind_data, IvyRemoveBind, snd->str_regexp );
- }
- free( snd->str_regexp );
- IvyBindingFree( snd->bind );
- IVY_LIST_REMOVE( clnt->msg_send, snd );
- }
- break;
- case AddBinding:
+ TRACE("Warning: regexp '%s' illegal, removing from %s\n",arg,ApplicationName);
-#ifdef DEBUG
- printf("AddBinding id=%d exp='%.*s'\n", id, len_args, (char*)args);
-#endif //DEBUG
- if ( !IvyBindingFilter( IvyBindSimple, len_args, args ) )
- {
-#ifdef DEBUG
- printf("Warning: regexp '%.*s' illegal, removing from %s\n",len_args,(char*)args,ApplicationName);
-#endif //DEBUG
- return ptr_end;
- }
- str_regexp = DupArg( len_args, args );
-
- bind = IvyBindingCompile( IvyBindSimple, str_regexp );
- if ( bind != NULL )
- {
- IVY_LIST_ADD( clnt->msg_send, snd )
- if ( snd )
- {
- snd->id = id;
- snd->str_regexp = str_regexp;
- snd->bind = bind;
- if ( application_bind_callback )
+ if ( application_bind_callback )
{
- (*application_bind_callback)( clnt, application_bind_data, IvyAddBind, snd->str_regexp );
+ (*application_bind_callback)( clnt, application_bind_data, id, arg, IvyFilterBind );
}
- }
+ return;
}
- else
+
+ bind = IvyBindingCompile( arg, & erroffset, & errbuf );
+ if ( bind != NULL )
{
- int offset;
- const char *errbuf;
- IvyBindingGetCompileError( &offset, &errbuf );
- MsgSendTo( client, Error, offset, strlen(errbuf), errbuf );
- free( str_regexp );
+ // On teste si c'est un change regexp : changement de regexp d'une id existante
+ IVY_LIST_ITER( clnt->msg_send, snd, ( id != snd->id ));
+ if ( snd ) {
+ free (snd->str_regexp);
+ snd->str_regexp = strdup( arg );
+ snd->binding = bind;
+ if ( application_bind_callback )
+ {
+ (*application_bind_callback)( clnt, application_bind_data, id, snd->str_regexp, IvyChangeBind );
+ }
+ } else {
+ IVY_LIST_ADD_START( clnt->msg_send, snd )
+ snd->id = id;
+ snd->str_regexp = strdup( arg );
+ snd->binding = bind;
+ if ( application_bind_callback )
+ {
+ (*application_bind_callback)( clnt, application_bind_data, id, snd->str_regexp, IvyAddBind );
+ }
+ IVY_LIST_ADD_END( clnt->msg_send, snd )
+
+ }
}
-
+ else
+ {
+ printf("Error compiling '%s', %s\n", arg, errbuf);
+ MsgSendTo( client, Error, erroffset, errbuf );
+ }
+
break;
- case DelBinding:
-#ifdef DEBUG
- printf("DelBinding id=%d\n", id);
-#endif //DEBUG
+ case DelRegexp:
+
+ TRACE("Regexp Delete id=%d\n", id);
IVY_LIST_ITER( clnt->msg_send, snd, ( id != snd->id ));
if ( snd )
{
if ( application_bind_callback )
{
- (*application_bind_callback)( clnt, application_bind_data, IvyRemoveBind, snd->str_regexp );
+ (*application_bind_callback)( clnt, application_bind_data, id, snd->str_regexp, IvyRemoveBind );
}
- free( snd->str_regexp );
- IvyBindingFree( snd->bind );
-
+ IvyBindingFree( snd->binding );
IVY_LIST_REMOVE( clnt->msg_send, snd );
}
break;
case StartRegexp:
-#ifdef DEBUG
- printf("Regexp Start id=%d Application='%.*s'\n", id, len_args, (char*)args);
-#endif //DEBUG
- clnt->app_name = DupArg( len_args, args );
+
+ TRACE("Regexp Start id=%d Application='%s'\n", id, arg);
+
+ clnt->app_name = strdup( arg );
clnt->app_port = id;
if ( CheckConnected( clnt ) )
{
-#ifdef DEBUG
- printf("Quitting already connected %.*s\n", len_args, (char*)args);
-#endif //DEBUG
+
+ TRACE("Quitting already connected %s\n", line);
+
IvySendError( clnt, 0, "Application already connected" );
SocketClose( client );
}
break;
case EndRegexp:
-#ifdef DEBUG
- printf("Regexp End id=%d\n", id);
-#endif //DEBUG
+ TRACE("Regexp End id=%d\n", id);
+
if ( application_callback )
{
(*application_callback)( clnt, application_user_data, IvyApplicationConnected );
@@ -574,94 +393,85 @@ static char* Receive( Client client, void *data, char *message, unsigned int len
int count;
count = ClientCall( clnt, ready_message );
-#ifdef DEBUG
- printf(" Sendind ready message %d\n", count);
-#endif //DEBUG
-
+ TRACE(" Sendind ready message %d\n", count);
}
break;
case Msg:
-#ifdef DEBUG
- printf("Message id=%d msg='%.*s'\n", id, len_args, (char*)args);
-#endif //DEBUG
- rcv = hash_lookup( msg_recv, id );
- if ( rcv && rcv->callback )
+ TRACE("Message id=%d msg='%s'\n", id, arg);
+
+ IVY_LIST_EACH( msg_recv, rcv )
+ {
+ if ( id == rcv->id )
{
- arguments = IvyArgumentDeserialize( len_args, args, &adv_buffer );
-
-#ifdef DEBUG
- printf("Calling id=%d for %s\n", id, rcv->regexp);
-#endif
- (*rcv->callback)( clnt, rcv->user_data, arguments );
- IvyArgumentFree( arguments ); /* TODO evy , suppress malloc/free on each callback */
- return ptr_end;
+ arg = nextArg( arg, ARG_END);
+ while ( arg )
+ {
+ argv[argc++] = arg;
+ arg = nextArg( 0, ARG_END );
+ }
+ TRACE("Calling id=%d argc=%d for %s\n", id, argc,rcv->regexp);
+ if ( rcv->callback ) (*rcv->callback)( clnt, rcv->user_data, argc, argv );
+ return;
}
- else
- printf("Callback Message id=%d not found!!!'\n", id);
+ }
+ printf("Callback Message id=%d not found!!!'\n", id);
break;
case DirectMsg:
-#ifdef DEBUG
- printf("Direct Message id=%d msg='%.*s'\n", id, len_args, (char*)args);
-#endif //DEBUG
+ TRACE("Direct Message id=%d msg='%s'\n", id, arg);
if ( direct_callback)
- (*direct_callback)( clnt, direct_user_data, id, len_args, args );
+ (*direct_callback)( clnt, direct_user_data, id, arg );
break;
case Die:
-#ifdef DEBUG
- printf("Die Message\n");
-#endif //DEBUG
+ TRACE("Die Message\n");
if ( application_die_callback)
(*application_die_callback)( clnt, application_die_user_data, id );
IvyCleanup();
exit(0);
break;
- case ApplicationId:
-#ifdef DEBUG
- printf("ApplicationId priority=%d appid='%.*s'\n", id, len_args, (char*)args);
-#endif //DEBUG
- clnt->app_id = DupArg( len_args, args );
- if ( id != clnt->priority )
- {
- clnt->priority = id;
- SortClients();
- }
+
+ case Ping:
+
+ TRACE("Ping Message\n");
+ MsgSendTo( client, Pong, id, "" );
+ break;
+
+ case Pong:
+
+ TRACE("Pong Message\n");
+ printf("Receive unhandled Pong message (ivy-c not able to send ping)\n");
break;
+
default:
- printf("Receive unhandled message %d\n", kind_of_msg);
+ printf("Receive unhandled message %s\n", line);
break;
}
- return ptr_end;
-}
-static BOOL SendRegexp(HASHKEYTYPE key, void *data, va_list args)
-{
- Client client = va_arg( args, Client);
- MsgRcvPtr msg = (MsgRcvPtr)data;
- MsgSendTo( client, msg->type == IvyBindRegexp ? AddRegexp : AddBinding, msg->id, strlen(msg->regexp), msg->regexp);
- return FALSE; /* iter throught all hash table */
+
}
-static IvyClientPtr SendService( Client client )
+
+static IvyClientPtr SendService( Client client, const char *appname )
{
IvyClientPtr clnt;
- IVY_LIST_ADD( clients, clnt )
- if ( clnt )
- {
- SocketKeepAlive ( client, 1 );
+ MsgRcvPtr msg;
+ IVY_LIST_ADD_START( clients, clnt )
+
clnt->msg_send = 0;
clnt->client = client;
- clnt->app_name = strdup("Unknown");
+ clnt->app_name = strdup(appname);
clnt->app_port = 0;
- clnt->priority = DEFAULT_PRIORITY;
- MsgSendTo( client, ApplicationId, applicationPriority, strlen(applicationUniqueId), applicationUniqueId );
- MsgSendTo( client, StartRegexp, ApplicationPort, strlen(ApplicationName), ApplicationName );
- hash_search( msg_recv, SendRegexp, client);
- MsgSendTo( client, EndRegexp, 0, 0,"");
- }
+ MsgSendTo( client, StartRegexp, ApplicationPort, ApplicationName);
+ IVY_LIST_EACH(msg_recv, msg )
+ {
+ MsgSendTo( client, AddRegexp,msg->id,msg->regexp);
+ }
+ MsgSendTo( client, EndRegexp, 0, "");
+
+ IVY_LIST_ADD_END( clients, clnt )
return clnt;
}
@@ -682,14 +492,13 @@ static void ClientDelete( Client client, void *data )
#ifdef DEBUG
/* probably bogus call, but this is for debug only anyway */
SocketGetRemoteHost( client, &remotehost, &remoteport );
- printf("Deconnexion de %s:%hu\n", remotehost, remoteport );
+ TRACE("Deconnexion de %s:%hu\n", remotehost, remoteport );
#endif //DEBUG
if ( clnt->app_name ) free( clnt->app_name );
- if ( clnt->app_id ) free( clnt->app_id );
IVY_LIST_EACH( clnt->msg_send, msg)
{
- IvyBindingFree( msg->bind );
+ /*regfree(msg->regexp);*/
free( msg->str_regexp);
}
IVY_LIST_EMPTY( clnt->msg_send );
@@ -703,69 +512,36 @@ static void *ClientCreate( Client client )
char *remotehost;
unsigned short remoteport;
SocketGetRemoteHost( client, &remotehost, &remoteport );
- printf("Connexion de %s:%hu\n", remotehost, remoteport );
+ TRACE("Connexion de %s:%hu\n", remotehost, remoteport );
#endif //DEBUG
- return SendService (client);
-}
-/* Hello packet Send */
-static void IvySendHello(unsigned long mask)
-{
- char *packet;
- char *ptr;
- int lenAppId;
- int lenAppName;
- int len;
- lenAppId = strlen( applicationUniqueId );
- lenAppName = strlen( ApplicationName );
- len = 4*sizeof(unsigned short) + lenAppId + lenAppName;
- packet = malloc( len );
- ptr = packet;
- *((unsigned short *) ptr)++ = htons( VERSION );
- *((unsigned short *) ptr)++ = htons( ApplicationPort );
- *((unsigned short *) ptr)++ = htons( lenAppId );
- strncpy( ptr, applicationUniqueId , lenAppId);
- ptr += lenAppId;
- *((unsigned short *) ptr)++ = htons( lenAppName );
- strncpy( ptr, ApplicationName , lenAppName);
-
- SocketSendBroadcast(broadcast, mask, SupervisionPort, packet,len );
- free( packet );
+
+ return SendService (client, "Unknown");
}
-/* Hello packet Receive */
-static char* BroadcastReceive( Client client, void *data, char *message, unsigned int len)
+
+static void BroadcastReceive( Client client, void *data, char *line )
{
Client app;
- unsigned short version;
+ int err;
+ int version;
unsigned short serviceport;
- char appname[1024];
- char appid[1024];
- unsigned short len_appid;
- unsigned short len_appname;
+ char appid[2048];
+ char appname[2048];
#ifdef DEBUG
unsigned short remoteport;
char *remotehost = 0;
#endif
-
- char *ptr_end;
- ptr_end = message;
-
- if ( len < 6 ) return NULL; /* incomplete message */
-
- version = ntohs( *((unsigned short *) ptr_end)++ );
- serviceport = ntohs( *((unsigned short *) ptr_end)++ );
- len_appid = ntohs( *((unsigned short *) ptr_end)++ );
- if ( len < (6 +len_appid) ) return NULL; /* incomplete message */
-
- strncpy( appid , ptr_end, len_appid );
- appid[ len_appid ] = '\0';
- ptr_end += len_appid;
- len_appname = ntohs( *((unsigned short *) ptr_end)++ );
- if ( len < (6 +len_appid + len_appname) ) return NULL; /* incomplete message */
-
- strncpy( appname , ptr_end, len_appname );
- appname[ len_appname ] = '\0';
- ptr_end += len_appname;
-
+ memset( appid, 0, sizeof( appid ) );
+ memset( appname, 0, sizeof( appname ) );
+ err = sscanf (line,"%d %hu %s %[^\n]", &version, &serviceport, appid, appname);
+ if ( err < 2 ) {
+ /* ignore the message */
+ unsigned short remoteport;
+ char *remotehost;
+ SocketGetRemoteHost (client, &remotehost, &remoteport );
+ printf (" Bad supervision message, expected 'version port' from %s:%d\n",
+ remotehost, remoteport);
+ return;
+ }
if ( version != VERSION ) {
/* ignore the message */
unsigned short remoteport;
@@ -773,116 +549,82 @@ static char* BroadcastReceive( Client client, void *data, char *message, unsigne
SocketGetRemoteHost (client, &remotehost, &remoteport );
fprintf (stderr, "Bad Ivy version, expected %d and got %d from %s:%d\n",
VERSION, version, remotehost, remoteport);
- return ptr_end;
+ return;
}
- /* check if we received our own message */
- if (strcmp( appid,applicationUniqueId )== 0)
- return ptr_end;
+ /* check if we received our own message. SHOULD ALSO TEST THE HOST */
+ if ( strcmp( appid , ApplicationID) ==0 ) return;
+ if (serviceport == ApplicationPort) return;
#ifdef DEBUG
SocketGetRemoteHost (client, &remotehost, &remoteport );
- printf(" Broadcast de %s:%hu port %hu %s %s\n", remotehost, remoteport, serviceport, appname, appid );
+ TRACE(" Broadcast de %s:%hu port %hu\n", remotehost, remoteport, serviceport );
#endif //DEBUG
- /* check if already the same name on the bus */
- if ( strcmp( appname,ApplicationName )== 0)
- {
- /* TODO rize some callback ? */
- fprintf(stderr,"!!! Warning a another instance of %s is arriving on the Bus !!!\n", ApplicationName );
- }
/* connect to the service and send the regexp */
app = SocketConnectAddr(SocketGetRemoteAddr(client), serviceport, 0, Receive, ClientDelete );
if (app) {
IvyClientPtr clnt;
- clnt = SendService( app );
+ clnt = SendService( app, appname );
SocketSetData( app, clnt);
}
- return ptr_end;
+}
+static unsigned long currentTime()
+{
+#define MILLISEC 1000
+ unsigned long current;
+#ifdef WIN32
+ current = GetTickCount();
+#else
+ struct timeval stamp;
+ gettimeofday( &stamp, NULL );
+ current = stamp.tv_sec * MILLISEC + stamp.tv_usec/MILLISEC;
+#endif
+ return current;
}
+static const char * GenApplicationUniqueIdentifier()
+{
+ static char appid[2048];
+ unsigned long curtime;
+ curtime = currentTime();
+ srand( curtime );
+ sprintf(appid,"%d:%lu:%d",rand(),curtime,ApplicationPort);
+ return appid;
+}
void IvyInit (const char *appname, const char *ready,
IvyApplicationCallback callback, void *data,
IvyDieCallback die_callback, void *die_data
)
{
- char hostname[1024];
- struct hostent *host;
- IvyChannelInit();
+ SocketInit();
- msg_recv = hash_create( 1024, FALSE );
- if ( ! msg_recv )
- {
- fprintf(stderr,"IvyInit can't create Binding hash Table\n");
- exit(-1);
- }
ApplicationName = appname;
application_callback = callback;
application_user_data = data;
application_die_callback = die_callback;
application_die_user_data = die_data;
ready_message = ready;
- /*
- * Initialize TCP port
- */
- server = SocketServer (ANYPORT, ClientCreate, ClientDelete, Receive);
- ApplicationPort = SocketServerGetPort (server);
- /* get Host Ip address */
- if ( gethostname(hostname,sizeof(hostname)) < 0 )
- {
- perror("gethostname");
- exit(-1);
- }
- host = gethostbyname( hostname );
- if ( ! host )
- {
- perror("gethostbyname");
- exit(-1);
- }
- /* generate application UniqueID (timeStamp-Ipaddress-port*/
- /* TODO bug if multiple interface */
- applicationUniqueId = malloc(1024);
- sprintf( applicationUniqueId , "%lu-%u%u%u%u-%d",
- currentTime(),
- (unsigned char)host->h_addr[0],
- (unsigned char)host->h_addr[1],
- (unsigned char)host->h_addr[2],
- (unsigned char)host->h_addr[3],
- ApplicationPort);
-
}
-void IvyStop()
+void IvySetBindCallback( IvyBindCallback bind_callback, void *bind_data )
{
- IvyCleanup();
- IvyChannelStop();
+ application_bind_callback=bind_callback;
+ application_bind_data=bind_data;
}
-void IvySetApplicationPriority( int priority )
+void IvySetFilter( int argc, const char **argv)
{
- int len;
- IvyClientPtr clnt;
- applicationPriority = priority;
- if ( clients )
- {
- /* Send to already connected clients */
- len = strlen(applicationUniqueId);
- IVY_LIST_EACH (clients, clnt ) {
- MsgSendTo( clnt->client, ApplicationId, applicationPriority, len, applicationUniqueId);
- }
- }
-}
+ IvyBindingSetFilter( argc, argv );
+ if ( getenv( "IVY_DEBUG_FILTER" )) debug_filter = 1;
-void IvySetBindCallback(IvyBindCallback bind_callback, void *bind_data)
-{
- application_bind_callback=bind_callback;
- application_bind_data=bind_data;
}
-void IvySetMyMessagesStart( int argc, const char **argv)
+void IvyStop (void)
{
- IvyBindingSetFilter( argc, argv );
+ IvyChannelStop();
}
+
void IvyStart (const char* bus)
{
@@ -898,6 +640,13 @@ void IvyStart (const char* bus)
/*
+ * Initialize TCP port
+ */
+ server = SocketServer (ANYPORT, ClientCreate, ClientDelete, Receive);
+ ApplicationPort = SocketServerGetPort (server);
+ ApplicationID = GenApplicationUniqueIdentifier();
+
+ /*
* Find network list as well as broadcast port
* (we accept things like 123.231,123.123:2000 or 123.231 or :2000),
* Initialize UDP port
@@ -956,7 +705,7 @@ void IvyStart (const char* bus)
if ( IN_MULTICAST( mask ) )
SocketAddMember (broadcast , mask );
- IvySendHello( mask );
+ SocketSendBroadcast (broadcast, mask, SupervisionPort, "%d %hu %s %s\n", VERSION, ApplicationPort, ApplicationID, ApplicationName);
numelem = 0;
mask = 0xffffffff;
}
@@ -986,123 +735,117 @@ void IvyStart (const char* bus)
++p;
}
-#ifdef DEBUG
- fprintf (stderr,"Listening on TCP:%hu\n",ApplicationPort);
-#endif
+ TRACE ("Listening on TCP:%hu\n",ApplicationPort);
}
/* desabonnements */
-void IvyUnbindMsg (MsgRcvPtr msg)
+void
+IvyUnbindMsg (MsgRcvPtr msg)
{
IvyClientPtr clnt;
/* Send to already connected clients */
IVY_LIST_EACH (clients, clnt ) {
- MsgSendTo( clnt->client, DelRegexp,msg->id, 0, "");
+ MsgSendTo( clnt->client, DelRegexp,msg->id, "");
}
- hash_remove( msg_recv, msg->id );
+ IVY_LIST_REMOVE( msg_recv, msg );
}
/* demande de reception d'un message */
-static MsgRcvPtr IvyBind ( IvyBindingType typ, MsgCallback callback, void *user_data, const char *fmt_regex, va_list ap )
+
+MsgRcvPtr
+IvyBindMsg (MsgCallback callback, void *user_data, const char *fmt_regex, ... )
{
- char *buffer = NULL;
- int size = 0;
+ static IvyBuffer buffer = { NULL, 0, 0};
+ va_list ap;
static int recv_id = 0;
IvyClientPtr clnt;
MsgRcvPtr msg;
- int len;
- int MsgType = typ == IvyBindRegexp ? AddRegexp : AddBinding;
- make_message( &buffer, &size, 0, fmt_regex, ap );
-
+ va_start (ap, fmt_regex );
+ buffer.offset = 0;
+ make_message( &buffer, fmt_regex, ap );
+ va_end (ap );
+
+ substituteInterval (&buffer);
+
/* add Msg to the query list */
- msg = malloc(sizeof(struct _msg_rcv));
- if (msg) {
- msg->type = typ;
+ IVY_LIST_ADD_START( msg_recv, msg )
msg->id = recv_id++;
- msg->regexp = buffer;
+ msg->regexp = strdup(buffer.data);
msg->callback = callback;
msg->user_data = user_data;
- if ( !hash_add(msg_recv, msg->id, msg) )
- {
- perror("IvyBindMsg can't hash_add Entry already exists!");
- exit(-1);
- }
- }
- else
- {
- perror("IvyBindMsg can't allocate Binding");
- free ( buffer );
- exit(-1);
- }
- len = strlen(msg->regexp);
+ IVY_LIST_ADD_END( msg_recv, msg )
/* Send to already connected clients */
/* recherche dans la liste des requetes recues de mes clients */
IVY_LIST_EACH( clients, clnt ) {
- MsgSendTo( clnt->client, MsgType,msg->id, len, msg->regexp);
+ MsgSendTo( clnt->client, AddRegexp,msg->id,msg->regexp);
}
return msg;
}
-
-MsgRcvPtr IvyBindMsg (MsgCallback callback, void *user_data, const char *fmt_regex, ... )
+/* changement de regexp d'un bind existant precedement fait avec IvyBindMsg */
+MsgRcvPtr
+IvyChangeMsg (MsgRcvPtr msg, const char *fmt_regex, ... )
{
+ static IvyBuffer buffer = { NULL, 0, 0};
va_list ap;
- MsgRcvPtr msg;
+ IvyClientPtr clnt;
va_start (ap, fmt_regex );
- msg = IvyBind ( IvyBindRegexp, callback, user_data, fmt_regex, ap );
+ buffer.offset = 0;
+ make_message( &buffer, fmt_regex, ap );
va_end (ap );
- return msg;
-
-}
-MsgRcvPtr IvyBindSimpleMsg( MsgCallback callback, void *user_data, const char *fmt_regex, ... )
-{
- va_list ap;
- MsgRcvPtr msg;
+ substituteInterval (&buffer);
- va_start (ap, fmt_regex );
- msg = IvyBind ( IvyBindSimple, callback, user_data, fmt_regex, ap );
- va_end (ap );
- return msg;
+ /* change Msg in the query list */
+ msg->regexp = strdup(buffer.data);
+ /* Send to already connected clients */
+ /* recherche dans la liste des requetes recues de mes clients */
+ IVY_LIST_EACH( clients, clnt ) {
+ MsgSendTo( clnt->client, AddRegexp,msg->id,msg->regexp);
+ }
+ return msg;
}
+/* emmission d'un message avec formatage a la printf */
int IvySendMsg(const char *fmt, ...)
{
IvyClientPtr clnt;
int match_count = 0;
- char *buffer = NULL; /* Use satic mem to eliminate multiple call to malloc /free */
- int size = 0; /* donc non reentrant !!!! */
+ static IvyBuffer buffer = { NULL, 0, 0}; /* Use satic mem to eliminate multiple call to malloc /free */
va_list ap;
+ if( fmt == 0 || strlen(fmt) == 0 ) return 0;
va_start( ap, fmt );
- make_message( &buffer, &size, 0, fmt, ap );
+ buffer.offset = 0;
+ make_message( &buffer, fmt, ap );
va_end ( ap );
/* recherche dans la liste des requetes recues de mes clients */
IVY_LIST_EACH (clients, clnt) {
- match_count += ClientCall (clnt, buffer);
+ match_count += ClientCall (clnt, buffer.data);
+ }
+ TRACE_IF( match_count == 0, "Warning no recipient for %s\n",buffer.data);
+ /* si le message n'est pas emit et qu'il y a des filtres alors WARNING */
+ if ( match_count == 0 && debug_filter )
+ {
+ IvyBindindFilterCheck( buffer.data );
}
-#ifdef DEBUG
- if ( match_count == 0 ) printf( "Warning no recipient for %s\n",buffer);
-#endif
- free(buffer);
return match_count;
}
void IvySendError( IvyClientPtr app, int id, const char *fmt, ... )
{
- char *buffer = NULL; /* Use satic mem to eliminate multiple call to malloc /free */
- int size = 0; /* donc non reentrant !!!! */
+ static IvyBuffer buffer = { NULL, 0, 0}; /* Use satic mem to eliminate multiple call to malloc /free */
va_list ap;
va_start( ap, fmt );
- make_message( &buffer, &size, 0, fmt, ap );
+ buffer.offset = 0;
+ make_message( &buffer, fmt, ap );
va_end ( ap );
- MsgSendTo( app->client, Error, id, strlen(buffer), buffer);
- free(buffer);
+ MsgSendTo( app->client, Error, id, buffer.data);
}
void IvyBindDirectMsg( MsgDirectCallback callback, void *user_data)
@@ -1111,14 +854,14 @@ void IvyBindDirectMsg( MsgDirectCallback callback, void *user_data)
direct_user_data = user_data;
}
-void IvySendDirectMsg( IvyClientPtr app, int id, int len, void *msg )
+void IvySendDirectMsg( IvyClientPtr app, int id, char *msg )
{
- MsgSendTo( app->client, DirectMsg, id, len, msg);
+ MsgSendTo( app->client, DirectMsg, id, msg);
}
void IvySendDieMsg( IvyClientPtr app )
{
- MsgSendTo( app->client, Die, 0, 0, "" );
+ MsgSendTo( app->client, Die, 0, "" );
}
char *IvyGetApplicationName( IvyClientPtr app )
@@ -1134,12 +877,7 @@ char *IvyGetApplicationHost( IvyClientPtr app )
return SocketGetPeerHost (app->client );
else return 0;
}
-char *IvyGetApplicationId( IvyClientPtr app )
-{
- if ( app && app->app_id )
- return app->app_id;
- else return 0;
-}
+
void IvyDefaultApplicationCallback( IvyClientPtr app, void *user_data, IvyApplicationEvent event)
{
switch ( event ) {
@@ -1154,14 +892,21 @@ void IvyDefaultApplicationCallback( IvyClientPtr app, void *user_data, IvyApplic
break;
}
}
-void IvyDefaultBindCallback( IvyClientPtr app, void *user_data, IvyBindEvent event, char* regexp )
+void IvyDefaultBindCallback( IvyClientPtr app, void *user_data, int id, char* regexp, IvyBindEvent event)
{
switch ( event ) {
case IvyAddBind:
- printf("Application: %s on %s add regexp %s\n", IvyGetApplicationName( app ), IvyGetApplicationHost(app), regexp);
+ printf("Application: %s on %s add regexp %d : %s\n", IvyGetApplicationName( app ), IvyGetApplicationHost(app), id, regexp);
break;
case IvyRemoveBind:
- printf("Application: %s on %s remove regexp %s\n", IvyGetApplicationName( app ), IvyGetApplicationHost(app), regexp);
+ printf("Application: %s on %s remove regexp %d :%s\n", IvyGetApplicationName( app ), IvyGetApplicationHost(app), id, regexp);
+ break;
+ case IvyFilterBind:
+ printf("Application: %s on %s as been filtred regexp %d :%s\n", IvyGetApplicationName( app ), IvyGetApplicationHost(app), id, regexp);
+ break;
+ case IvyChangeBind:
+ printf("Application: %s on %s change regexp %d : %s\n", IvyGetApplicationName( app ), IvyGetApplicationHost(app), id, regexp);
+ break;
break;
default:
printf("Application: %s unkown event %d\n",IvyGetApplicationName( app ), event);
@@ -1176,22 +921,23 @@ IvyClientPtr IvyGetApplication( char *name )
return app;
}
-char **IvyGetApplicationList()
+char *IvyGetApplicationList(const char *sep)
{
- static char* applist[500];
+ static char applist[4096]; /* TODO remove that ugly Thing */
IvyClientPtr app;
- int appCount= 0;
- memset( applist, 0 , sizeof( applist ));
+ applist[0] = '\0';
IVY_LIST_EACH( clients, app )
{
- applist[appCount++]= app->app_name;
+ strcat( applist, app->app_name );
+ strcat( applist, sep );
}
return applist;
}
char **IvyGetApplicationMessages( IvyClientPtr app )
{
- static char *messagelist[200];
+#define MAX_REGEXP 4096
+ static char *messagelist[MAX_REGEXP+1];/* TODO remove that ugly Thing */
MsgSndPtr msg;
int msgCount= 0;
memset( messagelist, 0 , sizeof( messagelist ));
@@ -1199,6 +945,53 @@ char **IvyGetApplicationMessages( IvyClientPtr app )
IVY_LIST_EACH( app->msg_send, msg )
{
messagelist[msgCount++]= msg->str_regexp;
+ if ( msgCount >= MAX_REGEXP )
+ {
+ fprintf(stderr,"Too Much expression(%d) for buffer\n",msgCount);
+ break;
+ }
}
return messagelist;
}
+
+static void substituteInterval (IvyBuffer *src)
+{
+ // pas de traitement couteux s'il n'y a rien à interpoler
+ if (strstr (src->data, "(?I") == NULL) {
+ return;
+ } else {
+ char *curPos;
+ char *itvPos;
+ IvyBuffer dst = {NULL, 0, 0};
+ dst.size = 8192;
+ dst.data = malloc (dst.size);
+
+ curPos = src->data;
+ while ((itvPos = strstr (curPos, "(?I")) != NULL) {
+ // copie depuis la position courante jusqu'à l'intervalle
+ int lenCp, min,max;
+ char withDecimal;
+ lenCp = itvPos-curPos;
+ memcpy (&(dst.data[dst.offset]), curPos, lenCp);
+ curPos=itvPos;
+ dst.offset += lenCp;
+
+ // extraction des paramètres de l'intervalle
+ sscanf (itvPos, "(?I%d#%d%c", &min, &max, &withDecimal);
+
+ // printf ("DBG> substituteInterval min=%d max=%d withDecimal=%d\n",
+ // min, max, (withDecimal != 'i'));
+
+ // generation et copie de l'intervalle
+ regexpGen (&(dst.data[dst.offset]), dst.size-dst.offset, min, max, (withDecimal != 'i'));
+ dst.offset = strlen (dst.data);
+
+ // consommation des caractères décrivant intervalle dans la chaine source
+ curPos = strstr (curPos, ")");
+ curPos++;
+ }
+ strncat (dst.data, curPos, dst.size-dst.offset);
+ free (src->data);
+ src->data = dst.data;
+ }
+}