Initial revision
authorteodor <teodor>
Wed, 22 Sep 2004 10:59:48 +0000 (10:59 +0000)
committerteodor <teodor>
Wed, 22 Sep 2004 10:59:48 +0000 (10:59 +0000)
27 files changed:
Makefile [new file with mode: 0644]
connection.h [new file with mode: 0644]
connpool.c [new file with mode: 0644]
hextest.c [new file with mode: 0644]
inftest.c [new file with mode: 0644]
kilter.c [new file with mode: 0644]
prs_hmap.c [new file with mode: 0644]
prs_hmap.h [new file with mode: 0644]
prs_inf.c [new file with mode: 0644]
prs_inf.h [new file with mode: 0644]
regis.c [new file with mode: 0644]
regis.h [new file with mode: 0644]
res [new file with mode: 0644]
sfxstr.c [new file with mode: 0644]
sfxstr.h [new file with mode: 0644]
sfxtest.c [new file with mode: 0644]
shmem.c [new file with mode: 0644]
shmem.h [new file with mode: 0644]
tcp.c [new file with mode: 0644]
test.inf [new file with mode: 0644]
tlog.c [new file with mode: 0644]
tlog.h [new file with mode: 0644]
tmalloc.c [new file with mode: 0644]
tmalloc.h [new file with mode: 0644]
tools.c [new file with mode: 0644]
tools.h [new file with mode: 0644]
udp.c [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..cdd4683
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,36 @@
+CC=gcc
+AR=ar rcv
+RANLIB=ranlib
+LD=ld -x -shared
+
+INCLUDE=-I.
+CFLAGS=-Wall -g -O2 -pedantic -ansi -DASSERT_CORE -D_GNU_SOURCE -DHAVE_POLL_H -DHAVE_SYS_POLL_H -DHAVE_HSTRERROR
+LIB=-L. -ltedtools
+
+OBJS=tlog.o tmalloc.o tools.o prs_hmap.o sfxstr.o \
+       regis.o prs_inf.o shmem.o tcp.o udp.o connpool.o
+PROGS=sfxtest hextest inftest kilter
+
+.SUFFIXES: .o.c
+
+all: libtedtools.a $(PROGS)
+
+$(PROGS): %: %.o
+       $(CC) -o $@ $< $(LIB)
+
+$(PROGS): libtedtools.a
+
+libtedtools.a: $(OBJS)
+       $(AR) $@ $?
+       $(RANLIB) $@
+
+.c.o:
+       $(CC) $(CFLAGS) $(INCLUDE) -c $<
+
+clean:
+       rm -rf $(OBJS)
+       rm -rf $(PROGS) *.o
+       rm -rf libtedtools.a
+       rm -rf *core *gmon* nohup.out
+       rm -rf sfxtest.log
+
diff --git a/connection.h b/connection.h
new file mode 100644 (file)
index 0000000..2bc936d
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CONNECTION_H__
+#define __CONNECTION_H__
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+
+
+#define CS_OK          0
+#define CS_INPROCESS    1
+#define CS_CONNECTED    2
+#define CS_READ         3
+#define CS_SEND         4
+#define CS_WAIT         5
+#define CS_ERROR        6
+#define CS_FINISHSEND   7
+#define CS_FINISHREAD   8
+#define CS_TIMEOUT     9
+#define CS_CLOSED      10      
+#define CS_NOTINITED           11
+#define CS_AGAIN       12
+#define CS_FINISH      13
+
+
+#define READ_INCRIMENT_BUFSIZ 1024
+
+typedef struct {
+       /* I/O buffer */
+        u_int32_t  len;
+        char    *buf;
+        char    *ptr;
+
+       /* internal fields */
+        int     fd;
+        u_int32_t
+               readyio:1,  
+               state:29;
+        struct sockaddr_in serv_addr;
+
+       /* external link */
+       void*           data;
+} TC_Connection;
+
+#define TCCONNHDRSZ   ( sizeof(TC_Connection) - sizeof(void*) )
+
+TC_Connection *TC_fillConnection( TC_Connection *cs, char *name, u_int32_t port );
+TC_Connection* TC_AcceptTcp(TC_Connection *cs);
+u_int32_t TC_ClientInitConnection(TC_Connection *cs, char *name, u_int32_t port);
+u_int32_t TC_ServerInitConnect( TC_Connection *cs );
+u_int32_t TC_ServerConnect( TC_Connection *cs );
+u_int32_t TC_Send( TC_Connection *cs );
+u_int32_t TC_Read( TC_Connection *cs );
+u_int32_t TC_Talk( TC_Connection *cs );
+void TC_FreeConnection( TC_Connection *cs );
+int TC_ReadyIO( TC_Connection **cs, int number, int timeout );
+
+typedef struct {
+        u_int32_t       len;
+        u_int32_t       type;
+        char            data[1];
+} TCMsg;
+
+#define TCMSGHDRSZ      (2*sizeof(u_int32_t))
+
+
+/* udp */
+typedef struct {
+       char    *host;
+       u_int32_t       port;
+       TCMsg   *msg;
+
+       /* private members */
+       int             sockfd;
+       struct sockaddr_in host_addr;
+} Msg; 
+
+/* 
+ * Udp server loop:
+ * TC_Connection  conn,*connptr;
+ * conn.fd = TC_AcceptUdp("127.0.0.1", 5432);
+ * conn.state = CS_READ;
+ * connptr = &conn;
+ * while(1) {
+ *     if ( TC_ReadyIO( &connptr, 1, 100 ) ) {
+ *             Msg m; 
+ *             if ( TC_getMsg(conn.fd, &m) == CS_OK ) {
+ *                     //do something
+ *             } 
+ *     }
+ * }
+ * close(conn.fd);
+ *
+ * Udp client send:
+ * Msg msg;
+ * msg.host        = "127.0.0.1";
+ * msg.port        = 5432;
+ * msg.sockfd =-1;
+ * msg.msg = GOTFILLEDPMSG();
+ * if ( TC_sendMsg(&msg)!=CS_OK ) {
+ *        //Very bad
+ * }
+ * msg.msg = GOTFILLEDPMSG();
+ * if ( TC_sendMsg(&msg)!=CS_OK ) {
+ *        //Very bad
+ * }
+ * TC_closefd(&msg);
+ */ 
+
+int TC_AcceptUdp(char *host, int port);
+u_int32_t TC_getMsg( int sockfd, Msg *msg );
+u_int32_t TC_sendMsg( Msg *msg );
+void     TC_closefd( Msg *msg );
+
+typedef struct {
+        u_int32_t       len;
+        u_int32_t       number;
+        TC_Connection   **conn;
+} PoolConnection;
+
+void TC_addConnection(PoolConnection *pool, TC_Connection *c);
+void TC_deleteConnectionByN(PoolConnection *pool, int n);
+void TC_deleteConnectionByC(PoolConnection *pool, TC_Connection *c);
+
+#endif
+
diff --git a/connpool.c b/connpool.c
new file mode 100644 (file)
index 0000000..c91a384
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "connection.h"
+#include "tlog.h"
+#include "tmalloc.h"
+
+
+void
+TC_addConnection(PoolConnection *pool, TC_Connection *c) {
+       if (!c)
+               return;
+       if ( pool->number >= pool->len ) {
+               if ( pool->len == 0 ) {
+                       pool->len = 8;
+                       pool->conn = (TC_Connection**)tmalloc( sizeof(TC_Connection*) * pool->len );
+               } else {
+                       pool->len *= 2;
+                       pool->conn = (TC_Connection**)trealloc( pool->conn, sizeof(TC_Connection*) * pool->len );
+               }
+       } 
+       pool->conn[ pool->number ] = c;
+       pool->number++;
+}
+
+void
+TC_deleteConnectionByN(PoolConnection *pool, int n) {
+       if ( n<0 || n>=pool->number || pool->len<=0 ) 
+               return;
+
+       TC_FreeConnection( pool->conn[ n ] );
+       free( pool->conn[ n ] );
+       if ( n==pool->number-1 ) {
+               pool->number--;
+               return;
+       } 
+
+       memcpy( &( pool->conn[ n ] ), &( pool->conn[ n+1 ] ), sizeof(TC_Connection*) * ( pool->number - n - 1 )); 
+       pool->number--;
+       return;
+}
+
+void
+TC_deleteConnectionByC(PoolConnection *pool, TC_Connection *c) {
+       int i;
+       for(i=0;i<pool->number;i++)
+               if ( pool->conn[ i ] == c ) {
+                       TC_deleteConnectionByN(pool, i);
+                       break;
+               }
+}
diff --git a/hextest.c b/hextest.c
new file mode 100644 (file)
index 0000000..6003a5b
--- /dev/null
+++ b/hextest.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tools.h"
+#include "tmalloc.h"
+#include "tlog.h"
+
+
+int
+main(int argn, char *argv[]) {
+       int i;
+
+       for(i=0;i<20;i++) {
+               u_int32_t orig = (u_int32_t) ( (random()%2) ? random() : rand() );
+               u_int32_t new = atox( xtostr(orig) );
+               char buf[10];
+               printf("ORIG:%d\tORIGHEX:%x\txtostr:%s\tatox(xtostr):%d\n", orig, orig, xtostr(orig), new);
+               tassert( orig==new );
+               sprintf(buf,"%x", orig);
+               tassert( strcmp(buf, strlower(xtostr(orig)))==0 );
+       }
+       
+       return 0;
+}      
diff --git a/inftest.c b/inftest.c
new file mode 100644 (file)
index 0000000..9f76304
--- /dev/null
+++ b/inftest.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+
+#include "prs_inf.h"
+
+int
+main(int argn, char *argv[] ) {
+       InfMap *map, *ptr;
+
+       if ( argn!=2 ) {
+               puts("Usage:");
+               puts("./inftest inffile");
+               return 1;
+       }
+
+       map=ptr=INFParse(argv[1]);
+       while(ptr&&ptr->section) {      
+               printf("S:'%s' K:'%s' V:'%s'\n", 
+                       ptr->section,
+                       (ptr->key) ? ptr->key : "(NULL)",
+                       (ptr->value) ? ptr->value : "(NULL)"
+               );
+               ptr++;
+       }
+       INFFree(map);
+       return 0;
+}
diff --git a/kilter.c b/kilter.c
new file mode 100644 (file)
index 0000000..78866a1
--- /dev/null
+++ b/kilter.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include "tlog.h"
+#include "tmalloc.h"
+
+static int exitAfterLastSignal=0;
+static int kilterDebug=0;
+
+static void
+usage() {
+       puts("Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>. All rights reserved.");
+       puts("Usage:");
+       puts("kilter [-d] [-e] -SIGNAL [+]TIMEOUT [-SIGNAL [+]TIMEOUT [...]] COMMAND");
+       puts("   -d - debug mode");
+       puts("   -e - don't wait child exit after last signal sended");
+       puts("   +TIMEOUT - means related time to previous"); 
+
+       exit(1);
+}
+
+typedef struct {
+       char *name;
+       unsigned int sign;
+} SigName;
+
+static SigName signalname[]={
+       { "HUP",          SIGHUP        },
+       { "INT",          SIGINT        },
+       { "QUIT",         SIGQUIT       },
+       { "ILL",          SIGILL        },
+       { "TRAP",         SIGTRAP       },
+       { "ABRT",         SIGABRT       },
+/*     { "EMT",          SIGEMT        }, */
+       { "FPE",          SIGFPE        },
+       { "KILL",         SIGKILL       },
+       { "BUS",          SIGBUS        },
+       { "SEGV",         SIGSEGV       },
+       { "SYS",          SIGSYS        },
+       { "PIPE",         SIGPIPE       },
+       { "ALRM",         SIGALRM       },
+       { "TERM",         SIGTERM       },
+       { "URG",          SIGURG        },
+       { "STOP",         SIGSTOP       },
+       { "TSTP",         SIGTSTP       },
+       { "CONT",         SIGCONT       },
+       { "CHLD",         SIGCHLD       },
+       { "TTIN",         SIGTTIN       },
+       { "TTOU",         SIGTTOU       },
+       { "IO",           SIGIO         },
+       { "XCPU",         SIGXCPU       },
+       { "XFSZ",         SIGXFSZ       },
+       { "VTALRM",       SIGVTALRM     },
+       { "PROF",         SIGPROF       },
+       { "WINCH",        SIGWINCH      },
+       /* { "INFO",         SIGINFO    },  */
+       { "USR1",         SIGUSR1       },
+       { "USR2",         SIGUSR2       },
+       {  NULL,                0       }
+};
+
+static unsigned int 
+name2sign(char *name) {
+       SigName *ptr = signalname;
+
+       /*strupper(name);*/
+       if ( strncmp(name,"sig",3)==0 )
+               name+=3;
+
+       while( ptr && ptr->name ) {
+               if ( strcmp(name, ptr->name)==0 )
+                       return ptr->sign;
+               ptr++;
+       }
+       
+       return 0;
+}
+
+
+static char sbuf[16];
+
+static char*
+sign2name(unsigned int sign) {
+       SigName *ptr = signalname;
+
+       while( ptr && ptr->name ) {
+               if (sign==ptr->sign) {
+                       strcpy(sbuf,"SIG");
+                       strcpy(sbuf+3,ptr->name);
+                       return sbuf;
+               }
+               ptr++;
+       }
+       return NULL;
+}
+
+typedef struct ChildAction {
+       unsigned int    sign;
+       int             timeout;
+       struct ChildAction *next;
+} ChildAction;
+
+#define PCL_WAITOPTION         0
+#define PCL_OPTION     1
+#define PCL_OPTIONVAL  2
+
+
+int
+parsecmdline(int argn, char *argv[], ChildAction **ca) {
+       int i;
+       int state=PCL_WAITOPTION;
+       ChildAction *captr=NULL,*caend=NULL,*caprev=NULL;
+
+       *ca=NULL;
+
+       for(i=0;i<argn;i++) {
+               char *ptr=argv[i];
+
+               while(ptr && *ptr) {
+                       if ( state == PCL_WAITOPTION ) {
+                               if (*ptr=='-') 
+                                       state=PCL_OPTION;
+                               else
+                                       return i;
+                       } else if ( state == PCL_OPTION ) {
+                               if (isdigit(*ptr)) {
+                                       captr = t0malloc(sizeof(ChildAction));
+                                       if ( *ca ) {
+                                               caprev=caend;
+                                               caend->next=captr;
+                                               caend=captr;
+                                       } else {
+                                               *ca=caend=captr;
+                                       }
+                                       captr->sign=atoi(ptr);
+                                       if ( !sign2name(captr->sign) )
+                                               tlog(TL_ALARM|TL_EXIT,"Unknown signal value: %d", captr->sign);
+                               } else if (isalpha(*ptr)) {
+                                       if ( strcmp(ptr,"h")==0 ) {
+                                               usage();
+                                       } else if ( strcmp(ptr,"d")==0 ) {
+                                               kilterDebug=1;
+                                               state = PCL_WAITOPTION;
+                                               break;
+                                       } else if ( strcmp(ptr,"e")==0 ) {
+                                               exitAfterLastSignal=1;
+                                               state = PCL_WAITOPTION;
+                                               break;
+                                       } else {
+                                               captr = t0malloc(sizeof(ChildAction));
+                                               if ( *ca ) {
+                                                       caprev=caend;
+                                                       caend->next=captr;
+                                                       caend=captr;
+                                               } else {
+                                                       *ca=caend=captr;
+                                               }
+                                               captr->sign=name2sign(ptr);
+                                               if (!captr->sign) 
+                                                       tlog(TL_ALARM|TL_EXIT,"Unknown signal name: %s", ptr);
+                                       }
+                               } else
+                                       tlog(TL_ALARM|TL_EXIT,"Unknown option: %s", ptr);
+                               state = PCL_OPTIONVAL;
+                               break;
+                       } else if ( state == PCL_OPTIONVAL ) {
+                               tassert(captr!=NULL);
+                               if (isdigit(*ptr) || *ptr=='+' ) {
+                                       captr->timeout = atoi(ptr);
+                                       if ( captr->timeout==0 )
+                                               tlog(TL_ALARM|TL_EXIT,"Wrong timeout: %s", ptr);
+                                       if (*ptr!='+' && caprev) {
+                                               if ( captr->timeout<=caprev->timeout )
+                                                       tlog(TL_ALARM|TL_EXIT,"Wrong absolute timeout: %d", captr->timeout);
+                                               captr->timeout -= caprev->timeout; 
+                                       }
+                                       state = PCL_WAITOPTION;
+                               } else
+                                       tlog(TL_ALARM|TL_EXIT,"Wrong timeout: %s", ptr);
+                               break;
+                       } else
+                               tlog(TL_CRIT|TL_EXIT,"parsecmdline: Wrong state: %d", state);
+                       ptr++;
+               }
+       }
+
+       usage();
+       
+       return 0;
+}
+
+static int wasSIGCHILD=0;
+
+static void
+handlerSIGCHILD(int s) {
+        wasSIGCHILD=1;
+}
+
+
+int
+main(int argn, char *argv[]) {
+       ChildAction     *ca,*ptr;
+       int skip=0, status;
+       pid_t   child;
+       int elapsedtime=0;
+
+       if ( argn<2 )
+               usage();
+
+       skip=parsecmdline(argn-1, argv+1, &ca)+1;
+       if ( skip==1 ) usage();
+
+       argn-=skip;
+       argv+=skip;
+
+       if ( kilterDebug )
+               opentlog( TL_OPEN_STDERR,  TL_DEBUG, NULL);
+       else
+               opentlog( TL_OPEN_SYSLOG, TL_INFO, NULL);
+
+       if ( signal(SIGCHLD, handlerSIGCHILD)==SIG_ERR )
+               tlog(TL_CRIT|TL_EXIT,"signal call failed: %s", strerror(errno));  
+       
+
+       if ( (child=fork()) == 0 ) {
+               /* child */
+               if (execvp(*argv, argv)==-1)
+                       tlog(TL_CRIT|TL_EXIT,"Exec error: %s", strerror(errno));
+       }
+       if (child==-1)
+               tlog(TL_CRIT|TL_EXIT,"Can't fork: %s", strerror(errno));
+
+       while(ca) {
+               elapsedtime=(wasSIGCHILD) ? ca->timeout : sleep(ca->timeout);
+               if ( elapsedtime > 0 || wasSIGCHILD ) {
+                       wasSIGCHILD=0;
+                       if ( waitpid(child, &status, WNOHANG) == -1 )
+                               tlog(TL_CRIT|TL_EXIT,"waitpid for %d process failed: %s", child, strerror(errno));
+                       if ( WIFEXITED(status) ) {
+                               tlog(TL_INFO, "Child %d was exited with status  %d", child, WEXITSTATUS(status));
+                               return 0;
+                       } else if ( WIFSIGNALED(status) ) { 
+                               tlog(TL_INFO, "Child %d was exited with signal %d(%s)", child, WTERMSIG(status), 
+                                       ( sign2name(WTERMSIG(status)) ) ? sign2name(WTERMSIG(status)) : "unknown");
+                               return 0;
+                       }
+                       ca->timeout = elapsedtime;
+               } else {
+                       if ( kill(child, ca->sign) != 0 )
+                               tlog(TL_CRIT|TL_EXIT,"kill %d process failed: %s", child, strerror(errno));
+                       tlog(TL_INFO,"%s'ed process %d", sign2name(ca->sign), child);
+                       ptr=ca->next;
+                       tfree(ca);
+                       ca=ptr;
+               }
+       }
+
+       if ( exitAfterLastSignal==0 ) {
+               if ( waitpid(child, &status, 0) == -1 )
+                       tlog(TL_CRIT|TL_EXIT,"waitpid for %d process failed: %s", child, strerror(errno));
+               if ( WIFEXITED(status) ) 
+                       tlog(TL_INFO, "Child %d was exited with status %d", child, WEXITSTATUS(status));
+               else if ( WIFSIGNALED(status) ) 
+                       tlog(TL_INFO, "Child %d was exited with signal %d(%s)", child, WTERMSIG(status), 
+                               ( sign2name(WTERMSIG(status)) ) ? sign2name(WTERMSIG(status)) : "unknown");
+               else
+                       tlog(TL_INFO, "Child %d wasn't exited",child);
+       } else 
+               tlog(TL_DEBUG, "Exit, don't wait a process %d", child);
+
+       return 0;
+}
diff --git a/prs_hmap.c b/prs_hmap.c
new file mode 100644 (file)
index 0000000..76e0769
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "tlog.h"
+#include "tmalloc.h"
+#include "prs_hmap.h"
+
+
+
+#define CS_WAITKEY     0
+#define CS_INKEY       1
+#define CS_WAITEQ      2
+#define CS_WAITVALUE   3
+#define CS_INVALUE     4
+#define CS_IN2VALUE 5
+#define CS_WAITDELIM   6
+#define CS_INESC       7
+#define CS_IN2ESC      8
+
+static char *
+nstrdup(char *ptr, int len) {
+       char       *res = tmalloc(len + 1),
+                          *cptr;
+
+       memcpy(res, ptr, len);
+       res[len] = '\0';
+       cptr = ptr = res;
+       while (*ptr) {
+               if (*ptr == '\\')
+                       ptr++;
+               *cptr = *ptr;
+               ptr++;
+               cptr++;
+       }
+       *cptr = '\0';
+
+       return res;
+}
+
+void
+parse_hmap(char *in, HMap ** m) {
+       HMap               *mptr;
+       char       *ptr = in,
+                          *begin = NULL;
+       char            num = 0;
+       int                     state = CS_WAITKEY;
+
+       while (*ptr)
+       {
+               if (*ptr == ',')
+                       num++;
+               ptr++;
+       }
+
+       *m = mptr = (HMap *) t0malloc(sizeof(HMap) * (num + 2));
+       ptr = in;
+       while (*ptr) {
+               if (state == CS_WAITKEY) {
+                       if (isalpha((unsigned char) *ptr)) {
+                               begin = ptr;
+                               state = CS_INKEY;
+                       } else if (!isspace((unsigned char) *ptr))      
+                               tlog(TL_ALARM|TL_EXIT,"parse_hmap: Syntax error in position %d near \"%c\"\n", (int) (ptr - in), *ptr);
+               } else if (state == CS_INKEY) {
+                       if (isspace((unsigned char) *ptr)) {
+                               mptr->key = nstrdup(begin, ptr - begin);
+                               state = CS_WAITEQ;
+                       } else if (*ptr == '=') {
+                               mptr->key = nstrdup(begin, ptr - begin);
+                               state = CS_WAITVALUE;
+                       } else if (!isalpha((unsigned char) *ptr))
+                               tlog(TL_ALARM|TL_EXIT,"parse_hmap: Syntax error in position %d near \"%c\"\n", (int) (ptr - in), *ptr);
+               } else if (state == CS_WAITEQ) {
+                       if (*ptr == '=')
+                               state = CS_WAITVALUE;
+                       else if (!isspace((unsigned char) *ptr))
+                               tlog(TL_ALARM|TL_EXIT,"parse_hmap: Syntax error in position %d near \"%c\"\n", (int) (ptr - in), *ptr);
+               } else if (state == CS_WAITVALUE) {
+                       if (*ptr == '"') {
+                               begin = ptr + 1;
+                               state = CS_INVALUE;
+                       } else if (!isspace((unsigned char) *ptr)) {
+                               begin = ptr;
+                               state = CS_IN2VALUE;
+                       }
+               } else if (state == CS_INVALUE) {
+                       if (*ptr == '"') {
+                               mptr->value = nstrdup(begin, ptr - begin);
+                               mptr++;
+                               state = CS_WAITDELIM;
+                       } else if (*ptr == '\\')
+                               state = CS_INESC;
+               } else if (state == CS_IN2VALUE) {
+                       if (isspace((unsigned char) *ptr) || *ptr == ',') {
+                               mptr->value = nstrdup(begin, ptr - begin);
+                               mptr++;
+                               state = (*ptr == ',') ? CS_WAITKEY : CS_WAITDELIM;
+                       } else if (*ptr == '\\')
+                               state = CS_INESC;
+               } else if (state == CS_WAITDELIM) {
+                       if (*ptr == ',')
+                               state = CS_WAITKEY;
+                       else if (!isspace((unsigned char) *ptr))
+                               tlog(TL_ALARM|TL_EXIT,"parse_hmap: Syntax error in position %d near \"%c\"\n", (int) (ptr - in), *ptr);
+               } else if (state == CS_INESC)
+                       state = CS_INVALUE;
+               else if (state == CS_IN2ESC)
+                       state = CS_IN2VALUE;
+               else
+                       tlog(TL_CRIT|TL_EXIT,"parse_hmap: Bad parser state %d at position %d near \"%c\"\n", state, (int) (ptr - in), *ptr);
+               ptr++;
+       }
+
+       if (state == CS_IN2VALUE) {
+               mptr->value = nstrdup(begin, ptr - begin);
+               mptr++;
+       }
+       else if (!(state == CS_WAITDELIM || state == CS_WAITKEY))
+               tlog(TL_ALARM|TL_EXIT,"parse_hmap: unexpected end of line\n");
+}
diff --git a/prs_hmap.h b/prs_hmap.h
new file mode 100644 (file)
index 0000000..1363070
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __PRS_HMAP_H__
+#define __PRS_HMAP_H__
+
+/* simple parser of cfg string */
+typedef struct {
+        char       *key;
+        char       *value;
+}       HMap;
+
+void  parse_hmap(char *in, HMap ** m);
+
+#endif
diff --git a/prs_inf.c b/prs_inf.c
new file mode 100644 (file)
index 0000000..5651e33
--- /dev/null
+++ b/prs_inf.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "tlog.h"
+#include "tmalloc.h"
+#include "prs_inf.h"
+
+#define INF_WAIT       1
+#define        INF_COMMENT     2
+#define INF_SECTION    3
+#define INF_KEY                4
+#define INF_WAITVAL    5
+#define INF_INQVAL     6
+#define INF_INVAL      7
+#define INF_QESCAPE    8
+#define INF_ESCAPE     9
+#define INF_WAITDELIM   10
+
+
+#define CHECKBUF       do {            \
+       if (bufptr-buf+1>=buflen) {     \
+       int diff = bufptr-buf;          \
+       buflen*=2;                      \
+       buf=trealloc(buf,buflen);       \
+       bufptr=buf+diff;                \
+       }                               \
+} while(0)
+
+#define CHECKMAP       do {            \
+       if (mapptr-map+1>=maplen) {     \
+       int diff = mapptr-map;          \
+       maplen*=2;                      \
+       map=trealloc(map,maplen);       \
+       mapptr=map+diff;                \
+       }                               \
+} while(0)
+
+#define ISKEYNAME(c)   ( (c)=='_' || isalnum(c) )
+
+static void
+clrbackspace(char *ptr, char *buf) {
+       while(ptr>=buf && (*ptr==' '||*ptr=='\t') ) {
+               *ptr='\0';
+               ptr--;
+       }
+}
+
+InfMap*
+INFParse(char *file) {
+       FILE *in;
+       int maplen=32, buflen=32;
+       InfMap *mapptr,*map;
+       int state=INF_WAIT, c;
+       char *buf,*bufptr;
+       int lineno=1;
+
+       if ( (in=fopen(file,"r"))==NULL )
+               tlog(TL_ALARM|TL_EXIT,"Can't open inf file '%s': %s", file, strerror(errno));
+
+       map=mapptr=(InfMap*)tmalloc(sizeof(InfMap)*maplen);
+       buf = bufptr = (char*)tmalloc(buflen);
+       mapptr->section=NULL; 
+
+       while( (c=fgetc(in))!=EOF ) {
+               CHECKBUF;
+               CHECKMAP;
+               if (c=='\r')
+                       continue;
+
+               if ( state==INF_WAIT ) {
+                       if ( c=='\n' )
+                               lineno++;
+                       else if ( c=='[' ) {
+                               bufptr=buf;
+                               state=INF_SECTION;
+                       } else if ( c=='#' )
+                               state=INF_COMMENT;
+                       else if ( ISKEYNAME(c) ) {
+                               if ( mapptr->section==NULL )
+                                       tlog(TL_ALARM|TL_EXIT, "Undefined section name at line %d, file %s", lineno, file);
+                               bufptr=buf;
+                               *bufptr=c;
+                               bufptr++;
+                               state=INF_KEY;
+                       }
+               } else if ( state==INF_SECTION ) {
+                       if ( c==']' ) {
+                               if ( bufptr==buf ) {
+                                       tlog(TL_ALARM|TL_EXIT,
+                                               "Void section name at line %d, file %s", lineno, file);
+                               } else {
+                                       if ( mapptr->section ) tfree(mapptr->section);
+                                       *bufptr='\0';
+                                       mapptr->section = tstrdup(buf);
+                                       bufptr=buf;     
+                               }
+                               state=INF_WAIT;
+                       } else if ( ISKEYNAME(c) ) {
+                               *bufptr=c;
+                               bufptr++;
+                       } else 
+                               tlog( TL_ALARM|TL_EXIT,"Syntax error at line %d, file %s", lineno, file);
+               } else if ( state==INF_COMMENT ) {
+                       if (c=='\n') {
+                               lineno++;
+                               state=INF_WAIT;
+                       }
+               } else if ( state==INF_KEY ) {
+                       if (ISKEYNAME(c)) {
+                               *bufptr=c;
+                               bufptr++;
+                       } else if (c=='=') {
+                               *bufptr='\0';
+                               mapptr->key = tstrdup(buf);
+                               bufptr=buf;
+                               state=INF_WAITVAL;
+                       } else if (c==' ' || c=='\t') {
+                               *bufptr='\0';
+                               mapptr->key = tstrdup(buf);
+                               bufptr=buf;
+                               state=INF_WAITDELIM;
+                       } else
+                               tlog( TL_ALARM|TL_EXIT,"Syntax error at line %d, file %s", lineno, file);
+               } else if ( state==INF_WAITDELIM ) {
+                       if (c=='=')
+                               state=INF_WAITVAL;
+                       else if (!(c==' ' || c=='\t'))
+                               tlog( TL_ALARM|TL_EXIT,"Syntax error at line %d, file %s", lineno, file);
+               } else if ( state==INF_WAITVAL ) {
+                       if ( c=='\n' ) {
+                               bufptr=buf;
+                               *bufptr='\0';
+                               mapptr->value=tstrdup(buf);
+                               mapptr++;
+                               mapptr->section = tstrdup((mapptr-1)->section);
+                               state=INF_WAIT;
+                               lineno++;
+                       } else if ( c=='\\' ) {
+                               bufptr=buf;
+                               state=INF_ESCAPE;
+                       } else if ( c=='"' ) {
+                               bufptr=buf;
+                               state=INF_INQVAL;
+                       } else if ( !(c==' ' || c=='\t') ) {
+                               bufptr=buf;
+                               *bufptr=c;
+                               bufptr++;
+                               state=INF_INVAL;
+                       }
+               } else if ( state==INF_ESCAPE ) {
+                       *bufptr=c;
+                       bufptr++;
+                       state=INF_INVAL;
+                       if (c=='\n') lineno++;
+               } else if ( state==INF_QESCAPE ) {
+                       *bufptr=c;
+                       bufptr++;
+                       state=INF_INQVAL;
+                       if (c=='\n') lineno++;
+               } else if ( state==INF_INVAL ) {
+                       if ( c=='#' ) {
+                               *bufptr=' ';
+                               clrbackspace(bufptr,buf);
+                               mapptr->value=tstrdup(buf);
+                               mapptr++;
+                               mapptr->section = tstrdup((mapptr-1)->section);
+                               bufptr=buf;
+                               state=INF_COMMENT;
+                       } else if (c=='\n') {
+                               *bufptr=' ';
+                               clrbackspace(bufptr,buf);
+                               mapptr->value=tstrdup(buf);
+                               mapptr++;
+                               mapptr->section = tstrdup((mapptr-1)->section);
+                               bufptr=buf;
+                               state=INF_WAIT;
+                               lineno++;
+                       } else if (c=='\\') {
+                               state=INF_ESCAPE;
+                       } else {
+                               *bufptr=c;
+                               bufptr++;
+                       }
+               } else if ( state==INF_INQVAL ) {
+                       if (c=='\\') {
+                               state=INF_QESCAPE;
+                       } else if ( c=='"' ) {
+                               *bufptr='\0';
+                               mapptr->value=tstrdup(buf);
+                               mapptr++;
+                               mapptr->section = tstrdup((mapptr-1)->section);
+                               bufptr=buf;
+                               state=INF_WAIT;
+                       } else {
+                               *bufptr=c;
+                               bufptr++;
+                               if (c=='\n') lineno++;
+                       }
+               } else 
+                       tlog( TL_CRIT|TL_EXIT,"INFParse: internal error, unknown state %d", state );
+       }
+
+       if ( state==INF_INVAL ) {
+               *bufptr=' ';
+               clrbackspace(bufptr,buf);
+               mapptr->value=tstrdup(buf);
+               mapptr++;
+               mapptr->section=NULL;
+               bufptr=buf;
+       } else if ( state!=INF_WAIT ) {
+               tlog( TL_ALARM|TL_EXIT,"Unexpected end of file %s", file);
+       } else if (mapptr->section) {
+               tfree(mapptr->section);
+               mapptr->section=NULL;
+       }
+       tfree(buf);
+       fclose(in);
+
+       return map;     
+}
+
+void  
+INFFree(InfMap *inf) {
+       InfMap *ptr=inf;
+       while(ptr && ptr->section) {
+               tfree(ptr->section);
+               if (ptr->key) tfree(ptr->key);
+               if (ptr->value) tfree(ptr->value);
+               ptr++;
+       }
+       tfree(inf);
+}
+
+InfMap*
+INFFindInfMap(InfMap *inf, char *sect, char *key) {
+       while(inf && inf->section) {
+               if (
+                       (sect==NULL || strcmp(inf->section,sect)==0) &&
+                       (key==NULL || strcmp(inf->key,key)==0)
+                  )
+                  return inf;
+
+               inf++;
+       }
+       return NULL;
+}
+
+int
+INFGetInt(InfMap *inf, char *sect, char *key, int *val) {
+       inf = INFFindInfMap(inf, sect, key);
+       if (inf) {
+               *val=atoi(inf->value);
+               return 0;
+       }
+       return 1;
+}
+
+int
+INFGetUint(InfMap *inf, char *sect, char *key, u_int32_t *val) {
+       inf = INFFindInfMap(inf, sect, key);
+       if (inf) {
+               *val=strtoul(inf->value, NULL,0);
+               return 0;
+       }
+       return 1;
+}
+
+int
+INFGetFloat(InfMap *inf, char *sect, char *key, float *val) {
+       inf = INFFindInfMap(inf, sect, key);
+       if (inf) {
+               *val=strtof(inf->value, NULL);
+               return 0;
+       }
+       return 1;
+}
+
+int
+INFGetDouble(InfMap *inf, char *sect, char *key, double *val) {
+       inf = INFFindInfMap(inf, sect, key);
+       if (inf) {
+               *val=strtod(inf->value, NULL);
+               return 0;
+       }
+       return 1;
+}
+
+int
+INFGetString(InfMap *inf, char *sect, char *key, char **val) {
+       inf = INFFindInfMap(inf, sect, key);
+       if (inf) {
+               *val=tstrdup(inf->value);
+               return 0;
+       }
+       return 1;
+}
+
+
diff --git a/prs_inf.h b/prs_inf.h
new file mode 100644 (file)
index 0000000..4694cb7
--- /dev/null
+++ b/prs_inf.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __PRS_INF_H__
+#define __PRS_INF_H__
+
+#include <sys/types.h>
+
+/* simple parser of cfg string */
+typedef struct {
+        char       *section;
+        char       *key;
+        char       *value;
+}       InfMap;
+
+InfMap*  INFParse(char *file);
+void  INFFree(InfMap *inf);
+
+InfMap* INFFindInfMap(InfMap *inf, char *sect, char *key);
+int INFGetInt(InfMap *inf, char *sect, char *key, int *val);
+int INFGetUint(InfMap *inf, char *sect, char *key, u_int32_t *val);
+int INFGetFloat(InfMap *inf, char *sect, char *key, float *val);
+int INFGetDouble(InfMap *inf, char *sect, char *key, double *val);
+int INFGetString(InfMap *inf, char *sect, char *key, char **val);
+
+#endif
diff --git a/regis.c b/regis.c
new file mode 100644 (file)
index 0000000..36df610
--- /dev/null
+++ b/regis.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <ctype.h>
+         
+#include "tlog.h"
+#include "tmalloc.h"
+#include "regis.h"
+
+
+int
+RS_isRegis(const char *str) {
+       unsigned char *ptr=(unsigned char *)str;
+
+       while(ptr && *ptr) 
+               if ( isalpha(*ptr) || *ptr=='[' || *ptr==']' || *ptr=='^')
+                       ptr++;
+               else
+                       return 0;
+       return 1; 
+}
+
+#define RS_IN_ONEOF    1
+#define RS_IN_ONEOF_IN 2
+#define RS_IN_NONEOF   3
+#define RS_IN_WAIT     4
+
+static RegisNode*
+newRegisNode(RegisNode *prev, int len) {
+       RegisNode       *ptr;
+       ptr = (RegisNode*)t0malloc(RNHDRSZ+len+1);
+       if (prev)
+               prev->next=ptr;
+       return ptr;
+}
+
+int
+RS_compile(Regis *r, int issuffix, const char *str) {
+       int i,len = strlen(str);
+       int state = RS_IN_WAIT;
+       RegisNode       *ptr=NULL;
+
+       memset(r,0,sizeof(Regis));
+       r->issuffix = (issuffix) ? 1 : 0;
+
+       for(i=0;i<len;i++) {
+               unsigned char c = *( ( (unsigned char*)str ) + i );
+               if ( state == RS_IN_WAIT ) {
+                       if ( isalpha(c) ) {
+                               if ( ptr ) 
+                                       ptr = newRegisNode(ptr,len);
+                               else
+                                       ptr = r->node = newRegisNode(NULL,len);
+                               ptr->data[ 0 ] = c;
+                               ptr->type = RSF_ONEOF;
+                               ptr->len=1;
+                       } else if ( c=='[' )  {
+                               if ( ptr ) 
+                                       ptr = newRegisNode(ptr,len);
+                               else
+                                       ptr = r->node = newRegisNode(NULL,len);
+                               ptr->type = RSF_ONEOF;
+                               state=RS_IN_ONEOF;
+                       } else 
+                               tlog(TL_ALARM|TL_EXIT,"Error in regis: %s at pos %d\n", str, i+1);
+               } else if ( state == RS_IN_ONEOF ) {
+                       if ( c=='^' ) {
+                               ptr->type = RSF_NONEOF;
+                               state=RS_IN_NONEOF;
+                       } else if ( isalpha(c) ) {
+                               ptr->data[ 0 ] = c;
+                               ptr->len=1;
+                               state=RS_IN_ONEOF_IN;
+                       } else
+                               tlog(TL_ALARM|TL_EXIT,"Error in regis: %s at pos %d\n", str,  i+1);
+               } else if ( state == RS_IN_ONEOF_IN || state == RS_IN_NONEOF ) {
+                       if ( isalpha(c) ) {
+                               ptr->data[ ptr->len ] = c;
+                               ptr->len++;
+                       } else if ( c==']' ) {
+                               state=RS_IN_WAIT;
+                       } else
+                               tlog(TL_ALARM|TL_EXIT,"Error in regis: %s at pos %d\n", str,  i+1);
+               } else
+                       tlog(TL_CRIT|TL_EXIT,"Internal error in RS_compile: %d\n", state);
+       }
+
+       ptr = r->node;
+       while(ptr) {
+               r->nchar++;
+               ptr=ptr->next;
+       }
+
+       return 0;
+}
+
+void 
+RS_free(Regis *r) {
+       RegisNode *ptr=r->node,*tmp;
+
+       while(ptr) {
+               tmp=ptr->next;
+               tfree(ptr);
+               ptr = tmp;
+       }
+
+       r->node = NULL;
+}
+
+int 
+RS_execute(Regis *r, const char *str, int len) {
+       RegisNode *ptr=r->node;
+       unsigned char *c;
+
+       if (len<0)
+               len=strlen(str);
+
+       if (len<r->nchar)
+               return 0;
+
+       if ( r->issuffix ) 
+               c = ((unsigned char*)str) + len - r->nchar;
+       else
+               c = (unsigned char*)str; 
+
+       while(ptr) {
+               switch(ptr->type) {
+                       case RSF_ONEOF:
+                               if ( ptr->len==0 ) {
+                                       if ( *c != *(ptr->data) )
+                                               return 0;
+                               } else if ( strchr((char*)ptr->data, *c) == NULL )
+                                       return 0;
+                               break;
+                       case RSF_NONEOF:
+                               if ( ptr->len==0 ) {
+                                       if ( *c == *(ptr->data) )
+                                               return 0;
+                               } else if ( strchr((char*)ptr->data, *c) != NULL )
+                                       return 0;
+                               break;
+                       default:
+                               tlog(TL_CRIT|TL_EXIT,"RS_execute: Unknown type node: %d\n", ptr->type);
+               }
+               ptr=ptr->next;
+               c++;
+       }
+
+       return 1;
+}
diff --git a/regis.h b/regis.h
new file mode 100644 (file)
index 0000000..c28c619
--- /dev/null
+++ b/regis.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __REGIS_H__
+#define __REGIS_H__
+
+#include <sys/types.h>
+
+typedef struct RegisNode {
+       u_int32_t       
+               type:2,
+               len:16,
+               unused:14;
+       struct RegisNode *next;
+       unsigned char   data[1];
+} RegisNode;
+
+#define  RNHDRSZ       (sizeof(u_int32_t)+sizeof(void*))
+
+#define        RSF_ONEOF       1
+#define        RSF_NONEOF      2
+
+typedef struct Regis {
+       RegisNode *node;
+       u_int32_t       
+               issuffix:1,
+               nchar:16,
+               unused:15;
+} Regis;
+
+int RS_isRegis(const char *str);
+
+int RS_compile(Regis *r, int issuffix, const char *str);
+void RS_free(Regis *r);
+/*×ÏÚ×ÒÁÝÁÅÔ 1 ÅÓÌÉ ÍÁÔÞÉÔÓÑ */
+int RS_execute(Regis *r, const char *str, int len); 
+#endif
diff --git a/res b/res
new file mode 100644 (file)
index 0000000..86ee3f4
--- /dev/null
+++ b/res
@@ -0,0 +1,9 @@
+xor
+               longread        1-byte          4096-block
+noncached      16.330          5.241           5.431
+   cached      184.446         8.824           326.961
+
+zeon
+               longread        1-byte          4096-block      1M-block
+noncached      39.754          5.838           15.535          24.955
+   cached      537.066         8.641           968.662         674.419
diff --git a/sfxstr.c b/sfxstr.c
new file mode 100644 (file)
index 0000000..e9dd00e
--- /dev/null
+++ b/sfxstr.c
@@ -0,0 +1,806 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *     may be used to endorse or promote products derived from this software
+ *     without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include "tlog.h"
+#include "tmalloc.h"
+#include "sfxstr.h"
+
+#define EN_VAL 0x01
+#define EN_CHLD        0x02
+#define EN_DATA        0x04
+
+static SFSNode* enlargeNode(SFSTree *info, SFSNode* node, u_int8_t val, int flag, SFSNodeData **nd);
+static SFSNode* addRecord(SFSTree *info, SFSNode* node, SFSDataIO *in, int level);
+
+#define STRNCMP(p1,p2,n) ( ((n)==1) ? ( *((char*)(p1))==*((char*)(p2)) ) : (strncmp((char*)(p1), (char*)(p2), (n))==0) )
+
+SFSTree* 
+SFSInit_dp(SFSTree *info, u_int32_t datasize, SFSDataIO *in) {
+       if ( datasize % sizeof(u_int32_t) )
+               tlog(TL_ALARM|TL_EXIT,"SFSInit_dp: datasize(%d) should be divided by sizeof(u_int32_t)", datasize);
+       if (!info) 
+               info=(SFSTree*)tmalloc(sizeof(SFSTree));
+       memset(info,0,sizeof(SFSTree));
+
+       info->datasize = datasize;
+
+       while(in && in->key) {
+               SFSAdd(info, in);
+               in++;
+       }
+
+       return info;    
+}
+
+SFSTree* 
+SFSInit_c(SFSTree *info, char **in) {
+       char **ptr=in;
+       SFSDataIO  d;
+
+       if (!info) 
+               info=(SFSTree*)tmalloc(sizeof(SFSTree));
+       memset(info,0,sizeof(SFSTree));
+
+       while(ptr && *ptr) {
+               d.key=*ptr;
+               d.keylen=0;
+               SFSAdd(info, &d);
+               ptr++;
+       }
+
+       return info;
+}
+
+void*
+SFSFindData(SFSTree *info, char *word) {
+       SFSNode *node = info->node;
+       SFSNodeData *StopLow, *StopHigh, *StopMiddle;
+       u_int8_t *ptr =(u_int8_t*)word;
+
+       while( node && *ptr ) {
+               if ( node->isskip ) {
+                       if ( STRNCMP(ptr, ((char*)node)+node->dataptr, node->nchar) ) {
+                               ptr+=node->nchar;
+                               if ( *ptr=='\0' && node->isword) {
+                                       return (void*) ( ((char*)(node->data)) + ((node->haschild) ? sizeof(SFSNode*) : 0) );
+                               } else if ( node->haschild ) {
+                                       node = *(SFSNode**)(node->data);
+                               } else {
+                                       return NULL;
+                               }
+                       } else
+                               return NULL;
+               } else {
+                       StopLow = node->data;
+                       StopHigh = StopLow + node->nchar;
+                       while (StopLow < StopHigh) {
+                              StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
+                              if ( StopMiddle->val == *ptr ) {
+                                      ptr++;
+                                      if ( *ptr=='\0' && StopMiddle->isword ) {
+                                               return (void*)( ((char*)node) + node->dataptr + info->datasize * StopMiddle->data );
+                                       } else if ( StopMiddle->haschild ) {
+                                               node=*(SFSNode**)( ((char*)StopMiddle) + StopMiddle->child );
+                                       } else {
+                                               return NULL;
+                                       }
+                                       break;
+                               } else if ( StopMiddle->val < *ptr ) {
+                                       StopLow = StopMiddle + 1;
+                               } else {
+                                       StopHigh = StopMiddle;
+                               }
+                       }
+                       if ( StopLow >= StopHigh )
+                               return NULL;
+               }
+       }
+       return NULL;
+}
+
+static void
+freeFSFNode(SFSTree *info, SFSNode *node, void (*freefunc)(void*)) {
+       u_int32_t i;
+       if ( node->isskip ) {
+               if (node->haschild)
+                       freeFSFNode(info, *(SFSNode**)(node->data), freefunc);
+               if (freefunc && node->isword && info->datasize)
+                       (*freefunc)( (void*)( ((char*)(node->data))+ (node->haschild) ? sizeof(SFSNode*) : 0 ) );
+       } else {
+               SFSNodeData *nd = node->data;
+               char *data= ((char*)node) + node->dataptr;
+       
+               for(i=0;i<node->nchar;i++) {
+                       if (nd->haschild)
+                               freeFSFNode(info, *(SFSNode**)( ((char*)nd) + nd->child ), freefunc);
+                       if (freefunc && nd->isword && info->datasize) {
+                               (*freefunc)( (void*)data );
+                               data+=info->datasize;
+                       }
+                       nd++;
+               }
+       }
+
+       tfree(node);
+}
+
+void 
+SFSFree(SFSTree *info, void (*freefunc)(void*)) {
+       SFSNodeStack *s=info->stack;
+
+       if (info->node) freeFSFNode(info, info->node, freefunc);
+       if (info->buf) tfree(info->buf);
+       info->buf = NULL;
+       info->tlen=0;
+       info->node = NULL;
+
+       while(s) {
+               info->stack=s->next;
+               tfree(s);
+               s=info->stack;
+       }
+}
+
+static SFSNode*
+makeSkipNode(SFSTree *info, SFSDataIO *io, int level) {
+       u_int32_t len;
+       int size;
+       SFSNode *res;
+
+       io->key+=level;
+       io->keylen-=level;
+
+       len = (io->keylen > 255) ? 255 : io->keylen;
+       size = SFSNHRDSZ + ((io->keylen > 255) ? sizeof(SFSNode*) : info->datasize) + len;
+
+       res = (SFSNode*)tmalloc(size);
+
+       info->nnodes++;
+       info->totalen+=size;
+
+       res->isskip=1;
+       res->nchar=len;
+       res->dataptr = SFSNHRDSZ + ((io->keylen > 255) ? sizeof(SFSNode*) : info->datasize);
+       memcpy(((char*)res) + res->dataptr, io->key, len);
+
+       if ( io->keylen > 255 ) {
+               res->haschild=1;
+               res->isword=0;
+               io->key = io->key+len;
+               io->keylen = io->keylen - len;
+               *(SFSNode**)(res->data) = makeSkipNode(info, io, 0);
+               io->key = io->key-len;
+               io->keylen = io->keylen + len;
+       } else {
+               res->haschild=0;
+               res->isword=1;
+               if (info->datasize) {
+                       memcpy( res->data, io->data, info->datasize );
+               }
+       }
+
+       io->key-=level;
+       io->keylen+=level;
+
+       return res;
+}
+
+static SFSNode*
+splitSkipNode(SFSTree *info, SFSNode* node, SFSDataIO *io, int level) {
+       SFSNode *res;
+       int prefixlen=0;
+       char *s1,*s2;
+       SFSNodeData     *ndata;
+
+       tassert(node->isskip);
+       io->key+=level;
+       io->keylen-=level;
+
+       s1=((char*)node) + node->dataptr;
+       s2=io->key;
+
+       while( s1 - (((char*)node) + node->dataptr) < node->nchar && s2 - io->key < io->keylen && *s1==*s2) {
+               s1++;
+               s2++;
+       }
+
+       prefixlen = s2 - io->key;
+
+       if ( prefixlen==0 ) {
+               if ( node->nchar == 1 ) {
+                       int flag = EN_VAL | ((node->isword) ? EN_DATA : 0) | ((node->haschild) ? EN_CHLD : 0);
+                       res = enlargeNode(info, NULL, *(u_int8_t*)(((char*)node) + node->dataptr), flag, &ndata);
+                       if ( node->isword ) {
+                               if ( info->datasize ) 
+                                       memcpy(
+                                               ((char*)res) + res->dataptr + info->datasize * ndata->data,
+                                               ((char*)(node->data)) + ((node->haschild) ? sizeof(SFSNode*) : 0),
+                                               info->datasize
+                                       );
+                       }
+                       if ( node->haschild ) 
+                               *(SFSNode**)( ((char*)ndata) + ndata->child ) = *(SFSNode**)( node->data );
+                       info->totalen -= SFSNHRDSZ + ((node->isword) ? info->datasize : 0) +
+                               ((node->haschild) ? sizeof(SFSNodeData*) : 0) + node->nchar;
+                       info->nnodes--;
+                       tfree(node);
+               } else {
+                       res = enlargeNode(info, NULL, *(u_int8_t*)(((char*)node) + node->dataptr), EN_VAL|EN_CHLD, &ndata);
+                       node->nchar--;
+                       memmove( ((char*)node) + node->dataptr, ((char*)node) + node->dataptr + 1, node->nchar);
+                       info->totalen--;
+                       *(SFSNode**)( ((char*)ndata) + ndata->child ) = (SFSNode*)trealloc(node,
+                               SFSNHRDSZ + ((node->haschild) ? sizeof(SFSNode*) : 0) + 
+                               ((node->isword) ? info->datasize : 0 )+ node->nchar);
+               }
+               res = addRecord(info, res, io, 0);
+       } else if (prefixlen==io->keylen) {
+               if (prefixlen==node->nchar) {
+                       if ( node->isword || info->datasize==0) {
+                               if (info->datasize)
+                                       memcpy( ((char*)(node->data)) + ((node->haschild) ? sizeof(SFSNodeData*) : 0),
+                                               io->data,
+                                               info->datasize);
+                               node->isword=1;
+                               res=node;
+                       } else {
+                               int size = SFSNHRDSZ + info->datasize + ((node->haschild) ? sizeof(SFSNodeData*) : 0) + node->nchar;
+
+                               info->totalen+=info->datasize;
+                               res=(SFSNode*)trealloc(node,size);
+                               res->dataptr=SFSNHRDSZ + info->datasize + ((res->haschild) ? sizeof(SFSNodeData*) : 0);
+                               res->isword=1;
+                               memmove(((char*)res) + res->dataptr,
+                                       ((char*)(res->data))  + ((res->haschild) ? sizeof(SFSNodeData*) : 0), res->nchar);
+                               memcpy(((char*)(res->data))  + ((res->haschild) ? sizeof(SFSNodeData*) : 0), io->data, info->datasize);
+                       }
+               } else {
+                       int size = SFSNHRDSZ + info->datasize + sizeof(SFSNodeData*) + prefixlen;
+                       info->totalen+=size;
+                       info->nnodes++;
+                       res = (SFSNode*)tmalloc(size);
+                       res->isskip=1;
+                       res->isword=1;
+                       res->haschild=1;
+                       res->nchar = prefixlen;
+                       res->dataptr = SFSNHRDSZ + info->datasize + sizeof(SFSNodeData*);
+                       memcpy(((char*)res)+res->dataptr, io->key, prefixlen);
+                       if (info->datasize)
+                               memcpy(((char*)(res->data)) + sizeof(SFSNodeData*), io->data, info->datasize);
+                       node->nchar-=prefixlen;
+                       memmove( ((char*)node) + node->dataptr, ((char*)node) + node->dataptr + prefixlen, node->nchar);
+                       info->totalen-=prefixlen;
+                       *(SFSNode**)(res->data) = (SFSNode*)trealloc(node, SFSNHRDSZ + ((node->isword) ? info->datasize : 0) +
+                               ((node->haschild) ? sizeof(SFSNodeData*) : 0) + node->nchar);
+               }
+       } else if ( prefixlen==node->nchar ) {
+               int size = SFSNHRDSZ + info->datasize +  sizeof(SFSNode*) + node->nchar;
+               info->totalen+=sizeof(SFSNode*);
+               res=(SFSNode*)trealloc(node,size);
+               memmove( ((char*)(res->data)) + sizeof(SFSNode*), res->data, info->datasize + res->nchar);
+               res->haschild=1;
+               res->dataptr+=sizeof(SFSNode*);
+               *(SFSNode**)(res->data) = makeSkipNode(info, io, prefixlen); 
+       } else { 
+               int size = SFSNHRDSZ + sizeof(SFSNodeData*) + prefixlen;
+               info->totalen+=size;
+               info->nnodes++;
+               res = (SFSNode*)tmalloc(size);
+               res->isskip=1;
+               res->isword=0;
+               res->haschild=1;
+               res->nchar = prefixlen;
+               res->dataptr = SFSNHRDSZ + sizeof(SFSNodeData*);
+               memcpy(((char*)res)+res->dataptr, io->key, prefixlen);
+
+               node->nchar-=prefixlen;
+               memmove( ((char*)node) + node->dataptr, ((char*)node) + node->dataptr + prefixlen, node->nchar);
+               info->totalen-=prefixlen;
+
+               *(SFSNode**)(res->data) = (SFSNode*)trealloc(node, 
+                       SFSNHRDSZ + ((node->isword) ? info->datasize : 0) +
+                               ((node->haschild) ? sizeof(SFSNodeData*) : 0) + node->nchar
+               );
+               *(SFSNode**)(res->data) = splitSkipNode(info, *(SFSNode**)(res->data), io, prefixlen); 
+
+       }
+
+       io->key-=level;
+       io->keylen+=level;
+       return res;
+}
+
+
+static SFSNode*
+enlargeNode(SFSTree *info, SFSNode* node, u_int8_t val, int flag, SFSNodeData **nd) {
+       u_int32_t nchild=0, nchar=0, nfound=0, i;
+       SFSNode *rs,**chld;
+       SFSNodeData *data;
+       int sizenode;
+       char *dataptr;
+
+
+       if ( node ) {
+               nchar=node->nchar;
+               nchild=node->nchild;
+               data=node->data;
+
+               for(i=0;i<nchar;i++) {
+                       nfound += data->isword;
+                       data++;
+               }
+       }
+
+       if ( node )
+               info->totalen -= SFSNHRDSZ+nchar*sizeof(SFSNodeData)+nchild*sizeof(SFSNode*)+nfound*info->datasize;
+
+       if ( flag & EN_VAL )   nchar++; 
+       if ( flag & EN_CHLD ) nchild++; 
+       if ( flag & EN_DATA )  nfound++;        
+
+
+       sizenode = SFSNHRDSZ+nchar*sizeof(SFSNodeData)+nchild*sizeof(SFSNode*)+nfound*info->datasize;
+
+       info->totalen+=sizenode;
+       if ( !node ) info->nnodes++;
+       rs=(SFSNode*)tmalloc(sizenode);
+
+       rs->isskip = 0;
+       rs->nchar = nchar;
+       rs->nchild = nchild;
+       rs->dataptr=SFSNHRDSZ+nchar*sizeof(SFSNodeData)+nchild*sizeof(SFSNode*);
+       dataptr=((char*)rs) + rs->dataptr;
+       chld = (SFSNode**)( ((char*)rs)+SFSNHRDSZ+nchar*sizeof(SFSNodeData) );
+       data=rs->data;
+
+       if (node) {
+               SFSNode **ochld=(SFSNode**)( ((char*)node)+SFSNHRDSZ+node->nchar*sizeof(SFSNodeData) );
+               SFSNodeData *odata = node->data;
+               char *odataptr=((char*)node) + node->dataptr;
+               int wasins=0;
+
+               for(i=0;i<node->nchar;i++) {
+                       if ( val > odata->val ) {
+                               *(u_int32_t*)data = *(u_int32_t*)odata;
+                               if ( odata->haschild ) {
+                                       *chld=*ochld;
+                                       data->child = ((char*)chld) - ((char*)data);
+                                       chld++; ochld++;
+                               }
+                               if ( odata->isword && info->datasize ) {
+                                       memcpy(dataptr, odataptr, info->datasize);
+                                       data->data = ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize;
+                                       dataptr += info->datasize; odataptr += info->datasize;
+                               }
+                               data++; odata++; 
+                       } else if ( val == odata->val ) {
+                               tassert ( (flag&EN_VAL)==0 );
+                               *(u_int32_t*)data = *(u_int32_t*)odata;
+                               wasins=1;
+                               if ( odata->haschild || flag & EN_CHLD ) {
+                                       if (odata->haschild) *chld=*ochld;
+                                       data->child = ((char*)chld) - ((char*)data);
+                                       data->haschild=1;
+                                       chld++; if (odata->haschild) ochld++;
+                               } else
+                                       data->haschild=0;
+                               if ( odata->isword || flag & EN_DATA ) {
+                                       data->isword=1;
+                                       if ( info->datasize && odata->isword ) {
+                                               memcpy(dataptr, odataptr, info->datasize);
+                                               odataptr += info->datasize;
+                                       }
+                                       data->data = ( info->datasize ) ? ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize : 0;
+                                       dataptr += info->datasize;
+                               } else
+                                       data->isword=0;
+                               *nd = data;
+                               data++; odata++; 
+                       } else {
+                               if ( wasins==0 ) {
+                                       tassert ( flag&EN_VAL );
+                                       data->val = val;
+                                       if ( flag & EN_CHLD ) {
+                                               data->haschild=1;
+                                               data->child = ((char*)chld) - ((char*)data);
+                                               chld++;
+                                       } else
+                                               data->haschild=0;
+                                       if ( flag & EN_DATA ) {
+                                                       data->isword=1;
+                                               data->data = ( info->datasize ) ? ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize : 0;
+                                               dataptr += info->datasize;
+                                       } else
+                                               data->isword=0;
+                                       *nd = data;
+                                       data++;
+                                       wasins=1;
+                                       i--;
+                               } else {
+                                       *(u_int32_t*)data = *(u_int32_t*)odata;
+                                       if ( odata->haschild ) {
+                                               *chld=*ochld;
+                                               data->child = ((char*)chld) - ((char*)data);
+                                               chld++; ochld++;
+                                       }
+                                       if ( odata->isword && info->datasize ) {
+                                               memcpy(dataptr, odataptr, info->datasize);
+                                               data->data = ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize;
+                                               dataptr += info->datasize; odataptr += info->datasize;
+                                       }
+                                       data++; odata++; 
+                               }
+                       } 
+               }
+               if ( wasins==0 ) {
+                       tassert ( flag&EN_VAL );
+                       data->val = val;
+                       if ( flag & EN_CHLD ) {
+                               data->haschild=1;
+                               data->child = ((char*)chld) - ((char*)data);
+                               chld++;
+                       } else
+                               data->haschild=0;
+                       if ( flag & EN_DATA ) {
+                                       data->isword=1;
+                               data->data = ( info->datasize ) ? ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize : 0;
+                               dataptr += info->datasize;
+                       } else 
+                               data->isword=0;
+                       *nd = data;
+               }
+       } else {
+               tassert ( flag & EN_VAL );
+               data->val = val;
+               if ( flag & EN_CHLD ) {
+                       data->haschild=1;
+                       data->child = ((char*)chld) - ((char*)data);
+               } else
+                       data->haschild=0;
+               if ( flag & EN_DATA ) {
+                       data->isword=1;
+                       data->data = ( info->datasize ) ? ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize : 0;
+               } else
+                       data->isword=0;
+               *nd = data;
+       }
+       if (node) tfree(node);
+       return rs;
+}
+
+static SFSNode*
+addRecord(SFSTree *info, SFSNode* node, SFSDataIO *in, int level) {
+       SFSNodeData *StopLow, *StopHigh, *StopMiddle;
+       u_int8_t *ptr = ((u_int8_t*)in->key) + level;
+
+
+       if ( node ) {
+               if ( node->isskip ) {
+                       if ( node->haschild && in->keylen-level > node->nchar && 
+                                       strncmp(in->key+level, ((char*)node)+node->dataptr, node->nchar)==0 ) 
+                               *(SFSNode**)( node->data ) = addRecord(info, *(SFSNode**)( node->data ), in, level+node->nchar); 
+                       else 
+                               node = splitSkipNode(info, node, in, level); 
+               } else {
+                       StopLow = node->data;   
+                       StopHigh = StopLow + node->nchar;
+                       while (StopLow < StopHigh) {
+                               StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
+                               if ( StopMiddle->val == *ptr ) {
+                                       if ( *(ptr+1)=='\0' ) {
+                                               if ( StopMiddle->isword ) {
+                                                       /* already exists */
+                                                       if ( info->datasize ) 
+                                                               memcpy(((char*)node) + node->dataptr + info->datasize * StopMiddle->data,
+                                                                       in->data, info->datasize );
+                                               } else {
+                                                       /* not exist word */
+                                                       if (info->datasize) {
+                                                               node = enlargeNode(info, node, *ptr, EN_DATA, &StopMiddle);
+                                                               memcpy(((char*)node) + node->dataptr + info->datasize * StopMiddle->data,
+                                                                       in->data, info->datasize );
+                                                       }
+                                                       StopMiddle->isword = 1;
+                                               }
+                                       } else if ( StopMiddle->haschild ) {
+                                               *(SFSNode**)( ((char*)StopMiddle) + StopMiddle->child ) = 
+                                                       addRecord(info, *(SFSNode**)( ((char*)StopMiddle) + StopMiddle->child ), in, level+1);
+                                       } else {
+                                               node = enlargeNode(info, node, *ptr, EN_CHLD, &StopMiddle);
+                                               *(SFSNode**)( ((char*)StopMiddle) + StopMiddle->child ) =
+                                                       makeSkipNode(info, in, level+1);
+                                       }
+                                       return node;
+                               } else if ( StopMiddle->val < *ptr ) {
+                                       StopLow = StopMiddle + 1;
+                               } else {
+                                       StopHigh = StopMiddle;
+                               }
+                       }
+                       if ( *(ptr+1)=='\0' ) {
+                               node = enlargeNode(info, node, *ptr, EN_VAL|EN_DATA, &StopMiddle);
+                               if ( info->datasize )
+                                       memcpy(((char*)node) + node->dataptr + info->datasize * StopMiddle->data,
+                                       in->data, info->datasize );
+                       } else {
+                               node = enlargeNode(info, node, *ptr, EN_VAL|EN_CHLD, &StopMiddle);
+                               *(SFSNode**)( ((char*)StopMiddle) + StopMiddle->child ) = 
+                                       makeSkipNode(info, in, level+1);
+                       }
+               }
+       } else 
+               node = makeSkipNode(info, in, level); 
+
+
+       return node;
+
+}
+
+void
+SFSAdd(SFSTree *info, SFSDataIO *in) {
+       if (in->keylen<=0)
+               in->keylen=strlen(in->key);
+       info->node = addRecord(info, info->node, in, 0);
+}
+
+static SFSNodeStack*
+pushStack(SFSNodeStack *top, SFSNode *node, int level ) {
+       SFSNodeStack *r=(SFSNodeStack*)tmalloc(sizeof(SFSNodeStack));
+
+       r->next = top;
+       r->node=node;
+       r->data=node->data;
+       r->level=level;
+       r->checkedchild = 0;
+       r->checkedval = 0;
+
+       return r;
+}
+
+void 
+SFSIteratorStart(SFSTree *info) {
+       if ( !info->buf ) {
+               info->tlen = 32;
+               info->buf = (char*)tmalloc(info->tlen);
+       } 
+       info->stack = pushStack(NULL, info->node, 0);
+       info->hasword=0; 
+}
+
+void
+SFSPrefixIteratorStart(SFSTree *info, char *word) {
+       SFSNode *node = info->node;
+       SFSNodeData *StopLow, *StopHigh, *StopMiddle;
+       u_int8_t *ptr =(u_int8_t*)word;
+       int len,wlen=strlen(word);
+
+       if ( wlen+1>=info->tlen ) {
+               info->tlen = 2*wlen;
+               info->buf = (info->buf) ?
+                               (char*)trealloc(info->buf,info->tlen)
+                       :
+                               (char*)tmalloc(info->tlen);
+       }
+
+       info->hasword=0;
+       while( node && *ptr) {
+               len = wlen - (((char*)ptr)-word);
+               if ( node->isskip ) {
+                       if ( STRNCMP(ptr, ((char*)node)+node->dataptr, (len<node->nchar) ? len : node->nchar) ) {
+                               if ( len<=node->nchar ) {
+                                       strcpy(info->buf,word);
+                                       info->stack = pushStack(NULL, node, ((char*)ptr) - word);
+                                       return;
+                               } else if ( node->haschild ) {
+                                       ptr+=node->nchar;
+                                       node = *(SFSNode**)(node->data);
+                               } else {
+                                       return;
+                               }
+                       } else
+                               return;
+               } else {
+                       StopLow = node->data;
+                       StopHigh = StopLow + node->nchar;
+                       while (StopLow < StopHigh) {
+                               StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
+                               if ( StopMiddle->val == *ptr ) {
+                                       if ( *(ptr+1)=='\0' ) {
+                                               len =((char*)ptr)-word+1;
+                                               strcpy(info->buf,word);
+                                               if ( StopMiddle->isword ) {
+                                                       info->hasword=1;
+                                                       info->wdata = (void*)( ((char*)node) + node->dataptr + info->datasize * StopMiddle->data );
+                                               }
+                                               if ( StopMiddle->haschild )
+                                                       info->stack = pushStack(NULL, *(SFSNode**)( ((char*)StopMiddle) + StopMiddle->child ), len);
+                                               return;
+                                       } else if ( StopMiddle->haschild ) {
+                                               node=*(SFSNode**)( ((char*)StopMiddle) + StopMiddle->child );
+                                       } else {
+                                               return;
+                                       }
+                                       ptr++;
+                                       break;
+                               } else if ( StopMiddle->val < *ptr ) {
+                                       StopLow = StopMiddle + 1;
+                               } else {
+                                       StopHigh = StopMiddle;
+                               }
+                       }
+                       if ( StopLow >= StopHigh )
+                               break;
+               }
+       }
+       return;
+}
+
+int
+SFSIterate(SFSTree *info, SFSDataIO *out) {
+       SFSNodeStack *s=info->stack;
+
+       if ( info->hasword ) {
+               out->key = info->buf;
+               out->keylen = strlen(out->key);
+               out->data = info->wdata;
+               info->hasword = 0;
+               return 1;
+       }
+
+       if ( s == NULL || s->node == NULL)
+               return 0;
+                                                        
+       while ( s->level + s->node->nchar + 1 >= info->tlen ) {
+               info->tlen *= 2;
+               info->buf = (char*)trealloc(info->buf, info->tlen);
+       }
+
+       if ( s->node->isskip ) {
+               memcpy( info->buf + s->level, ((char*)s->node) + s->node->dataptr, s->node->nchar );
+               if ( s->node->isword && !s->checkedval) {
+                       info->buf[ s->level+s->node->nchar ] = '\0';
+                       out->key = info->buf;
+                       out->keylen = s->level+s->node->nchar;
+                       out->data =((char*)(s->node->data)) + ((s->node->haschild) ? sizeof(SFSNode*) : 0);
+                       s->checkedval=1;
+                       return 1;
+               }
+               if ( s->node->haschild && !s->checkedchild) {
+                       info->stack = pushStack(s, *(SFSNode**)( (char*)(s->node->data) ), s->level+s->node->nchar);
+                       s->checkedchild=1;
+                       if ( SFSIterate(info, out) )
+                               return 1;
+               }
+       } else {
+               while( s->data - s->node->data < s->node->nchar ) {
+                       info->buf[ s->level ] = (char)s->data->val;
+                       if ( s->checkedval==0 && s->data->isword ) {
+                               info->buf[ s->level+1 ] = '\0';  
+                               out->key = info->buf;
+                               out->keylen = s->level+1;
+                               out->data =((char*)s->node) + s->node->dataptr + info->datasize * s->data->data;
+                               s->checkedval = 1;
+                               return 1;
+                       }
+                       if ( s->checkedchild==0 && s->data->haschild ) {
+                               info->stack = pushStack(s, *(SFSNode**)( ((char*)s->data) + s->data->child ), s->level+1);
+                               s->checkedchild=1;
+                               if ( SFSIterate(info, out) )
+                                       return 1;
+                       }
+                       s->checkedval = s->checkedchild = 0;
+                       s->data++;
+               }
+       }
+       info->stack = s->next;
+       tfree(s);
+
+       return SFSIterate(info, out);
+}
+
+int
+SFSRange(SFSTree *info, char *word, SFSDataIO *f, SFSDataIO *l) {
+       SFSNodeStack *s=info->stack;
+
+       SFSPrefixIteratorStart(info, word);
+       s=info->stack;
+
+       if ( SFSIterate(info, f) ) {
+               SFSNodeStack *sptr = info->stack, *stmp;
+               while( sptr && sptr!=s ) {
+                       stmp=sptr->next;
+                       tfree(sptr);
+                       sptr=stmp;
+               }
+        
+               if ( s == NULL ) {
+                       memcpy(l,f,sizeof(SFSDataIO));
+                       return 1;
+               }
+       } else
+               return 0;
+                                                        
+       info->stack=NULL;
+
+       while( f->keylen +  s->level + 2 >= info->tlen ) {
+               info->tlen *= 2;
+               info->buf = (char*)trealloc(info->buf, info->tlen);
+       }
+
+       f->key = info->buf;
+       l->key = info->buf + f->keylen + 1;
+       memcpy(l->key, f->key, f->keylen + 1);
+                       
+       while(s->node) {
+               while( f->keylen + 1 + s->level + s->node->nchar + 1 >= info->tlen ) {
+                       info->tlen *= 2;
+                       info->buf = (char*)trealloc(info->buf, info->tlen);
+               }
+               if ( s->node->isskip ) {
+                       memcpy(info->buf + f->keylen + 1 + s->level,
+                               ((char*)(s->node))+s->node->dataptr, s->node->nchar);
+                       s->level+=s->node->nchar;
+                       if (s->node->haschild) {
+                               s->node=*(SFSNode**)( s->node->data );  
+                       } else { /* if (s->node->isword) */
+                               info->buf[ f->keylen + 1 + s->level + 1 ] = '\0';
+                               l->data = (void*)(s->node->data);
+                               l->keylen = s->level+1;
+                               break;
+                       }
+               } else {
+                       s->data = s->node->data + s->node->nchar - 1;
+                       while( s->data - s->node->data >= 0 ) {
+                               info->buf[ f->keylen + 1 + s->level ] = (char)s->data->val;
+                               if ( s->data->haschild ) {
+                                       s->node = *(SFSNode**)( ((char*)s->data) + s->data->child );
+                                       s->level++;
+                                       break;
+                               }
+                               if ( s->data->isword ) {
+                                       info->buf[ f->keylen + 1 + s->level+1 ] = '\0';
+                                       l->keylen = s->level+1;
+                                       l->data =((char*)s->node) + s->node->dataptr + info->datasize * s->data->data;
+                                       s->node=NULL;
+                                       break;
+                               }
+                               s->data--;
+                       }
+               }
+       }               
+       f->key = info->buf;
+       l->key = info->buf + f->keylen + 1;
+       tfree(s); 
+
+       return 1;
+}
diff --git a/sfxstr.h b/sfxstr.h
new file mode 100644 (file)
index 0000000..5f1be7b
--- /dev/null
+++ b/sfxstr.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SFXSTR_H__
+#define __SFXSTR_H__
+
+#include <sys/types.h>
+
+/* 
+ * ëÁÖÄÙÊ ÕÚÅÌ ÄÅÒÅ×Á ÍÏÖÅÔ ÂÙÔÔØ ÏÂÎÉÍ ÉÚ Ä×ÕÈ ÔÉÐÏ×:
+ * SFSNode->isskip = 1  - ÕÚÅÌ "ÐÕÔÅ×ÏÊ ËÏÍÐÒÅÓÉÉ". 
+ *    ôÁËÏÊ ÕÚÅÌ ÍÏÖÅÔ ÉÍÅÔØ ÏÄÎÏÇÏ ÒÅÂÅÎËÁ É/ÉÌÉ
+ *    ÏÄÎÏ ÓÌÏ×Ï.
+ * SFSNode->isskip = 0  - "×ÅÔ×ÑÝÉÊÓÑ ÕÚÅÌ"
+ *
+ * "×ÅÔ×ÑÝÉÊÓÑ" ÕÚÅÌ ÄÅÒÅ×Á ÈÒÁÎÉÔØÓÑ × ÐÁÍÑÔÉ ÓÌÅÄÕÀÝÉÍ ÏÂÒÁÚÏÍ:
+ *  ( SFSNHRDSZ ÂÁÊÔÁ ) SFSNode - ÚÁÇÏÌÏ×ÏË ÕÚÌÁ
+ *  ( sizeof(SFSNodeData)*SFSNode->nchar ÂÁÊÔÁ) SFSNodeData[] - ÍÁÓÓÉ× "ÓÉÍ×ÏÌÏ×"
+ *  ( sizeof(SFSNode*)*SFSNode->nchild ÂÁÊÔÁ ) *SFSNode[] - ÍÁÓÓÉ× ÓÓÙÌÏË ÎÁ ÄÏÞÅÒÎÉÅ ÕÚÌÙ
+ *  ( SFSTree->datasize * (ËÏÌÉÞÅÓÔ×Ï ÓÌÏ×, ÚÁËÁÎÞÉ×ÁÀÝÉÈÓÑ × ÜÔÏÍ ÕÚÌÅ) ) - 
+ *         ÍÁÓÓÉ× ÚÎÁÞÅÎÉÊ
+ *
+ *  ÍÁÓÓÉ× "ÓÉÍ×ÏÌÏ×" - ÕÐÏÒÑÄÏÞÅΠÐÏ ÓÉÍ×ÏÌÁÍ (SFSNodeData->val),
+ *  ÐÏÒÑÄÏË ÏÓÔÁÌØÎÙÈ ÍÁÓÓÉ×Ï× ÚÁÄÁÅÔÓÑ ÍÁÓÓÉ×ÏÍ "ÓÉÍ×ÏÌÏ×"
+ *  ÕÚÅÌ "ÐÕÔÅ×ÏÊ ËÏÍÐÒÅÓÉÉ" ÈÒÁÎÉÔØÓÑ × ÐÁÍÑÔÉ ÓÌÅÄÕÀÝÉÍ ÏÂÒÁÚÏÍ:
+ *  ( SFSNHRDSZ ÂÁÊÔÁ ) SFSNode - ÚÁÇÏÌÏ×ÏË ÕÚÌÁ
+ *  sizeof(SFSNode*) ÂÁÊÔ - ÓÓÙÌËÁ ÎÁ ÒÅÂÅÎËÁ (ÎÅÏÂÑÚÁÔÅÌØÎÏÅ ÐÏÌÅ)
+ *  SFSTree->datasize ÂÁÊÔ - ÚÎÁÞÅÎÉÅ, ÅÓÌÉ ÚÄÅÓØ ÚÁËÁÎÞÉ×ÁÅÔÓÑ ËÌÀÞ 
+ *                        (ÎÅÏÂÑÚÁÔÅÌØÎÏÅ ÐÏÌÅ)
+ *  SFSTree->nchar ÂÁÊÔ - "ÓËÏÍÐÒÅÓÓÉÒÏ×ÁÎÎÁÑ" ÞÁÓÔØ ÐÕÔÉ. 
+ */ 
+
+/* ÓÔÒÕËÔÕÒÁ, ÏÐÉÓÙ×ÁÀÝÁÑ "ÓÉÍ×ÏÌ" */
+typedef struct {
+        u_int32_t
+                /* ÓÍÅÝÅÎÉÅ ÏÔ ÔÅËÕÝÅÇÏ "ÓÉÍ×ÏÌÁ" ÄÏ ÓÓÙÌËÉ ÎÁ ÄÏÞÅÒÎÉÊ ÕÚÅÌ  × ÂÁÊÔÁÈ */
+                child:10,  
+                unused:4,
+
+               /* × ÌÀÂÏÍ "ÓÉÍ×ÏÌÏ×" isword + haschild > 0 */
+               /* ÚÁËÁÎÞÉ×ÁÅÔÓÑ ÌÉ ÚÄÅÓØ ÓÌÏ×Ï */ 
+                isword:1,  
+               /* ÅÓÔØ ÌÉ ÄÏÞÅÒÎÉÊ ÕÚÅÌ */
+               haschild:1,
+
+               /* ÓÍÅÝÅÎÉÅ ÏÔ SFSNode->dataptr ÄÏ ÚÎÁÞÅÎÉÑ × ÅÄÉÎÉÃÁÈ SFSTree->datasize */ 
+                data:8, 
+               /* óÏÂÓÔ×ÅÎÎÏ ÓÉÍ×ÏÌ */
+                val:8; 
+} SFSNodeData;
+
+/* úÁÇÏÌÏ×ÏË ÕÚÌÁ ÄÅÒÅ×Á */
+typedef struct SFSNode {
+        u_int32_t
+               /* ÔÉРÕÚÌÁ */ 
+               isskip:1,
+               /* ÚÁËÁÎÞÉ×ÁÅÔÓÑ ÌÉ ËÌÀÞ × ÜÔÏÍ ÕÚÌÅ (ÔÏÌØËÏ ÄÌÑ ÕÚÌÁ "ÐÕÔÅ×ÏÊ ËÏÍÐÒÅÓÉÉ,
+                   ÄÌÑ "×ÅÔ×ÑÝÅÇÏÓÑ" - ÎÅÉÓÐÏÌØÚÕÅÔÓÑ) */
+               isword:1,
+
+               /* ÅÓÔØ ÌÉ ÒÅÂÅÎÏË ÜÔÏÇÏ ÕÚÌÁ (ÔÏÌØËÏ ÄÌÑ ÕÚÌÁ "ÐÕÔÅ×ÏÊ ËÏÍÐÒÅÓÉÉ,
+                   ÄÌÑ "×ÅÔ×ÑÝÅÇÏÓÑ" - ÎÅÉÓÐÏÌØÚÕÅÔÓÑ) */
+               haschild:1, 
+               unused:1,
+               /* "ÐÕÔÅ×ÏÊ": ÓÍÅÝÅÎÉÅ × ÂÁÊÔÁÈ ÏÔ ÎÁÞÁÌÁ ÕÚÌÁ ÄÏ ÎÁÞÁÌÁ "ÓËÏÍÐÒÅÓÓÉÒÏ×ÁÎÎÏÊ" ÞÁÓÔÉ ÐÕÔÉ */ 
+               /* "×ÅÔ×ÑÝÉÊÓÑ": ÓÍÅÝÅÎÉÅ × ÂÁÊÔÁÈ ÏÔ ÎÁÞÁÌÁ ÕÚÌÁ ÄÏ ÎÁÞÁÌÁ ÍÁÓÓÉ×Á ÚÎÁÞÅÎÉÊ */ 
+               dataptr:12,
+
+               /* "ÐÕÔÅ×ÏÊ": ÎÅÉÓÐÏÌØÚÕÅÔÓÑ */ 
+               /* "×ÅÔ×ÑÝÉÊÓÑ": ËÏÌ-×Ï ÄÏÞÅÒÎÉÈ ÕÚÌÏ× */ 
+               nchild:8,
+
+               /* "ÐÕÔÅ×ÏÊ": ËÏÌ-×Ï "ÓËÏÍÐÒÅÓÓÏ×ÁÎÎÙÈ" ÕÚÌÏ× */
+               /* "×ÅÔ×ÑÝÉÊÓÑ": ËÏÌ-×Ï "ÓÉÍ×ÏÌÏ×" */
+               nchar:8;
+        SFSNodeData      data[1];
+} SFSNode;
+
+#define SFSNHRDSZ        (sizeof(u_int32_t))
+
+
+/* ÓÔÒÕËÔÕÒÁ ÄÌÑ ÏÂÈÏÄÁ ÄÅÒÅ×Á ÉÔÅÒÁÔÏÒÏÍ */
+typedef struct SFSNodeStack {
+       /* ÕËÁÚÁÔÅÌØ ÎÁ ÕÚÅÌ */
+       SFSNode *node;  
+       /* ÕËÁÚÁÔÅÌØ ÎÁ "ÓÉÍ×ÏÌ" ÕÚÌÁ */ 
+       SFSNodeData *data;
+       u_int32_t 
+               /* ÆÌÁÇ ÐÒÏ×ÅÒËÉ ËÌÀÞÁ */ 
+               checkedval:1,
+               /* ÆÌÁÇ ÐÒÏ×ÅÒËÉ  ÄÏÞÅÒÎÅÇÏ ÕÚÌÁ */ 
+               checkedchild:1,
+               /* "ÇÌÕÂÉÎÁ" ÕÚÌÁ */
+               level:30;
+       struct SFSNodeStack *next;
+} SFSNodeStack;
+
+typedef struct {
+       /* óÔÁÔÉÓÔÉÞÅÓËÉÅ ÄÁÎÎÙÅ */
+       u_int32_t       totalen; /* ÏÂÝÅÅ ËÏÌ-×Ï ÍÁÌÌÏÃÉÒÏ×ÁÎÎÏÊ ÐÁÍÑÔÉ */
+       u_int32_t       nnodes;  /* ÏÂÝÅÅ ËÏÌ-×Ï ÕÚÌÏ× ÄÅÒÅ×Á */
+
+       u_int32_t       datasize; /* ÒÁÚÍÅÒ ÚÎÁÞÅÎÉÑ (ËÒÁÔÅΠsizeof(u_int32_t))*/
+        SFSNode        *node;    /* ËÏÒÎÅ×ÏÊ ÕÚÅÌ ÄÅÒÅ×Á */
+
+       /* iterator */
+       SFSNodeStack    *stack;  /* ÓÔÅË ÏÂÈÏÄÁ ÄÅÒÅ×Á */ 
+       char            *buf;    /* ÂÕÆÅÒ ËÌÀÞÁ */
+       int             tlen;    /* ÅÇÏ ÄÌÉÎÁ */
+
+       /* addon for prefix iterator */
+       int             hasword; /* ÅÓÔØ ÌÉ ËÌÀÞ, ÒÁ×ÎÏÅ ÐÒÅÆÉËÓÕ (ÓÌÕÖÅÂÎÏÅ ÐÏÌÅ) */
+       void            *wdata;  /* ÕËÁÚÁÔÅÌØ ÎÁ ÚÎÁÞÅÎÉÅ ËÌÀÞÁ, ÒÁ×ÎÏÇÏ ÐÒÅÆÉËÓÕ (ÓÌÕÖÅÂÎÏÅ ÐÏÌÅ) */ 
+}       SFSTree;
+
+/* ÓÔÒÕËÔÕÒÁ ××ÏÄÁ - ×Ù×ÏÄÁ ÚÁÐÉÓÅÊ */
+typedef struct {
+       /* ËÌÀÞ, ÄÏÌÖÅΠÚÁËÁÎÞÔÉ×ÁÔØÓÑ ÓÉÍ×ÏÌÏÍ '\0' */ 
+        char   *key;
+        /* ÄÌÉÎÁ ËÌÀÞÁ. ïÐÃÉÏÎÁÌØÎÏÅ ÐÏÌÅ, ÎÅ ÉÓÐÏÌØÚÕÅÔÓÑ × ÐÒÏÃÅÓÓÅ ×ÎÅÓÅÎÉÑ 
+           ÎÏ×ÏÇÏ ËÌÀÞÁ, ÎÏ ÐÒÉ ×Ù×ÏÄÅ ×ÓÅÇÄÁ ÓÏÄÅÒÖÉÔ ÄÌÉÎÕ ËÌÀÞÁ */ 
+        int    keylen;
+       /* ÕËÁÚÁÔÅÌØ ÎÁ ÚÎÁÞÅÎÉÅ */
+        void   *data;
+} SFSDataIO;
+
+/*
+ *  ëÏÒÒÅËÔÎÏÓÔØ ÆÕÎËÃÉÏÎÉÒÏ×ÁÎÉÑ ËÏÎÔÒÏÌÉÒÕÅÔÓÑ assert'ÏÍ,
+ *  × ÔÏÍ ÞÉÓÌÅ É ËÏÎÔÒÏÌØ ÚÁ malloc/realloc
+ *  ÷ÓÅ Æ-ÃÉÉ ÒÁÓÓÞÉÔÁÎÙ ÎÁ ËÌÀÞÉ, ÚÁËÁÎÞÉ×ÁÀÝÉÍÉÓÑ ÓÉÍ×ÏÌÏÍ '\0'
+ */
+
+/* 
+ * Æ-ÃÉÉ ÉÎÉÃÉÁÌÉÚÁÃÉÉ, datasize - ÒÁÚÍÅÒ × ÂÁÊÔÁÈ
+ * ÚÎÁÞÅÎÉÑ, ÐÒÉ×ÑÚÁÎÎÏÊ Ë ËÌÀÞÁÍ.
+ * SFSInit_c ÐÒÅÄÐÏÌÁÇÁÅÔ, ÞÔÏ ÚÎÁÞÅÎÉÑ ÏÔÓÕÔÓÔ×ÕÀÔ.
+ * òÁÚÍÅÒ ÓÔÒÕËÔÕÒÙ ÄÏÌÖÅΠÂÙÔØ ÒÁ×ÅΠËÒÁÔÅΠsizeof(u_int32_t)
+ */
+SFSTree* SFSInit_dp(SFSTree *info, u_int32_t datasize, SFSDataIO *in);
+SFSTree* SFSInit_c(SFSTree *info, char **in);
+
+/*
+ * ïÓ×ÏÂÏÖÄÅÎÉÅ ÐÁÍÑÔÉ, ÚÁÎÑÔÏÊ ÄÅÒÅ×ÏÍ.
+ * åÓÌÉ ÕËÁÚÁÎÁ freefunc, ÔÏ ÏÎÁ ×ÙÚÙ×ÁÅÔÓÑ ÄÌÑ
+ * ËÁÖÄÏÇÏ ÚÎÁÞÅÎÉÑ , ÐÒÉ×ÑÚÁÎÎÏÇÏ Ë ËÌÀÞÁÍ
+ */ 
+void SFSFree(SFSTree *info, void (*freefunc)(void*));
+
+/* 
+ * äÏÂÁ×ÌÅÎÉÅ ÐÁÒÙ ËÌÀÞ-ÚÎÁÞÅÎÉÅ 
+ */
+void SFSAdd(SFSTree *info, SFSDataIO *in);
+
+/*
+ * ðÏÉÓË ÚÎÁÞÅÎÉÑ ÐÏ ËÌÀÞÕ, × ÓÌÕÞÁÅ ÕÓÐÅÈÁ ×ÏÚ×ÒÁÝÁÅÔ 
+ * ÕËÁÚÁÔÅÌØ ÎÁ ÚÎÁÞÅÎÉÅ, ÉÎÁÞÅ - NULL
+ */
+void* SFSFindData(SFSTree *info, char *word);
+
+/*
+ * éÎÉÃÉÁÌÉÚÁÃÉÑ ÉÔÅÒÁÔÏÒÁ × ÎÁÞÁÌÏ ÄÅÒÅ×Á 
+ */
+void SFSIteratorStart(SFSTree *info);
+
+/*
+ * éÎÉÃÉÁÌÉÚÁÃÉÑ ÉÔÅÒÁÔÏÒÁ Ë ËÌÀÞÕ, ÂÏÌØÛÅ ÉÌÉ ÒÁ×ÎÏÍÕ
+ * word 
+ */
+void SFSPrefixIteratorStart(SFSTree *info, char *word);
+
+/* 
+ * ïÂÈÏÄ ÉÔÅÒÁÔÏÒÁ, × ÓÌÕÞÁÅ ÕÓÐÅÈÁ ×ÏÚ×ÒÁÝÁÅÔ 1 É ÚÁÐÏÌÎÅÎÎÕÀ
+ * ÓÔÒÕËÔÕÒÕ SFSDataIO *out, ÉÎÁÞÅ 0 É ÎÅÐÒÅÄÓËÁÚÕÅÍÏ ÚÁÐÏÌÎÅÎÎÕÀ
+ * ÓÔÒÕËÔÕÒÕ SFSDataIO *out. ÷ ÓÔÒÕËÔÕÒÅ out ÐÏÌÑ key É data
+ * îå ÄÏÌÖÎÙ ÉÚÍÅÎÑÔØÓÑ ÉÌÉ ÏÓ×ÏÂÏÖÄÁÔØÓÑ ÐÁÍÑÔØ.
+ * æ-ÃÉÑ ÐÒÅËÒÁÝÁÅÔ ÏÂÈÏÄ:
+ *  1) ÉÎÉÃÉÁÌÉÚÁÃÉÑ SFSIteratorStart: ×ÙÂÒÁÎÙ ×ÓÅ ËÌÀÞÉ
+ *  2) -/- SFSPrefixIteratorStart: ×ÙÂÒÁÎÙ ×ÓÅ ËÌÀÞÉ Ó ÚÁÄÁÎÎÙÍ ÐÒÅÆÉËÓÏÍ.
+ * ëÌÀÞÉ ×ÙÄÁÀÔÓÑ × ÌÅËÓÉËÏÇÒÁÆÉÞÅÓËÏÍ ÐÏÒÑÄËÅ, ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÍ
+ * ASCI ËÏÄÉÒÏ×ËÅ. 
+ */ 
+int SFSIterate(SFSTree *info, SFSDataIO *out);
+
+/* 
+ * ðÏÉÓË ÍÉÎÉÍÁÌØÎÏÇÏ É ÍÁËÓÉÍÁÌØÎÏÇÏ ËÌÀÞÅÊ, ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÈ
+ * ÐÒÅÆÉËÓÕ word. ÷ ÓÌÕÞÁÅ ÕÓÐÅÈÁ ×ÏÚ×ÒÁÝÁÅÔ 1 É ÚÁÐÏÌÎÅÎÎÙÅ ÓÔÒÕËÔÕÒÙ f É l,
+ * byfxt - 0 É "ÍÕÓÏÒ" × f É l. ÷ ÓÔÒÕËÔÕÒÁÈ f É l ÐÏÌÑ key É data
+ * îå ÄÏÌÖÎÙ ÉÚÍÅÎÑÔØÓÑ ÉÌÉ ÏÓ×ÏÂÏÖÄÁÔØÓÑ ÐÁÍÑÔØ.
+ */
+int SFSRange(SFSTree *info, char *word, SFSDataIO *f, SFSDataIO *l); 
+
+#endif
+
diff --git a/sfxtest.c b/sfxtest.c
new file mode 100644 (file)
index 0000000..f98140d
--- /dev/null
+++ b/sfxtest.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *     may be used to endorse or promote products derived from this software
+ *     without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "tools.h"
+#include "tlog.h"
+#include "tmalloc.h"
+#include "sfxstr.h"
+
+extern char *optarg;
+static int verbose=1;
+
+static int
+STRINGCMP(const void *a, const void *b) {
+       return strcmp( *(char**)a, *(char**)b );
+}
+
+static void
+usage() {
+       puts("Usage:");
+       puts("./sfxtest -d datafile [-b| [-a addondatafile] [-l | -p | -r | -g] [-n]] [-q]");
+       puts("Detailed description:");
+
+       puts("  Binary search");
+       puts("    ./sfxtest -b -d datafile [-q]");
+       puts("       -q - quiet (no output)");
+
+       puts("  Optimal suffix search");
+       puts("    ./sfxtest -d datafile [-a addondatafile] [-l | -p | -r | -g]  [-n] [-q]");
+       puts("       -a addondatafile - addon file data for loading");
+       puts("       -g - histogramm mode");
+       puts("       -l - listing mode");
+       puts("       -p - prefix search mode");
+       puts("       -r - range search mode");
+       puts("       -n - enumerate entries");
+       puts("       -q - quiet (no output)");
+       
+       exit(1);
+}
+
+static void
+gistogramm(SFSNode *node, int *gist) {
+       if ( !node )
+               return;
+
+      if ( node->isskip ) {
+              if ( node->haschild ) {
+                      gist[1]++;
+                      gistogramm( *(SFSNode**)(node->data), gist );
+              } else
+                     gist[0]++;
+       } else {
+              SFSNodeData *data;
+
+              gist[ node->nchild ]++;
+
+              data=node->data;
+              while(data - node->data < node->nchar) {
+                      if ( data->haschild )
+                              gistogramm( *(SFSNode**)( ((char*)data) + data->child ), gist);
+                      data++;
+              }
+       }
+}
+
+int
+main(int argn, char *argv[]) {
+       struct timeval begin,end;
+       char *datafile=NULL;
+       int i, binary=0;
+       FILE *in;
+       char buf[4096];
+       double sumtime=0.0;
+       int structsize=0, list=0, prefix=0, range=0, enumerate=0,gmode=0;
+       char *addondatafile=NULL;
+
+       int len=4096, curlen=0, checked=0, success=0;
+       char **data;
+       void *res;
+       
+       while ((i = getopt(argn, argv, "pd:bqha:lrng")) != EOF) {
+               switch(i) {
+                       case 'a':
+                               addondatafile=optarg;
+                               break;
+                       case 'd':
+                               datafile=optarg;
+                               break;
+                       case 'n':
+                               enumerate=1;
+                               break;
+                       case 'g':
+                               gmode=1;
+                               break;
+                       case 'r':
+                               range=1;
+                               break;
+                       case 'p':
+                               prefix=1;
+                               break;
+                       case 'l':
+                               list=1;
+                               break;
+                       case 'b':
+                               binary=1;
+                               break;
+                       case 'q':
+                               verbose=0;
+                               break;
+                       case 'h':
+                       default: 
+                               usage();
+               }
+       }
+
+       if (!datafile) usage();
+
+       opentlog(TL_OPEN_STDERR|TL_OPEN_SYSLOG|TL_OPEN_FILE, TL_INFO, "./sfxtest.log");
+       if ( (in=fopen(datafile,"r"))==NULL ) 
+               tlog(TL_CRIT|TL_EXIT,"Beda with %s", datafile);
+
+       data=(char**)tmalloc(len*sizeof(char*));
+       while(fgets(buf,4096,in)) {
+               structsize+=clrspace(buf)+1;
+               if ( !*buf ) continue;
+               if (curlen+2 > len) {
+                       len*=2;
+                       data=(char**)trealloc(data, len*sizeof(char*));
+               }
+               data[curlen]=tstrdup(buf);
+               curlen++;
+       }
+       fclose(in);
+       data[curlen]=NULL;
+       structsize+=sizeof(char*)*curlen;
+
+       if ( binary == 1 ) {
+               gettimeofday( &begin, NULL );
+               qsort(data, curlen, sizeof(char**), STRINGCMP);
+               tlog(TL_INFO,"Init time: %.03f secs",  elapsedtime(&begin) );
+               tlog(TL_INFO,"Memory allocated: %.2fMb", ((float)structsize)/(1024.0*1024.0));
+
+               gettimeofday( &begin, NULL );
+               while(fgets(buf,4096,stdin)) {
+                       char *ptr=buf;
+                       len = clrspace(buf);
+                       if (!len) continue;
+                       res = bsearch(&ptr, data, curlen, sizeof(char**), STRINGCMP);
+                       
+                       if (verbose) 
+                               puts( (res) ? "Y" : "N" );
+
+                       checked++;
+                       if (res) success++;
+               }
+               gettimeofday( &end, NULL );
+       } else {
+               SFSTree info;
+               SFSDataIO n = {NULL,0,NULL};
+               n.data = (void*)&enumerate;
+
+               gettimeofday( &begin, NULL );
+               if (enumerate) {
+                       char **ptr=data;
+
+                       SFSInit_dp(&info,sizeof(enumerate),NULL);
+                       while(*ptr) {
+                               n.key = *ptr;
+                               SFSAdd(&info, &n);
+                               enumerate++;
+                               ptr++;
+                       }
+               } else
+                       SFSInit_c(&info,data);
+               tlog(TL_INFO,"Init time: %.03f secs",  elapsedtime(&begin) );
+               tlog(TL_INFO,"Memory allocated: %.2fMb", ((float)info.totalen)/(1024.0*1024.0));
+               tlog(TL_INFO,"Number of nodes: %d", info.nnodes);
+
+               for(i=0;i<curlen;i++)
+                       tfree(data[i]);
+               tfree(data);
+
+               if ( addondatafile ) {
+                       int cntadd=0;
+
+                       if ( (in=fopen(addondatafile,"r"))==NULL ) 
+                               tlog(TL_CRIT|TL_EXIT,"Beda with %s", addondatafile);
+                       n.key=buf;
+
+                       gettimeofday( &begin, NULL );
+                       while(fgets(buf,4096,in)) {
+                               if ( !clrspace(buf) ) continue;
+                               n.keylen=0;
+                               SFSAdd(&info, &n);
+                               if (enumerate) enumerate++;
+                               cntadd++;
+                       }
+                       gettimeofday( &end, NULL );
+                       fclose(in);
+                       sumtime = timediff(&begin,&end);
+                       tlog(TL_INFO,"Add time: %.03f secs,   %.03f per second", sumtime, ((double)cntadd)/sumtime);
+                       tlog(TL_INFO,"Added item: %d", cntadd);
+                       tlog(TL_INFO,"Memory allocated: %.2fMb", ((float)info.totalen)/(1024.0*1024.0));
+                       tlog(TL_INFO,"Number of nodes: %d", info.nnodes);
+                       curlen+=cntadd;
+               }
+
+               if (list) {
+                       SFSDataIO out;
+
+                       gettimeofday( &begin, NULL );
+                       SFSIteratorStart(&info);
+                       while( SFSIterate(&info, &out) ) { 
+                               if ( verbose ) {
+                                       if (enumerate) {
+                                               fputs(out.key, stdout);
+                                               printf(" %d\n", *(int*)(out.data));
+                                       } else
+                                               puts(out.key);
+                               }
+                               checked++; success++;
+                       }
+                       gettimeofday( &end, NULL );
+               } else if ( gmode ) {
+                       int Gist[256];
+   
+                       memset(Gist,0,sizeof(int)*256);
+                       gettimeofday( &begin, NULL );
+                       gistogramm(info.node, Gist);
+                       gettimeofday( &end, NULL );
+                       for(i=0;i<256;i++)
+                               printf("%d\t%d\n",i,Gist[i]);
+               } else if ( prefix ) {
+                       SFSDataIO out;
+                       
+                       gettimeofday( &begin, NULL );
+                       while(fgets(buf,4096,stdin)) {
+                               len = clrspace(buf);
+                               if (!len) continue;
+
+                               SFSPrefixIteratorStart(&info,buf);
+                               while( SFSIterate(&info, &out)) { 
+                                       if (verbose) { 
+                                               if (enumerate) {
+                                                       putchar('>'); 
+                                                       fputs(out.key, stdout);
+                                                       printf(" %d\n", *(int*)(out.data));
+                                               } else {
+                                                       putchar('>'); 
+                                                       puts(out.key);
+                                               }
+                                       }
+                                       success++;
+                               }       
+                               checked++;
+                       }
+                       gettimeofday( &end, NULL );
+               } else if ( range ) {
+                       SFSDataIO f,l;
+                       
+                       gettimeofday( &begin, NULL );
+                       while(fgets(buf,4096,stdin)) {
+                               len = clrspace(buf);
+                               if (!len) continue;
+
+                               if ( SFSRange(&info,buf,&f,&l) ) {
+                                       if (verbose) { 
+                                               if (enumerate) {
+                                                       putchar('>'); 
+                                                       fputs(f.key, stdout);
+                                                       printf(" %d\n", *(int*)(f.data));
+                                                       putchar('>'); 
+                                                       fputs(l.key, stdout);
+                                                       printf(" %d\n", *(int*)(l.data));
+                                               } else {
+                                                       putchar('>'); puts(f.key);
+                                                       putchar('>'); puts(l.key);
+                                               }
+                                       }
+                                       success++;
+                               }       
+                               checked++;
+                       }
+                       gettimeofday( &end, NULL );
+               } else {
+                       gettimeofday( &begin, NULL );
+                       while(fgets(buf,4096,stdin)) {
+                               len = clrspace(buf);
+                               if (!len) continue;
+
+                               res = SFSFindData(&info,buf);
+                               if (verbose) {
+                                       if (enumerate && res)
+                                               printf("%d\n", *(int*)(res));
+                                       else 
+                                               puts( (res) ? "Y" : "N" );
+                               }
+
+                               checked++;
+                               if (res) success++;
+                       }
+                       gettimeofday( &end, NULL );
+               }
+               SFSFree(&info,NULL);
+       }
+
+       sumtime = timediff(&begin,&end);
+       tlog(TL_INFO,"Total execution time: %.03f secs", sumtime);
+       tlog(TL_INFO,"Total words in data: %d; Checked: %d; Success: %d", curlen, checked, success);
+       tlog(TL_INFO,"%.2f words per second", ((double)checked)/sumtime);
+       
+       closetlog();
+       return 0;
+}      
diff --git a/shmem.c b/shmem.c
new file mode 100644 (file)
index 0000000..933dc4b
--- /dev/null
+++ b/shmem.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h> 
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+#include <errno.h>
+
+#include "tlog.h"
+#include "shmem.h"
+
+#define KEY 101
+#define PATH   "/bin"
+
+void *
+attachSharedMemory(int key, char *path, int size, int rdonly) {
+       key_t shm_key;
+       int shm_id, flags=0;
+       void *shm;
+
+       if ( size>0 && rdonly )
+               return NULL;
+
+       shm_key = ftok( (path) ? path : PATH, (key) ? key : KEY);    /* Get IPC key */
+       if ((int) shm_key == -1) 
+               tlog(TL_CRIT|TL_EXIT, "Ftok error: %s", strerror(errno));
+
+       if (size > 0) 
+               flags = IPC_CREAT | IPC_EXCL | 0644;
+
+       shm_id = shmget(shm_key, size, flags); /* Get SHM segment */
+       if (shm_id == -1) {
+               if ( errno == EEXIST || errno == ENOENT )
+                       return NULL;
+               else
+                        tlog(TL_CRIT|TL_EXIT, "shmget error: %s", strerror(errno));
+       }
+
+       flags = ( rdonly ) ? SHM_RDONLY : 0;
+
+       shm = shmat(shm_id, 0, flags);      /* Attach SHM segment */
+       if ( (int)shm == -1 )
+               tlog(TL_CRIT|TL_EXIT, "shmat error: %s", strerror(errno));
+       return shm;
+}
+void 
+detachSharedMemory(void *shm) {
+       if ( shmdt(shm) == -1 )
+               tlog(TL_CRIT, "shmdt error: %s", strerror(errno));
+}
+
+int
+attachSemaphore(int key, char *path) {
+       key_t shm_key;
+       int sem_id;
+
+       shm_key = ftok( (path) ? path : PATH, (key) ? key : KEY);    /* Get IPC key */
+       if ((int) shm_key == -1)
+               tlog(TL_CRIT|TL_EXIT, "Ftok error: %s", strerror(errno));
+
+       sem_id = semget(shm_key, 1, 0);
+       if ( sem_id == -1 ) {
+               if ( errno == ENOENT ) { /* not exists */
+                       sem_id = semget(shm_key, 1, IPC_CREAT | IPC_EXCL | 0644);
+                       if ( sem_id == -1 )
+                               tlog(TL_CRIT|TL_EXIT, "semget error: %s", strerror(errno));
+                       if ( semctl( sem_id, 0, SETVAL, 1 ) == -1 )
+                               tlog(TL_CRIT|TL_EXIT, "sysctl error: %s", strerror(errno));
+               } else 
+                       tlog(TL_CRIT|TL_EXIT, "semget error: %s", strerror(errno));
+       }
+       return sem_id;
+}
+
+void releaseSemaphore(int sem_id) {
+       struct sembuf sem;
+
+       sem.sem_num = 0;
+       sem.sem_flg = 0;
+       sem.sem_op =  1;
+
+       if (semop(sem_id, &sem, 1) == -1) 
+               tlog(TL_CRIT|TL_EXIT, "semop error: %s", strerror(errno));
+}
+       
+void lockSemaphore(int sem_id) {
+       struct sembuf sem;
+
+       sem.sem_num = 0;
+       sem.sem_flg = 0;
+       sem.sem_op = -1;
+
+       if (semop(sem_id, &sem, 1) == -1) 
+               tlog(TL_CRIT|TL_EXIT, "semop error: %s", strerror(errno));
+}
+       
+       
+
diff --git a/shmem.h b/shmem.h
new file mode 100644 (file)
index 0000000..94721f7
--- /dev/null
+++ b/shmem.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __T_SHMEM_H__
+#define __T_SHMEM_H__
+
+void * attachSharedMemory(int key, char *path, int size, int rdonly);
+void detachSharedMemory(void *shm);
+
+int attachSemaphore(int key, char *path);
+void lockSemaphore(int sem_id);
+void releaseSemaphore(int sem_id);
+
+#endif
diff --git a/tcp.c b/tcp.c
new file mode 100644 (file)
index 0000000..0273787
--- /dev/null
+++ b/tcp.c
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#else /* HAVE_POLL */
+#ifdef HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#else
+#error Not defined HAVE_POLL_H or HAVE_SYS_POLL_H
+#endif /* HAVE_SYS_POLL_H */
+#endif /* HAVE_POLL */
+
+#ifdef HAVE_HSTRERROR 
+#include <netdb.h>
+#endif
+
+
+#include "connection.h"
+#include "tlog.h"
+#include "tmalloc.h"
+
+u_int32_t
+TC_ClientInitConnection(TC_Connection *cs, char *name, u_int32_t port) {
+       int flags;
+
+       cs = TC_fillConnection(cs, name, port);
+
+       cs->state = CS_OK;
+       if ((cs->fd= socket(AF_INET, SOCK_STREAM, 0)) < 0)
+               tlog(TL_CRIT|TL_EXIT,"socket4: %s:%d - %s",inet_ntoa(cs->serv_addr.sin_addr),
+                       ntohs(cs->serv_addr.sin_port),strerror(errno));
+
+       if ((flags=fcntl(cs->fd,F_GETFL,0)) == -1)
+               tlog(TL_ALARM,"fcntl F_GETFL - %s",strerror(errno));
+       if (fcntl(cs->fd,F_SETFL,flags|O_NDELAY) < 0 )
+               tlog(TL_ALARM,"fcntl O_NDELAY - %s",strerror(errno));
+
+       if (bind(cs->fd, (struct sockaddr *) &(cs->serv_addr), sizeof(cs->serv_addr)) < 0)
+               tlog(TL_CRIT|TL_EXIT, "cannot bind to %s address: %s",
+                       inet_ntoa(cs->serv_addr.sin_addr), strerror(errno));
+       
+       if (listen(cs->fd, 0) < 0)
+               tlog(TL_CRIT|TL_EXIT, "cannot listen to %s address: %s",
+                       inet_ntoa(cs->serv_addr.sin_addr), strerror(errno));
+       
+       return CS_OK;
+}
+
+TC_Connection*
+TC_AcceptTcp(TC_Connection *cs) {
+       TC_Connection *nc;
+       struct sockaddr_in cli_addr;
+       int ret, flags;
+       socklen_t clilen = sizeof(cli_addr);
+
+       cs->state = CS_READ;
+       if ( (ret = accept(cs->fd,(struct sockaddr *)&cli_addr, &clilen)) < 0 ) {
+               if ( errno == EAGAIN || errno == EWOULDBLOCK )
+                       return NULL;
+               tlog(TL_ALARM,"TC_AcceptTcp: accept: %s", strerror(errno));
+               return NULL;
+       }
+       nc = (TC_Connection*)t0malloc(sizeof(TC_Connection));
+
+       nc->fd = ret;
+       if ((flags=fcntl(nc->fd,F_GETFL,0)) == -1)
+               tlog(TL_ALARM,"fcntl F_GETFL - %s",strerror(errno));
+       if (fcntl(nc->fd,F_SETFL,flags|O_NDELAY) < 0 )
+               tlog(TL_ALARM,"fcntl O_NDELAY - %s",strerror(errno));
+       memcpy( &(nc->serv_addr), &cli_addr, clilen );
+       nc->state = CS_CONNECTED;
+
+       return nc;
+}
+
+TC_Connection *
+TC_fillConnection(TC_Connection *sc, char *name, u_int32_t port) {
+       if ( !sc ) 
+               sc = (TC_Connection *)t0malloc(sizeof(TC_Connection));
+       sc->serv_addr.sin_family = AF_INET;
+       sc->serv_addr.sin_addr.s_addr = (name) ? inet_addr(name) : htonl(INADDR_ANY);
+       sc->serv_addr.sin_port = htons(port);
+       sc->state = CS_NOTINITED;
+       return sc; 
+}
+
+static u_int32_t
+setlinger( TC_Connection *cs ) {
+       struct linger ling;
+       int     val = 0;
+       socklen_t size = sizeof(val); 
+
+       if (getsockopt(cs->fd, SOL_SOCKET,SO_ERROR,&val,&size) == -1) {
+               tlog(TL_ALARM,"getsockopt: %s:%d - %s(%d)",inet_ntoa(cs->serv_addr.sin_addr),
+                       ntohs(cs->serv_addr.sin_port), strerror(errno), errno);
+               shutdown(cs->fd,SHUT_RDWR);
+               close(cs->fd);
+               cs->fd = 0;
+               cs->state = CS_ERROR;
+               return CS_ERROR;
+       }
+
+       if ( val ) {
+               tlog(TL_ALARM,"getsockopt return: %s:%d - %s(%d)",inet_ntoa(cs->serv_addr.sin_addr),
+                       ntohs(cs->serv_addr.sin_port), strerror(val), val);
+               shutdown(cs->fd,SHUT_RDWR);
+               close(cs->fd);
+               cs->fd = 0;
+               cs->state = CS_ERROR;
+               return CS_ERROR;
+       }
+
+
+       ling.l_onoff = ling.l_linger = 0;
+       if (setsockopt(cs->fd, SOL_SOCKET,SO_LINGER,(char *)&ling,sizeof(ling))==-1) {
+               tlog(TL_ALARM,"setsockopt: LINGER %s:%d - %s",inet_ntoa(cs->serv_addr.sin_addr),
+                       strerror(errno));
+               shutdown(cs->fd,SHUT_RDWR);
+               close(cs->fd);
+               cs->fd = 0;
+               cs->state = CS_ERROR;
+               return CS_ERROR;
+       }
+       cs->state = CS_CONNECTED;
+       return CS_CONNECTED;
+}
+
+u_int32_t
+TC_ServerInitConnect( TC_Connection    *cs ) {
+       int flags;
+
+       if ( cs->state == CS_ERROR )
+               return CS_ERROR;
+
+       if ((cs->fd= socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+               tlog(TL_CRIT,"socket4: %s:%d - %s",inet_ntoa(cs->serv_addr.sin_addr),
+                       ntohs(cs->serv_addr.sin_port),strerror(errno));
+               cs->state  = CS_ERROR;
+               return  CS_ERROR;
+       }
+
+       if ((flags=fcntl(cs->fd,F_GETFL,0)) == -1)
+               tlog(TL_ALARM,"fcntl F_GETFL - %s",strerror(errno));
+       if (fcntl(cs->fd,F_SETFL,flags|O_NDELAY) < 0 )
+               tlog(TL_ALARM,"fcntl O_NDELAY - %s",strerror(errno));
+
+       if ( connect(cs->fd, (struct sockaddr *) &(cs->serv_addr),
+               sizeof(struct sockaddr_in)) < 0 ) {
+               if ( errno == EINPROGRESS || errno == EALREADY ) {
+                       cs->state = CS_INPROCESS;
+                       return CS_INPROCESS; 
+               } else if (errno != EISCONN && errno != EALREADY &&
+                       errno != EWOULDBLOCK && errno != EAGAIN) {
+                       tlog(TL_DEBUG,"open4: %s:%d - %s",
+                               inet_ntoa(cs->serv_addr.sin_addr), ntohs(cs->serv_addr.sin_port),
+                               strerror(errno));
+                       shutdown(cs->fd,SHUT_RDWR);
+                       close(cs->fd);
+                       cs->fd = 0;
+               } else {
+                       tlog(TL_DEBUG,"nonblock connect: %s:%d - %s [%d]",
+                               inet_ntoa(cs->serv_addr.sin_addr),
+                               ntohs(cs->serv_addr.sin_port),
+                               strerror(errno),errno);
+               }
+               cs->state = CS_ERROR;
+               return CS_ERROR;
+       }
+
+       cs->state = CS_INPROCESS;
+       return TC_ServerConnect( cs );
+}
+       
+
+u_int32_t
+TC_ServerConnect( TC_Connection *cs ) {
+       struct pollfd   pfd;
+       int ret;
+
+       if ( cs->state != CS_INPROCESS )
+               return cs->state;
+
+       pfd.fd = cs->fd;
+       pfd.events = POLLOUT;
+       pfd.revents = 0;
+       ret = poll( &pfd, 1, 0 );
+       if ( ret<0 ) {
+               tlog( TL_CRIT, "TC_ServerConnect: poll: %s",
+                       strerror(errno));
+               cs->state = CS_ERROR;
+               return CS_ERROR;
+       } else if ( ret == 0 ) 
+               return CS_INPROCESS;
+
+       if ( (pfd.revents & (POLLHUP | POLLNVAL | POLLERR)) ) {
+               tlog( TL_CRIT, "TC_ServerConnect: poll return connect error for %s:%d",
+                       inet_ntoa(cs->serv_addr.sin_addr), ntohs(cs->serv_addr.sin_port));
+               cs->state = CS_ERROR;
+               return CS_ERROR;
+       }
+
+       if ( ! (pfd.revents & POLLOUT) )
+               return CS_INPROCESS;
+
+
+       return setlinger( cs );
+}
+
+int
+TC_ReadyIO( TC_Connection **cs, int number, int timeout ) {
+       struct pollfd   *pfd;
+       int ret,i, fdnum=0;
+
+       if ( number==0 || cs ==NULL ) {
+               usleep( timeout * 1000.0 );
+               return 0;
+       }
+       pfd = (struct pollfd*) tmalloc( sizeof(struct pollfd) * number );
+
+       for(i=0; i<number;i++) {
+               if ( cs[i]->fd>0 && (cs[i]->state == CS_READ || cs[i]->state == CS_SEND) ) {
+                       pfd[fdnum].fd = cs[i]->fd;
+                       pfd[fdnum].events = ( cs[i]->state == CS_READ ) ? POLLIN : POLLOUT;
+                       pfd[fdnum].revents = 0;
+                       fdnum++;
+               }
+               cs[i]->readyio=0;
+       }
+       ret = poll( pfd, fdnum, timeout );
+       if ( ret<0 ) {
+               tlog( TL_CRIT, "TC_ReadyIO: poll: %s",
+                       strerror(errno));
+               tfree(pfd);
+               return 0;
+       }
+
+       if ( ret == 0 ) {
+               tfree(pfd);
+               return 0;
+       }
+
+       fdnum=0; ret=0;
+       for(i=0; i<number;i++) {
+               if ( cs[i]->fd>0 && (cs[i]->state == CS_READ || cs[i]->state == CS_SEND) ) {
+                       if ( pfd[fdnum].revents & (POLLHUP | POLLNVAL | POLLERR) ) { 
+                               tlog( TL_ALARM, "TC_ReadyIO: poll return error for %s:%d",
+                                       inet_ntoa(cs[i]->serv_addr.sin_addr), 
+                                       ntohs(cs[i]->serv_addr.sin_port));
+                               cs[i]->state = CS_ERROR;
+                               ret = 1;
+                       } else if ( pfd[fdnum].revents & ( ( cs[i]->state == CS_READ ) ? POLLIN : POLLOUT ) ) {
+                               cs[i]->readyio=1;
+                               ret = 1;
+                       }
+                       fdnum++;
+               }
+       }
+
+       tfree(pfd);
+       return ret;
+}
+
+u_int32_t
+TC_Send( TC_Connection *cs ) {
+       int sz;
+       
+       if ( cs->state == CS_ERROR )
+               return CS_ERROR;
+
+       if ( cs->state != CS_SEND ) {
+               cs->state = CS_SEND;
+               cs->ptr = cs->buf;
+       }
+
+       if ( cs->ptr - cs->buf >= cs->len ) {
+               cs->state = CS_FINISHSEND;
+               return CS_FINISHSEND;
+       }
+
+       if ((sz=write(cs->fd, cs->ptr, cs->len - (cs->ptr - cs->buf)))==0 ||
+               (sz < 0 && (errno == EWOULDBLOCK || errno == EAGAIN))) {
+
+               /* SunOS 4.1.x, are broken and select() says that
+                * O_NDELAY sockets are always writable even when
+                * they're actually not.
+                */
+               cs->state = CS_SEND;
+               return CS_SEND;
+       }
+       if ( sz<0 ) {
+               if (errno != EPIPE && errno != EINVAL)
+                       tlog(TL_ALARM, "write[%s:%d] - %s",
+                               inet_ntoa(cs->serv_addr.sin_addr),
+                               ntohs(cs->serv_addr.sin_port), 
+                               strerror(errno));
+               cs->state = CS_ERROR;
+               return CS_ERROR;
+       }
+
+       cs->ptr += sz;
+
+       if ( cs->ptr - cs->buf >= cs->len ) {
+               cs->state = CS_FINISHSEND;
+               return CS_FINISHSEND;
+       }
+       
+       return cs->state;
+}
+
+static void 
+resizeCS( TC_Connection *cs, int sz ) {
+       int diff = cs->ptr - cs->buf;
+       if ( cs->len >= sz )
+               return; 
+       cs->len = sz;
+       cs->buf = (char*)trealloc( (void*)cs->buf, cs->len );
+       cs->ptr = cs->buf + diff;
+}
+
+u_int32_t
+TC_Read( TC_Connection *cs ) {
+       int sz, totalread = -1, toread=0, alreadyread;
+
+       if ( cs->state == CS_ERROR )
+               return CS_ERROR;
+
+       if (cs->state != CS_READ ) {
+               cs->state = CS_READ;
+               cs->ptr = cs->buf;
+       }
+
+       alreadyread = cs->ptr - cs->buf;
+       if ( alreadyread < sizeof(u_int32_t) ) {
+               toread = sizeof(u_int32_t) - alreadyread;
+               resizeCS(cs, sizeof(u_int32_t));
+       } else {
+               totalread = *(u_int32_t*)(cs->buf);
+               toread = totalread - alreadyread;
+               if ( toread == 0 ) {
+                       cs->state = CS_FINISHREAD;
+                       return CS_FINISHREAD;
+               }
+               resizeCS(cs, totalread);
+       }
+
+       if ((sz=read( cs->fd, cs->ptr, toread))<0) {
+               if (errno == EAGAIN || errno == EINTR) {
+                       cs->state = CS_READ;
+                       return CS_READ;
+               }
+               tlog(TL_ALARM,"read: finish - %s",strerror(errno));
+               cs->state = CS_ERROR;
+               return CS_ERROR;
+       }
+       
+
+       cs->ptr += sz;
+       alreadyread += sz;
+       if ( sz == 0 && alreadyread != totalread ) {
+               tlog(TL_ALARM,"read: disconnecting");
+               cs->state = CS_ERROR;
+               return CS_ERROR;
+       }
+       cs->state = ( alreadyread == totalread ) ? CS_FINISHREAD : CS_READ;
+       return cs->state;
+}
+
+void
+TC_FreeConnection( TC_Connection *cs ) {
+       if ( cs->state == CS_CLOSED )
+               return;
+       if ( cs->buf ) {
+               tfree(cs->buf);
+               cs->buf = NULL;
+       }
+       if ( cs->fd && cs->state != CS_NOTINITED ) {
+               shutdown(cs->fd,SHUT_RDWR);
+               close(cs->fd);
+       }
+       cs->fd = 0;
+       cs->state = CS_CLOSED;
+}
+
+u_int32_t 
+TC_Talk( TC_Connection *cs ) {
+       u_int32_t ret = TC_ServerInitConnect( cs );
+
+       while( ret == CS_INPROCESS ) {
+               ret =  TC_ServerConnect(cs);
+       }
+
+       if ( ret != CS_CONNECTED )
+               return ret;
+       
+       while( ret != CS_FINISHSEND ) {
+               ret = TC_Send(cs);
+               if ( ret == CS_ERROR ) return ret;
+       }
+
+       cs->state = CS_READ;
+       cs->ptr = cs->buf;
+       while( cs->state != CS_FINISHREAD ) {
+               while( !TC_ReadyIO( &cs, 1, 100) );
+               if ( ret == CS_ERROR ) return ret;
+               if ( TC_Read(cs) == CS_ERROR ) return CS_ERROR;
+       }
+
+       return CS_OK; 
+}
+
+
diff --git a/test.inf b/test.inf
new file mode 100644 (file)
index 0000000..c0b254b
--- /dev/null
+++ b/test.inf
@@ -0,0 +1,23 @@
+
+[test]
+kde=   
+
+kde=v
+kde =v
+kde  =    v      #WOW
+asdfas = \
+HAHA\
+
+#wwekljrw
+[test2] #sfljkl'sdf
+#dfghjkl
+t2="qweqwe#asd" 
+t2="qweqwe#as\"d" #HEH
+t5="hsdf
+sdf sdf 
+sdf sdf sdf
+sdf sdf 
+sdf sdfssd f
+\\
+sdf sdf sdf
+" 
diff --git a/tlog.c b/tlog.c
new file mode 100644 (file)
index 0000000..36c4c54
--- /dev/null
+++ b/tlog.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <stdarg.h>
+
+#include "tlog.h"
+
+static FILE             *TL_ErrOut    = NULL;
+static u_int32_t        TL_DebugLevel = TL_INFO;
+static u_int32_t       tlflag = TL_OPEN_STDERR | TL_OPEN_SYSLOG; 
+
+
+static int
+TLtoSYS(int level) {
+       switch(level) {
+               case    TL_CRIT : return LOG_CRIT;
+               case    TL_ALARM: return LOG_ERR;
+               case    TL_WARN : return LOG_WARNING;
+               case    TL_INFO : return LOG_INFO;
+               case    TL_DEBUG: return LOG_DEBUG;
+               default: return LOG_WARNING;
+       }
+       return LOG_ERR;
+}
+
+void 
+opentlog(u_int32_t flag, u_int32_t level, char *file) {
+       if (flag==0)
+               flag=tlflag;
+
+       TL_DebugLevel=level;
+
+       tlflag &= ~TL_OPEN_FILE;
+       if ( TL_ErrOut )
+               fclose(TL_ErrOut);
+       if ( (flag & TL_OPEN_FILE) && file ) {
+               if ( (TL_ErrOut=fopen(file,"a")) == NULL )
+                       tlog(TL_ALARM,"Can't open log file '%s': %s", file, strerror(errno));
+               else {
+                       u_int32_t oldflag = tlflag;
+                       tlflag = TL_OPEN_FILE;
+                       tlog(TL_INFO, "Log opened");
+                       tlflag = oldflag | TL_OPEN_FILE;        
+               }
+       }
+
+       tlflag &= ~TL_OPEN_SYSLOG;
+       tlflag |= (flag & TL_OPEN_SYSLOG);
+
+       tlflag &= ~TL_OPEN_STDERR;
+       tlflag |= (flag & TL_OPEN_STDERR);
+}
+
+void
+closetlog() {
+       if ( TL_ErrOut ) {
+               if ( tlflag & TL_OPEN_FILE ) {
+                       tlflag = TL_OPEN_FILE;
+                       tlog(TL_INFO,"Log closed");
+               }
+               fclose(TL_ErrOut);
+       }
+       TL_ErrOut=NULL;
+       tlflag = TL_OPEN_STDERR | TL_OPEN_SYSLOG;
+}
+
+void 
+tlog(u_int32_t level,const char *format, ...) {
+       va_list args;
+
+       if ( (level & TL_EXIT)==0 )
+               if ( (level & ~TL_EXIT) > TL_DebugLevel )
+                       return;
+       
+       if ( tlflag & (TL_OPEN_STDERR | TL_OPEN_FILE) ) { 
+               time_t t;
+               char buf[64];
+               t = time(NULL);
+
+               strftime(buf,64,"%H:%M:%S %d/%m/%Y",localtime(&t));
+               if ( tlflag & TL_OPEN_STDERR ) {
+                       fprintf( stderr,"%d %s ", getpid(), buf );
+                       va_start(args, format);
+                       vfprintf( stderr, format, args);
+                       va_end(args);
+                       fputc('\n', stderr);
+               }
+               if ( (tlflag & TL_OPEN_FILE) && TL_ErrOut ) {
+                       fprintf( TL_ErrOut,"%d %s ", getpid(), buf );
+                       va_start(args, format);
+                       vfprintf( TL_ErrOut, format, args);
+                       va_end(args);
+                       fputc('\n', TL_ErrOut);
+               }
+       }
+
+       if ( tlflag & TL_OPEN_SYSLOG ) {
+               va_start(args, format);
+               vsyslog( TLtoSYS( (int)(level & ~TL_EXIT) ),  format, args );   
+               va_end(args);
+       }
+
+       if ( level & TL_EXIT ) {
+               tlog(level & ~TL_EXIT, "Exitting...");
+               closetlog();
+               exit(1);
+       }
+}
+
diff --git a/tlog.h b/tlog.h
new file mode 100644 (file)
index 0000000..dbe6efd
--- /dev/null
+++ b/tlog.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __TLOG_H__
+#define __TLOG_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#define TL_EXIT 0x70000000
+#define TL_CRIT        0
+#define TL_ALARM        1
+#define TL_WARN                2
+#define TL_INFO                3       
+#define TL_DEBUG        4
+
+#define TL_OPEN_SYSLOG         0x01
+#define TL_OPEN_STDERR         0x02
+#define TL_OPEN_FILE           0x04
+
+void opentlog(u_int32_t flag, u_int32_t level, char *file);
+void tlog(u_int32_t level,const char *format, ...);
+void closetlog();
+
+#ifdef ASSERT_CORE
+#define tassert(e)   ( (e) ? (void)0 : (tlog(TL_CRIT, "Assertion failed: %s, function %s, file %s, line %d.", #e, (__func__) ? __func__ : "UNKNOWN", __FILE__, __LINE__), closetlog(), abort()) )
+#else
+#define tassert(e)   ( (e) ? (void)0 : (tlog(TL_CRIT|TL_EXIT, "Assertion failed: %s, function %s, file %s, line %d.", #e, (__func__) ? __func__ : "UNKNOWN", __FILE__, __LINE__)) )
+#endif
+
+#endif
diff --git a/tmalloc.c b/tmalloc.c
new file mode 100644 (file)
index 0000000..953e28f
--- /dev/null
+++ b/tmalloc.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "tlog.h"
+#include "tmalloc.h"
+
+void *
+tmalloc(size_t size) {
+       void *ptr = malloc(size);
+       if (!ptr)
+               tlog(TL_CRIT|TL_EXIT, "Can't allocate %d bytes", size);
+       return ptr;
+}
+
+void *
+t0malloc(size_t size) {
+       void *ptr = tmalloc(size);
+       memset(ptr,0,size);
+       return ptr;
+}
+
+void *
+trealloc(void * ptr, size_t size) {
+       if (ptr) {
+               ptr = realloc(ptr,size);
+               if (!ptr)
+                       tlog(TL_CRIT|TL_EXIT, "Can't reallocate to %d bytes", size);
+       } else
+               ptr = tmalloc(size);    
+       return ptr;
+}
+
+void
+tfree(void * ptr) {
+       free(ptr);
+}
+
+char * 
+tstrdup(char * src) {
+       char * dest = strdup(src);
+       if (!dest) 
+               tlog(TL_CRIT|TL_EXIT, "Can't strdup %d bytes", strlen(src)+1);
+       return dest;
+}
+
+char *
+tnstrdup(char *src, int len) {
+       char *dest=(char*)tmalloc(len+1);
+       memcpy(dest, src, len);
+       dest[len]='\0';
+       return dest;
+}
+
+char *
+strlower(char * src) {
+       char *ptr = src;
+       if (!src) return src;
+       while(*ptr) {
+               *ptr = tolower(*(unsigned char *) ptr);
+               ptr++; 
+       }
+       return src;
+}
+
+char *
+strupper(char * src) {
+       char *ptr = src;
+       if (!src) return src;
+       while(*ptr) {
+               *ptr = toupper(*(unsigned char *) ptr);
+               ptr++; 
+       }
+       return src;
+}
+
+int
+clrspace(char *buf) {
+        char *ptr=buf, *ptrc=buf;
+        while(*ptr) {
+                if (!isspace(*ptr)) {
+                        *ptrc=*ptr;
+                        ptrc++;
+                }
+                ptr++;
+        }
+        *ptrc='\0';
+        return ptrc - buf;
+}
+
diff --git a/tmalloc.h b/tmalloc.h
new file mode 100644 (file)
index 0000000..0c3a275
--- /dev/null
+++ b/tmalloc.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __TMALLOC_H__
+#define __TMALLOC_H__
+
+#include <sys/types.h>
+
+void * tmalloc(size_t size);
+void * trealloc(void * ptr, size_t size); 
+void * t0malloc(size_t size);
+void tfree(void * ptr);
+
+char * tstrdup(char * src); 
+char * tnstrdup(char *src, int len);
+char * strlower(char * src);
+char * strupper(char * src);
+int clrspace(char *buf);
+#endif
diff --git a/tools.c b/tools.c
new file mode 100644 (file)
index 0000000..a6c0206
--- /dev/null
+++ b/tools.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ctype.h>
+#include <sys/types.h>
+
+#include "tmalloc.h"
+#include "tlog.h"
+#include "tools.h"
+
+#define isXdigit(c) ( ((c)>='0' && (c)<='9') || ((c)>='A' && (c)<='F') || ((c)>='a' && (c)<='f') )
+
+static u_int8_t str2hex[] = {
+          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+          0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  0,  0,  0,  0,  0,  0,
+          0, 10, 11, 12, 13, 14, 15,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+          0, 10, 11, 12, 13, 14, 15,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
+}; 
+
+u_int32_t 
+strtox(char *src, char **end) {
+       u_int32_t res=0, i=0;
+       
+       while(src && *src && isXdigit(*src) && i<8) {
+               res = res << 4;
+               res |= str2hex[ *(unsigned char*)src ];
+               src++;
+               i++;
+       }
+
+       if ( end )
+               *end=src;
+       return res;
+}
+
+static char buf[10];
+static char hex2str[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+
+char*     
+xtostr(u_int32_t x) {
+       char *ptr=buf;
+       int i,wast=0;
+       for(i=28;i>=0;i-=4) {
+               *ptr = hex2str[  (x>>i) & 0x0f ];
+               if ( wast || *ptr!='0' || i==0 ) {
+                       ptr++;
+                       wast=1;
+               }       
+       }
+       *ptr='\0';
+       return buf;
+}
+
+double 
+timediff(struct timeval *begin, struct timeval *end) {
+       return ((double)( end->tv_sec - begin->tv_sec )) + ( (double)( end->tv_usec-begin->tv_usec ) ) / 1.0e+6; 
+}
+
+double 
+elapsedtime(struct timeval *begin) {
+       struct timeval end;
+       gettimeofday(&end,NULL);
+       return timediff(begin,&end);
+}
diff --git a/tools.h b/tools.h
new file mode 100644 (file)
index 0000000..d70d14d
--- /dev/null
+++ b/tools.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __TTOOLS_H__
+#define __TTOOLS_H__
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+u_int32_t strtox(char *src, char **end);
+#define atox(x)        strtox((x),NULL)
+char*     xtostr(u_int32_t x);
+
+double timediff(struct timeval *begin, struct timeval *end);
+double elapsedtime(struct timeval *begin);
+#endif
diff --git a/udp.c b/udp.c
new file mode 100644 (file)
index 0000000..c98d4a1
--- /dev/null
+++ b/udp.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "connection.h"
+#include "tlog.h"
+#include "tmalloc.h"
+
+int 
+TC_AcceptUdp(char *host, int port) {
+       struct sockaddr_in serv_addr;
+       int sockfd, flags;
+
+       if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+               tlog(TL_CRIT|TL_EXIT, "udp socket %s", strerror(errno));
+       if ((flags=fcntl(sockfd,F_GETFL,0)) == -1)
+               tlog(TL_ALARM,"fcntl F_GETFL - %s",strerror(errno));
+
+       if (fcntl(sockfd,F_SETFL,flags|O_NDELAY) < 0 )
+               tlog(TL_ALARM,"fcntl O_NDELAY - %s",strerror(errno));
+
+       memset(&serv_addr, 0, sizeof(serv_addr));
+       serv_addr.sin_family = AF_INET;
+       serv_addr.sin_addr.s_addr = inet_addr(host);
+       serv_addr.sin_port = htons(port);
+
+       if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
+               tlog(TL_CRIT|TL_EXIT, "cannot bind to %s address: %s",
+                       inet_ntoa(serv_addr.sin_addr), strerror(errno));
+
+       return sockfd;
+}
+
+#define MSGMAXSIZE      8192
+char pc_msg_buf[MSGMAXSIZE];
+
+u_int32_t 
+TC_getMsg( int sockfd, Msg *msg ) {
+       struct sockaddr_in cli_addr;
+       int n;
+       socklen_t clilen = sizeof(cli_addr);
+       TCMsg *pmsg = (TCMsg*)pc_msg_buf;
+       
+       n = recvfrom(sockfd, pc_msg_buf, MSGMAXSIZE, 0, (struct sockaddr *)&cli_addr, &clilen);
+
+       if ( n<0 ) {
+               if ( errno == EAGAIN || errno == EWOULDBLOCK)
+                       return CS_AGAIN;
+               tlog(TL_ALARM, "recvfrom error: %s", strerror(errno));
+               return CS_ERROR;
+       }
+
+       if ( n<TCMSGHDRSZ  ) {
+               tlog(TL_ALARM, "Got message %d bytes (should be al least %d)", n, TCMSGHDRSZ );
+               return CS_AGAIN;
+       }
+
+       if ( pmsg->len > MSGMAXSIZE  ) {
+               tlog(TL_ALARM, "Messages (%d bytes) is too big", pmsg->len);
+               return CS_AGAIN;
+       }
+
+       if ( pmsg->len != n ) {
+               tlog(TL_ALARM, "Wrong size of messages (got %d bytes, should be %d bytes)", n, pmsg->len);
+               return CS_AGAIN;
+       }
+
+       memcpy( &(msg->host_addr), &cli_addr, clilen );
+       msg->msg = pmsg;
+       
+       return CS_OK; 
+}
+
+/* send */
+u_int32_t 
+TC_sendMsg( Msg *msg ) {
+       if ( msg->msg == NULL || msg->msg->len <=0  )
+               return CS_OK;
+
+       if ( msg->msg->len > MSGMAXSIZE )
+               return CS_ERROR; 
+
+       if ( msg->sockfd <=0 ) {
+               struct sockaddr_in cli_addr;
+               if ( (msg->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+                       tlog(TL_CRIT,"udp socket %s %d: %s", msg->host, msg->port, strerror(errno));
+                       return CS_ERROR;
+               }
+       
+               memset(&cli_addr, 0, sizeof(cli_addr));
+               cli_addr.sin_family = AF_INET;
+               cli_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+               cli_addr.sin_port = htons(0);
+       
+               if (bind(msg->sockfd, (struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0) {
+                       tlog(TL_CRIT, "cannot bind to address: %s", strerror(errno));   
+                       close(msg->sockfd);
+                       msg->sockfd=-1;
+                       return CS_ERROR;        
+               }
+               memset(&(msg->host_addr), 0, sizeof(msg->host_addr));
+               msg->host_addr.sin_family = AF_INET;
+               msg->host_addr.sin_addr.s_addr = inet_addr(msg->host);
+               msg->host_addr.sin_port = htons(msg->port);
+       }
+
+       if (sendto(msg->sockfd, (void*)msg->msg, msg->msg->len, 0, (struct sockaddr *) &(msg->host_addr), sizeof(msg->host_addr)) != msg->msg->len) {
+               tlog(TL_CRIT,"Can't send message to %s:%d : %s", msg->host, msg->port, strerror(errno));
+               close(msg->sockfd);
+               msg->sockfd=-1;
+               return CS_ERROR;        
+       }
+
+       return CS_OK;
+}
+
+void      
+TC_closefd( Msg *msg ) {
+       if ( msg->sockfd > 0 )
+               close(msg->sockfd);
+       msg->sockfd=-1;
+}
+
+