--- /dev/null
+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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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");
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
+
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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));
+}
+
+
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
+
+
--- /dev/null
+
+[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
+"
--- /dev/null
+/*
+ * 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);
+ }
+}
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
+
+