2 /* -------------------------------------------------------------------------- */
6 #include <kernelplat.h>
9 /* -------------------------------------------------------------------------- */
12 #define CERNDATE "%d/%b/%Y:%H:%M:%S"
15 #define TMPBUFSIZE 40960
16 #define WRITEMAX 30000
17 #define LOGBUFSIZE 1024
18 #define OOM_STRING "Out of memory!\nBailing."
19 #define MAX_MODULES 64
20 #define MAX_EVENTS_PER_MODULE 3
21 #define CHAN_CLOSING(chan) (chan->priv->state!=CHAN_OPEN)
27 #define MIN(a,b) (((a) < (b))? (a): (b))
29 /* -------------------------------------------------------------------------- */
31 typedef struct wrbuffer{
37 struct k_channel_priv{
53 typedef struct event{ struct event* next;
57 typedef struct k_module{
59 k_module_tick_fn tick_fn;
60 k_module_event_fn event_fn;
64 typedef struct key_event{ struct key_event* next;
69 /* -------------------------------------------------------------------------- */
72 static k_gl_reshape_event reshape_fn=0;
73 static k_gl_draw_event draw_fn=0;
74 static k_gl_key_event key_fn=0;
75 static k_module modules[MAX_MODULES];
76 static int nextmodule=0;
77 static key_event* key_consumer=0;
78 static key_event* key_producer=0;
79 static k_channel* k_channels=0;
80 static k_hashtable* connecting_chans;
81 static k_hashtable* current_chans;
82 static k_hashtable* monthhash;
83 static char tmpbuf[TMPBUFSIZE];
84 static char logbuf[LOGBUFSIZE];
85 static FILEP logfile=0;
87 static char dummy_empty_data[0];
89 /* -------------------------------------------------------------------------- */
91 static void gen_conn_name(k_channel* chan);
92 static void chan_closed(k_channel* chan);
93 static SOCK_T make_listen_socket(int listenport);
94 static SOCK_T make_connect_socket(void);
95 static int listen_socket(SOCK_T s, int listenport);
96 static int connect_socket(SOCK_T s, char*, int);
97 static void add_module_entry(char*, k_module_tick_fn, k_module_event_fn);
98 static int run_queues(void);
99 static void show_open_channels(void);
100 static k_channel* find_k_channel_for_socket(SOCK_T s);
101 static k_channel* register_k_channel(char* name,
105 k_channel_event rdcallback,
106 k_channel_event wrcallback,
109 struct in_addr clientip,
111 static event** get_module_queue(char* name);
112 static k_module_loaded_fn get_module_loaded_fn(char* name, MODULE module);
113 static k_module_tick_fn get_module_tick_fn( char* name, MODULE module);
114 static k_module_event_fn get_module_event_fn( char* name, MODULE module);
115 static int check_i(char* key, char* includes[], int ignorecase);
116 static int check_x(char* key, char* excludes[], int ignorecase);
117 static unsigned int string_hash(char* p);
118 static int set_rdbuffer(k_channel*, char* rdbuffer, size_t size);
119 static char* get_rdbuffer(k_channel* chan);
120 static void append_to_wrbuffers(k_channel*, char*, size_t, int);
121 static char* chop_from_rdbuffer_div(k_channel* chan, char* div);
122 static char* chop_from_rdbuffer_len(k_channel* chan, size_t size);
123 static void chop_from_wrbuffers( k_channel* chan, size_t size);
124 static void got_key(unsigned char key, int down);
125 static void init_keys(void);
126 static void dir_read(char*, char*, char*, int, k_stat, void*);
127 static void load_module(char* name, int dot);
128 static void init_modules(void);
129 static void log_net_err(char* where, int e);
130 static int dir_list(char*, int, char*, char*, char*);
131 static int ensure_dir(char* fullname);
132 static void next_keys(void);
133 static void read_more_and_notify(k_channel* chan);
134 static void readable_socket(k_channel* chan);
135 static void register_connections(k_channel* chan);
136 static void do_regular_things(void);
137 static void tick_modules(void);
138 static void remove_dead_k_channels(void);
139 static void unregister_k_channel(k_channel* chan, int now);
140 static void write_more_and_notify(k_channel* chan);
141 static char hex_to_int(char c);
142 static void write_to_logfile_cern_style(char* text, int error);
143 static void writeable_socket(k_channel* chan);
144 static void exception_socket(k_channel* chan);
145 static SOCK_T make_udp_listen_socket(int listenport);
146 static struct sockaddr_in make_sockaddr_in(unsigned long address,
148 static void init_hashtables(void);
150 /* -------------------------------------------------------------------------- */
152 #include <kernelplat.c>
154 /* -------------------------------------------------------------------------- */
156 EXPORT void c_init(char* version,
158 void (*terminate)(void))
162 k_terminate=terminate;
167 if(LOAD_MODULES_EARLY){
174 EXPORT C_RUN_RV c_run(C_RUN_ARG arg)
178 if(!LOAD_MODULES_EARLY){
184 if(reshape_fn)(*reshape_fn)(640,480);
185 if(draw_fn) (*draw_fn)();
187 k_log_out("Cilux U-Web Exchange started");
188 k_log_out("%s", k_version);
189 k_log_out("---------------------------------------------");
191 int queue_events_to_do=0;
193 if(running==2) poller(queue_events_to_do);
194 if(running==1) SLEEP_MS(LOOP_TICK);
195 if(running==0) break;
197 if(running==2) queue_events_to_do=run_queues();
199 if(running==0) break;
202 k_log_out("Cilux U-Web Exchange terminated");
207 EXPORT OTHER_THREAD void c_running(int r)
212 EXPORT OTHER_THREAD void c_key(unsigned char key, int down)
217 EXPORT OTHER_THREAD void c_signal(int signum)
219 k_log_out("Received signal %d", signum);
222 /* -------------------------------------------------------------------------- */
224 EXPORT void k_gl_register_reshape(k_gl_reshape_event callback){
228 EXPORT void k_gl_register_draw(k_gl_draw_event callback){
232 EXPORT void k_gl_register_key(k_gl_key_event callback){
236 /* -------------------------------------------------------------------------- */
238 void init_hashtables(void)
240 connecting_chans=k_hashtable_new("Connecting Channels", 0);
241 current_chans =k_hashtable_new("Current Channels", 0);
242 monthhash =k_hashtable_new("Months", 1);
243 k_hashtable_set(monthhash, "Jan", (void*)1);
244 k_hashtable_set(monthhash, "Feb", (void*)2);
245 k_hashtable_set(monthhash, "Mar", (void*)3);
246 k_hashtable_set(monthhash, "Apr", (void*)4);
247 k_hashtable_set(monthhash, "May", (void*)5);
248 k_hashtable_set(monthhash, "Jun", (void*)6);
249 k_hashtable_set(monthhash, "Jul", (void*)7);
250 k_hashtable_set(monthhash, "Aug", (void*)8);
251 k_hashtable_set(monthhash, "Sep", (void*)9);
252 k_hashtable_set(monthhash, "Oct", (void*)10);
253 k_hashtable_set(monthhash, "Nov", (void*)11);
254 k_hashtable_set(monthhash, "Dec", (void*)12);
257 void init_logging(void)
259 snprintf(tmpbuf, TMPBUFSIZE, "%s.log", k_ciux);
260 logfile=FOPEN(tmpbuf, "a");
261 if(!logfile) k_log_err("couldn't open logfile %s", tmpbuf);
264 void init_modules(void)
266 char* patts[]={ "{*.dll,*.so}", 0};
267 char* temps[]={ "%s:", 0 };
268 k_dir_list(".", ".", patts, temps, dir_read, 0);
271 void dir_read(char* basedir,
280 if(!strncmp(data, MODPRE, strlen(MODPRE))){
281 k_ciux=k_strdup(data+strlen(MODPRE));
282 char* c=strchr(k_ciux, '.');
294 k_log_out("========================================");
296 load_module("ni", 0);
297 load_module("np", 0);
298 if(!is_np) load_module(k_ciux, 1);
300 k_log_out("========================================");
303 void load_module(char* name, int dot)
305 k_log_out("------------ %s --------------", name);
307 snprintf(dlname, 64, "%s%s%s%s", dot? "./": "", MODPRE, name, MODPOST);
308 MODULE module=DLOPEN(dlname);
310 k_module_loaded_fn loaded_fn=get_module_loaded_fn(name, module);
311 k_module_tick_fn tick_fn =get_module_tick_fn( name, module);
312 k_module_event_fn event_fn =get_module_event_fn( name, module);
313 if(loaded_fn && event_fn){
314 add_module_entry(name, tick_fn, event_fn);
317 else k_log_err("Couldn't load module %s (hooks)", dlname);
319 else k_log_err("Couldn't load module %s (dlopen) %s", dlname, DLERROR);
322 k_module_loaded_fn get_module_loaded_fn(char* name, MODULE module)
324 snprintf(tmpbuf, TMPBUFSIZE, "%s%s", name, NAME_OF_MODULE_LOADED_FN);
325 k_module_loaded_fn f=(k_module_loaded_fn)DLSYM(module, tmpbuf);
326 if(!f) k_log_err("no %s", tmpbuf);
330 k_module_tick_fn get_module_tick_fn(char* name, MODULE module)
332 snprintf(tmpbuf, TMPBUFSIZE, "%s%s", name, NAME_OF_MODULE_TICK_FN);
333 k_module_tick_fn f=(k_module_tick_fn)DLSYM(module, tmpbuf);
334 if(!f) k_log_err("no %s", tmpbuf);
338 k_module_event_fn get_module_event_fn(char* name, MODULE module)
340 snprintf(tmpbuf, TMPBUFSIZE, "%s%s", name, NAME_OF_MODULE_EVENT_FN);
341 k_module_event_fn f=(k_module_event_fn)DLSYM(module, tmpbuf);
342 if(!f) k_log_err("no %s", tmpbuf);
346 /* -------------------------------------------------------------------------- */
348 void add_module_entry(char* name,
349 k_module_tick_fn tick_fn,
350 k_module_event_fn event_fn)
352 if(nextmodule==MAX_MODULES){
353 k_fatal("Too many modules! Maximum %d", MAX_MODULES);
355 modules[nextmodule ].name =name;
356 modules[nextmodule ].tick_fn =tick_fn;
357 modules[nextmodule ].event_fn=event_fn;
358 modules[nextmodule++].queue =0;
361 event* event_new(void* data)
364 ev=k_malloc(sizeof(event));
370 EXPORT int k_event_post(char* module, void* data)
372 event* ev=event_new(data);
373 event** queue=get_module_queue(module);
375 k_log_err("k_event_post(%s): no such module", module);
378 if(!*queue) *queue=ev;
392 event** get_module_queue(char* name)
395 for(i=0; i< nextmodule; i++){
396 if(!strcmp(modules[i].name, name)) return &modules[i].queue;
404 for(i=0; i< nextmodule; i++){
405 for(j=0; modules[i].queue && j < MAX_EVENTS_PER_MODULE; j++){
406 event* event=modules[i].queue;
407 modules[i].queue=event->next;
409 (*modules[i].event_fn)(event->data);
413 for(i=0; i< nextmodule; i++){
414 if(modules[i].queue) return 1;
419 /* -------------------------------------------------------------------------- */
424 ke=k_malloc(sizeof(key_event));
432 OTHER_THREAD void got_key(unsigned char key, int down)
434 if(!key_producer) return;
436 ke=k_malloc(sizeof(key_event));
440 key_producer->next=ke;
446 while(key_consumer!=key_producer){
447 key_event* ke=key_consumer->next;
448 if(key_fn) (*key_fn)(ke->key, ke->down);
449 k_free(key_consumer);
454 /* -}{----------------------------------------------------------------------- */
456 EXPORT char* k_channel_name(char* type, char* ip, int port, char* other)
459 int bufsize=TMPBUFSIZE;
461 if(type) ln+=snprintf(tmpbuf+ln, bufsize-ln, "|%s|", type);
462 else ln+=snprintf(tmpbuf+ln, bufsize-ln, "|-|");
463 if(ln>=bufsize) return 0;
465 if(ip) ln+=snprintf(tmpbuf+ln, bufsize-ln, "%s|", ip);
466 else ln+=snprintf(tmpbuf+ln, bufsize-ln, "-|");
467 if(ln>=bufsize) return 0;
469 if(port) ln+=snprintf(tmpbuf+ln, bufsize-ln, "%d|", port);
470 else ln+=snprintf(tmpbuf+ln, bufsize-ln, "-|");
471 if(ln>=bufsize) return 0;
473 if(other) ln+=snprintf(tmpbuf+ln, bufsize-ln, "%s|", other);
474 else ln+=snprintf(tmpbuf+ln, bufsize-ln, "-|");
475 if(ln>=bufsize) return 0;
477 return k_strdup(tmpbuf);
480 EXPORT k_channel* k_channel_connect_name(char* chanm,
481 k_channel_event rdcallback,
482 k_channel_event wrcallback)
484 if(k_hashtable_get(connecting_chans, chanm)){
485 if(1) k_log_out("Already connecting to %s", chanm);
488 k_hashtable_set(connecting_chans, chanm, chanm);
491 char* t=k_strdup(chanm);
492 char* a=strchr(t+1, '|'); *a++=0;
493 char* p=strchr(a, '|'); *p++=0;
494 char* o=strchr(p, '|'); *o++=0;
497 if(strstr(t, "-client")){
498 chan=k_channel_connect(t, a, pi, rdcallback, wrcallback, 0);
499 if(!chan) k_log_err("couldn't connect to %s:%d", a, pi);
502 if(strstr(t, "-server") && *a=='-'){
503 chan=k_channel_listen(t, pi, 0, rdcallback, wrcallback, 0);
504 if(!chan) k_log_err("couldn't listen on port %d", pi);
507 if(strstr(t, "-server")){
508 chan=k_channel_connect(t, a, pi, rdcallback, wrcallback, 0);
509 if(!chan) k_log_err("couldn't connect to %s:%d", a, pi);
521 EXPORT k_channel* k_channel_get_name(char* chanm)
523 k_channel* chan=k_hashtable_get(current_chans, chanm);
527 EXPORT void k_channel_show_all()
529 k_log_out("----------------------------------------");
530 k_hashtable_show(connecting_chans);
531 k_log_out("----------------------------------------");
532 k_hashtable_show(current_chans);
533 k_log_out("----------------------------------------");
536 void gen_conn_name(k_channel* chan)
538 char* t=chan->name+1;
539 char* a=strchr(t, '|'); *a++=0;
540 char* p=strchr(a, '|'); *p++=0;
541 char* o=strchr(p, '|'); *o++=0;
542 char* ip=inet_ntoa(chan->clientip);
546 static long uniquenum;
547 snprintf(b, 32, "%ld", ++uniquenum);
548 chan->name=k_channel_name(t, ip, pi, b);
555 /* -------------------------------------------------------------------------- */
557 EXPORT k_channel* k_channel_listen(char* name,
560 k_channel_event rdcallback,
561 k_channel_event wrcallback,
564 SOCK_T s=make_listen_socket(listenport);
567 struct in_addr noclientip=EMPTY_IN_ADDR;
568 k_channel* chan=register_k_channel(name,
578 int r=listen_socket(s, listenport);
580 unregister_k_channel(chan,1);
586 EXPORT k_channel* k_channel_connect(char* name,
589 k_channel_event rdcallback,
590 k_channel_event wrcallback,
593 SOCK_T s=make_connect_socket();
596 struct in_addr noclientip=EMPTY_IN_ADDR;
597 k_channel* chan=register_k_channel(name,
607 int r=connect_socket(s, listenhost, listenport);
609 unregister_k_channel(chan,1);
615 EXPORT k_channel* k_channel_send(k_channel* chan,
620 append_to_wrbuffers(chan, base, size, free);
621 set_callback(chan, SETCB_WR);
625 EXPORT char* k_channel_chop_div(k_channel* chan, char* divider)
627 return chop_from_rdbuffer_div(chan, divider);
630 EXPORT char* k_channel_chop_len(k_channel* chan, size_t size)
632 return chop_from_rdbuffer_len(chan, size);
635 EXPORT int k_channel_setbuf(k_channel* chan, char* rdbuffer, size_t size)
637 return set_rdbuffer(chan, rdbuffer, size);
640 EXPORT char* k_channel_getbuf(k_channel* chan)
642 return get_rdbuffer(chan);
645 EXPORT void k_channel_close(k_channel* chan)
647 unregister_k_channel(chan,0);
650 k_channel* register_k_channel(char* name,
654 k_channel_event rdcallback,
655 k_channel_event wrcallback,
658 struct in_addr clientip,
662 chan=k_malloc(sizeof(k_channel));
665 chan->listenhost=listenhost;
666 chan->listenport=listenport;
668 chan->rdcallback=rdcallback;
669 chan->wrcallback=wrcallback;
670 chan->context=context;
672 chan->clientip=clientip;
675 chan->priv=k_malloc(sizeof(k_channel_priv));
677 chan->priv->state=CHAN_OPEN;
678 chan->priv->event=0; /* what is this for? */
679 chan->priv->rwmask=0; /* what is this for? */
680 chan->priv->rdbuffer=(char*)k_malloc(RDSIZE); /* 40K per connection??!! */
681 chan->priv->rdbufpos=0;
682 chan->priv->rdbufsize=RDSIZE;
683 chan->priv->rdbufforeign=0;
684 chan->priv->wrbuffers=(wrbuffer*)k_malloc(WRSIZE*sizeof(wrbuffer));
685 chan->priv->wrbufpos=0;
686 chan->priv->wrbufsize=WRSIZE;
687 chan->priv->lingercount=LINGER_LOOPS;
690 set_callback(chan, SETCB_RD);
692 if(chan->listenhost){
693 set_callback(chan, SETCB_WR);
696 chan->next=k_channels;
702 void unregister_k_channel(k_channel* chan, int now)
704 int closing=CHAN_CLOSING(chan);
705 if(closing && !now) return;
706 int linger=chan->linger && !now;
707 chan->priv->state=linger? CHAN_LINGER: CHAN_CLOSE;
708 if(linger) un_set_callback(chan, SETCB_WR);
709 else un_set_callback(chan, SETCB_WR | SETCB_RD);
712 if(chan->rdcallback)(*chan->rdcallback)(chan, chan->priv->rdbufpos, -1);
714 if(chan->wrcallback)(*chan->wrcallback)(chan, chan->priv->wrbufpos, -1);
717 void chan_closed(k_channel* chan)
719 if(0) k_log_out("chan_closed %s", chan->name);
720 k_hashtable_remove(connecting_chans, chan->name);
721 k_hashtable_remove(current_chans, chan->name);
722 if(0) k_channel_show_all();
725 void do_regular_things(void)
728 remove_dead_k_channels();
731 void tick_modules(void)
734 for(i=0; i< nextmodule; i++){
735 k_module_tick_fn tf=modules[i].tick_fn;
740 void remove_dead_k_channels(void)
745 k_channel* cc=k_channels;
748 if( cc->priv->state==CHAN_CLOSE ||
749 (cc->priv->state==CHAN_LINGER && !cc->priv->lingercount--)){
750 un_set_callback(cc, SETCB_WR | SETCB_RD);
751 if(!cp) k_channels=cn;
753 SOCKET_CLOSE(cc->priv->SOCK);
754 for(i=0; i< cc->priv->wrbufpos; i++){
755 k_free(cc->priv->wrbuffers[i].free);
757 k_free(cc->priv->wrbuffers);
758 k_free(cc->priv->rdbuffer);
768 k_channel* find_k_channel_for_socket(SOCK_T s)
771 for(chan=k_channels; chan; chan=chan->next){
772 if(chan->priv->SOCK==s) break;
777 void show_open_channels(void)
779 k_channel* chan=k_channels;
781 if(chan->priv->state==CHAN_OPEN ){
782 if(0) k_log_out("chan open %x", chan->priv->SOCK);
784 if(chan->priv->state==CHAN_LINGER){
785 if(0) k_log_out("chan lingering %x", chan->priv->SOCK);
787 if(chan->priv->state==CHAN_CLOSE ){
788 if(0) k_log_out("chan closed %x", chan->priv->SOCK);
794 void readable_socket(k_channel* chan)
796 if(chan->type==CHAN_LISTEN){
797 register_connections(chan);
800 read_more_and_notify(chan);
804 void writeable_socket(k_channel* chan)
806 write_more_and_notify(chan);
809 void exception_socket(k_channel* chan)
811 if(0) k_log_out("exception_socket");
812 unregister_k_channel(chan,1);
815 void register_connections(k_channel* chan)
817 SOCK_T as=chan->priv->SOCK;
818 struct sockaddr_in iaddr;
819 struct sockaddr* iaddrp=(struct sockaddr*)&iaddr;
820 socklen_t size=sizeof(struct sockaddr_in);
823 int r=ACCEPT(as, iaddrp, &size, s);
826 if(ERRNO==INTERRUPTED) break;
827 if(ISNOTACTIVE(ERRNO)) break;
828 log_net_err("accept", ERRNO);
835 SOCKET_WRITE(s, chan->banner, strlen(chan->banner));
838 k_channel* chann=register_k_channel(chan->name,
848 gen_conn_name(chann);
849 k_hashtable_set(current_chans, chann->name, chann);
850 if(chann->rdcallback) (*chann->rdcallback)(chann, 0, 0);
854 void read_more_and_notify(k_channel* chan)
856 int pos=chan->priv->rdbufpos;
857 int size=SOCKET_READ(chan->priv->SOCK,
858 chan->priv->rdbuffer +pos,
859 chan->priv->rdbufsize-pos);
861 if(size==0){ size= -1; ERRNO=EPIPE; }
863 if(ERRNO==INTERRUPTED) return;
864 if(ISNOTACTIVE(ERRNO)) return;
865 log_net_err("socket_read", ERRNO);
866 unregister_k_channel(chan,1);
869 if(CHAN_CLOSING(chan)) return;
871 chan->priv->rdbufpos+=size;
873 if(chan->rdcallback){
874 (*chan->rdcallback)(chan, chan->priv->rdbufpos, size);
877 if(chan->priv->rdbufpos==chan->priv->rdbufsize){
878 if(chan->priv->rdbufforeign){
879 k_log_err("Run out of room in given buffer");
880 k_log_err("rdbufsize=%d", chan->priv->rdbufsize);
881 unregister_k_channel(chan,1);
884 chan->priv->rdbufsize*=2;
885 chan->priv->rdbuffer=k_realloc(chan->priv->rdbuffer,
886 chan->priv->rdbufsize);
887 if(0) k_log_out("rdbufsize=%d", chan->priv->rdbufsize);
888 // DoS vulnerability unless buffer size limited
892 void write_more_and_notify(k_channel* chan)
894 if(!chan->priv->wrbufpos){
896 k_hashtable_remove(connecting_chans, chan->name);
897 k_hashtable_set( current_chans, chan->name, chan);
899 if(chan->wrcallback) (*chan->wrcallback)(chan, 0, 0);
900 if(!chan->priv->wrbufpos) un_set_callback(chan, SETCB_WR); // Eerrk?
904 int writemax=MIN(WRITEMAX, chan->priv->wrbuffers[0].size);
905 int size=SOCKET_WRITE(chan->priv->SOCK,
906 chan->priv->wrbuffers[0].base,
909 if(size==0){ size= -1; ERRNO=NOTACTIVE; }
911 if(ERRNO==INTERRUPTED) return;
912 if(ISNOTACTIVE(ERRNO)) return;
913 log_net_err("socket_write", ERRNO);
914 unregister_k_channel(chan,1);
918 chop_from_wrbuffers(chan, size);
920 if(chan->wrcallback){
921 (*chan->wrcallback)(chan, chan->priv->wrbufpos, size);
924 if(!chan->priv->wrbufpos) un_set_callback(chan, SETCB_WR);
927 char* strnstr(char* haystack, size_t size, char* needle) // Errk!
929 if(!needle || !*needle) return haystack;
931 char* e=haystack+size;
932 for(h=haystack; h < e && *h; h++){
935 while(i < e && *i && *n && *i==*n){ i++; n++; }
941 char* chop_from_rdbuffer_div(k_channel* chan, char* divider)
943 char* s=strnstr(chan->priv->rdbuffer, chan->priv->rdbufpos, divider);
946 size_t size=(s+1 - chan->priv->rdbuffer);
948 char* chunk=k_memdup(chan->priv->rdbuffer, size);
949 char* e=chan->priv->rdbuffer+chan->priv->rdbufpos;
950 memmove(chan->priv->rdbuffer, s, e-s);
951 chan->priv->rdbufpos=e-s;
955 char* chop_from_rdbuffer_len(k_channel* chan, size_t size)
957 if(!size || size > chan->priv->rdbufpos) return 0;
958 char* chunk=k_memdup(chan->priv->rdbuffer, size);
959 char* s=chan->priv->rdbuffer+size;
960 char* e=chan->priv->rdbuffer+chan->priv->rdbufpos;
961 memmove(chan->priv->rdbuffer, s, e-s);
962 chan->priv->rdbufpos=e-s;
966 int set_rdbuffer(k_channel* chan, char* rdbuffer, size_t size)
968 if(chan->priv->rdbufforeign) return BUFFER_ALREADY_SET;
969 size_t pos=chan->priv->rdbufpos;
971 memcpy(rdbuffer, chan->priv->rdbuffer, size);
972 char* s=chan->priv->rdbuffer+size;
973 char* e=chan->priv->rdbuffer+pos;
974 memmove(chan->priv->rdbuffer, s, e-s);
975 chan->priv->rdbufpos=e-s;
976 return BUFFER_FILLED;
978 memcpy(rdbuffer, chan->priv->rdbuffer, pos);
979 k_free(chan->priv->rdbuffer);
980 chan->priv->rdbuffer=rdbuffer;
981 chan->priv->rdbufsize=size;
982 chan->priv->rdbufforeign=1;
986 char* get_rdbuffer(k_channel* chan)
988 if(!chan->priv->rdbufforeign) return 0;
989 char* rdbuffer=chan->priv->rdbuffer;
990 chan->priv->rdbuffer=(char*)k_malloc(RDSIZE);
991 chan->priv->rdbufpos=0;
992 chan->priv->rdbufsize=RDSIZE;
993 chan->priv->rdbufforeign=0;
997 void append_to_wrbuffers(k_channel* chan, char* base, size_t size, int free)
999 if(chan->priv->wrbufpos==chan->priv->wrbufsize){
1000 chan->priv->wrbufsize*=2;
1001 chan->priv->wrbuffers=k_realloc(chan->priv->wrbuffers,
1002 chan->priv->wrbufsize *
1004 if(0) k_log_out("wrbufsize=%d", chan->priv->wrbufsize);
1006 chan->priv->wrbuffers[chan->priv->wrbufpos].base=base;
1007 chan->priv->wrbuffers[chan->priv->wrbufpos].size=size;
1008 chan->priv->wrbuffers[chan->priv->wrbufpos].free=free? base: 0;
1009 chan->priv->wrbufpos++;
1012 void chop_from_wrbuffers(k_channel* chan, size_t size)
1014 if(chan->priv->wrbuffers[0].size != size){
1015 chan->priv->wrbuffers[0].base+=size;
1016 chan->priv->wrbuffers[0].size-=size;
1019 k_free(chan->priv->wrbuffers[0].free);
1020 chan->priv->wrbufpos--;
1022 for(i=0; i< chan->priv->wrbufpos; i++){
1023 chan->priv->wrbuffers[i]=chan->priv->wrbuffers[i+1];
1028 /* -------------------------------------------------------------------------- */
1030 SOCK_T make_listen_socket(int listenport)
1033 int r=SOCKET(AF_INET, SOCK_STREAM, IPPROTO_TCP, s);
1036 log_net_err("socket", ERRNO);
1039 SET_NON_BLOCKING(s);
1042 struct sockaddr_in iaddr;
1043 struct sockaddr* iaddrp=(struct sockaddr*)&iaddr;
1044 iaddr=make_sockaddr_in(INADDR_ANY, listenport);
1046 r=BIND(s, iaddrp, sizeof(iaddr));
1049 log_net_err("bind", ERRNO);
1057 SOCK_T make_connect_socket(void)
1060 int r=SOCKET(AF_INET, SOCK_STREAM, IPPROTO_TCP, s);
1063 log_net_err("socket", ERRNO);
1066 SET_NON_BLOCKING(s);
1071 int listen_socket(SOCK_T s, int listenport)
1073 if(0) k_log_out("Listening on port %d", listenport);
1074 int r=LISTEN(s, 128);
1077 log_net_err("listen", ERRNO);
1084 int connect_socket(SOCK_T s, char* listenhost, int listenport)
1086 if(0) k_log_out("Hanging on gethostbyname for %s", listenhost);
1087 struct hostent* hostaddr=gethostbyname(listenhost);
1093 struct sockaddr_in iaddr;
1094 struct sockaddr* iaddrp=(struct sockaddr*)&iaddr;
1095 iaddr=make_sockaddr_in(0, listenport);
1096 memcpy(&iaddr.sin_addr, hostaddr->h_addr, hostaddr->h_length);
1098 if(0) k_log_out("Connect: %s(%s):%d ",
1099 listenhost, inet_ntoa(iaddr.sin_addr), listenport);
1101 int r=CONNECT(s, iaddrp, sizeof(iaddr));
1103 if(r== -1 && ERRNO==INTERRUPTED) continue;
1104 if(r== -1 && !ISCONNECTING(ERRNO)){
1105 log_net_err("connect", ERRNO);
1115 SOCK_T make_udp_listen_socket(int listenport)
1119 struct sockaddr_in iaddr;
1120 struct sockaddr* iaddrp=(struct sockaddr*)&iaddr;
1122 r=SOCKET(AF_INET, SOCK_DGRAM, IPPROTO_UDP, s);
1125 log_net_err("socket", ERRNO);
1131 iaddr=make_sockaddr_in(INADDR_ANY, listenport);
1133 r=BIND(s, iaddrp, sizeof(iaddr));
1136 log_net_err("bind", ERRNO);
1144 EXPORT SOCK_T make_udp_send_socket(char* listenhost, int listenport)
1148 struct sockaddr_in iaddr;
1149 struct sockaddr* iaddrp=(struct sockaddr*)&iaddr;
1151 r=SOCKET(AF_INET, SOCK_DGRAM, IPPROTO_UDP, s);
1154 log_net_err("socket", ERRNO);
1158 struct hostent* hostaddr=gethostbyname(listenhost);
1160 log_net_err("gethostbyname", h_errno);
1165 iaddr=make_sockaddr_in(0, listenport);
1166 memcpy(&iaddr.sin_addr, hostaddr->h_addr, hostaddr->h_length);
1168 r=CONNECT(s, iaddrp, sizeof(iaddr));
1171 log_net_err("connect", ERRNO);
1179 struct sockaddr_in make_sockaddr_in(unsigned long address, unsigned int port)
1181 struct sockaddr_in iaddr;
1182 struct sockaddr* iaddrp=(struct sockaddr*)&iaddr;
1183 memset(iaddrp, 0, sizeof(iaddr));
1184 iaddr.sin_addr.s_addr=htonl(address);
1185 iaddr.sin_port =htons(port);
1186 iaddrp->sa_family=AF_INET;
1190 void log_net_err(char* where, int e)
1192 if(0) k_log_out("Network (%s): %s (%d)", where, str_error(e), e);
1195 /* -------------------------------------------------------------------------- */
1197 EXPORT void k_file_stat(char* basedir,
1199 k_file_event callback,
1202 snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", basedir, filename);
1203 char* fullname=tmpbuf;
1205 k_stat kstat={0,0,0,0};
1207 stat_only(fullname, &kstat);
1208 (*callback)(basedir, filename, 0, 0, kstat, context);
1211 EXPORT void k_file_read(char* basedir,
1215 k_file_event callback,
1218 snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", basedir, filename);
1219 char* fullname=tmpbuf;
1222 k_stat kstat={0,0,0,0};
1225 if(write && !ensure_dir(fullname)){
1226 (*callback)(basedir, filename, 0, 0, kstat, context);
1230 stat_only(fullname, &kstat);
1231 if(!kstat.type && !write){
1232 (*callback)(basedir, filename, 0, 0, kstat, context);
1235 filehandle=open_only(fullname, write);
1237 (*callback)(basedir, filename, 0, 0, kstat, context);
1240 if(!kstat.type || (write && kstat.size!=size)){
1241 if(ftruncate(filehandle, size)){
1243 (*callback)(basedir, filename, 0, 0, kstat, context);
1249 if(!write) size=kstat.size;
1250 else kstat.size=size;
1252 if(size>MAX_FILESIZE){
1253 (*callback)(basedir, filename, 0, 0, kstat, context);
1256 int dommap=(size >= mmapsize);
1258 int prot=(write? PROT_WRITE: 0)|PROT_READ;
1262 if(size==0) data=dommap? dummy_empty_data: k_malloc(1);
1264 if(dommap) data=mmap_name( 0, size, prot, MAP_SHARED, fullname, 0);
1265 else data=mmap_malloc(0, size, prot, MAP_SHARED, fullname, 0);
1267 if(data==MAP_FAILED){
1268 (*callback)(basedir, filename, 0, 0, kstat, context);
1271 (*callback)(basedir, filename, data, dommap, kstat, context);
1274 EXPORT int k_file_sync(char* data, size_t size)
1276 int r=msync(data, size, MS_ASYNC);
1280 EXPORT void k_file_write(char* basedir,
1284 k_file_event callback,
1287 snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", basedir, filename);
1288 char* fullname=tmpbuf;
1291 k_stat kstat={0,0,0,0};
1293 if(!ensure_dir(fullname)){
1294 (*callback)(basedir, filename, 0, 0, kstat, context);
1298 filehandle=open_only(fullname, 1);
1300 (*callback)(basedir, filename, 0, 0, kstat, context);
1303 if(datalength!=0) kstat.size=WRITEFILE(filehandle, data, datalength);
1304 if(kstat.size== -1){
1306 (*callback)(basedir, filename, 0, 0, kstat, context);
1310 (*callback)(basedir, filename, data, 0, kstat, context);
1313 EXPORT void k_dir_list(char* basedir,
1317 k_file_event callback,
1320 snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", basedir, dirname);
1321 char* fullname=k_strdup(tmpbuf);
1323 k_stat kstat={ STAT_D, 0, 0, 0 };
1325 int size=TMPBUFSIZE;
1327 for(i=0; format[i]; i++){
1328 int n=dir_list(buf, size, fullname, pattern[i], format[i]);
1330 (*callback)(basedir, dirname, 0, 0, kstat, context);
1336 kstat.size=TMPBUFSIZE-size;
1337 (*callback)(basedir, dirname, k_strdup(tmpbuf), 0, kstat, context);
1341 int dir_list(char* buf, int size, char* fullname, char* pattern, char* format)
1343 DIR* d=opendir(fullname);
1350 while((de=readdir(d))){
1352 char* name=de->d_name;
1353 if(*name=='.') continue;
1355 if(pattern && *pattern &&
1356 !k_string_matches_pattern(name, pattern)) continue;
1358 int n=snprintf(b, s, format, name, name, name, name, name);
1359 if(n< 0 || n>=s){ closedir(d); return -1; }
1366 int ensure_dir(char* fullname)
1368 char* e=strrchr(fullname, '/');
1371 k_stat kstat={0,0,0,0};
1372 stat_only(fullname, &kstat);
1373 if(kstat.type!=STAT_D){
1375 stat_only(fullname, &kstat);
1378 return kstat.type==STAT_D;
1381 /* -------------------------------------------------------------------------- */
1383 EXPORT int k_string_matches_pattern(char* string, char* pattern)
1386 strncpy(patt, pattern, 32);
1392 char* e=strpbrk(pattern, ",}");
1395 if(k_string_matches_pattern(string, pattern)) return 1;
1403 return k_string_ends_with(string, pattern);
1408 EXPORT int k_string_ends_with(char* string, char* postfix)
1410 char* i=string+strlen(string)-strlen(postfix);
1411 if(i<string) return 0;
1412 return !strcmp(i, postfix);
1415 EXPORT void k_string_url_decode(char* s)
1419 if(s[0]=='%' && isxdigit(s[1]) && isxdigit(s[2])){
1420 *t=hex_to_int(s[1])*16+hex_to_int(s[2]);
1431 char hex_to_int(char c)
1434 (c >= '0' && c <= '9')? c-'0':
1435 (c >= 'A' && c <= 'F')? c-'A'+10:
1436 (c >= 'a' && c <= 'f')? c-'a'+10: 0;
1439 /* -------------------------------------------------------------------------- */
1441 EXPORT void k_log_out(char* format, ...)
1444 va_start(ap, format);
1446 VPRINTFOUT(format,ap);
1451 vsnprintf(logbuf, LOGBUFSIZE,format,ap);
1452 *(logbuf+LOGBUFSIZE-2)='\n';
1453 *(logbuf+LOGBUFSIZE-1)=0;
1454 write_to_logfile_cern_style(logbuf,0);
1459 EXPORT void k_log_err(char* format, ...)
1462 va_start(ap, format);
1464 VPRINTFERR(format,ap);
1469 vsnprintf(logbuf, LOGBUFSIZE,format,ap);
1470 *(logbuf+LOGBUFSIZE-2)='\n';
1471 *(logbuf+LOGBUFSIZE-1)=0;
1472 write_to_logfile_cern_style(logbuf,1);
1477 EXPORT void k_fatal(char* format, ...)
1480 va_start(ap, format);
1481 k_log_out(format, ap);
1483 k_log_out("Terminating Cilux");
1484 k_log_out("---------------------");
1488 void write_to_logfile_cern_style(char* text, int error)
1490 if(!logfile) return;
1504 if(z >=0){ sgn='+'; }
1505 else{ sgn='-'; z= -z; }
1509 strftime(cern, sizeof(cern), CERNDATE, tm);
1511 snprintf(date, sizeof(date), "%s %c%02d%02d", cern, sgn, z/60, z%60);
1513 snprintf(date, sizeof(date), "%s", cern);
1515 FPRINTF(logfile, "[%s|%s] %s%s\n", date, k_ciux,
1516 error? "Warning: ": "", text);
1520 /* -------------------------------------------------------------------------- */
1522 #define EXAMPLE_DATE Fri, 04 Feb 2005 12:14:48 GMT
1523 #define RFC1123STRF "%a, %d %b %Y %H:%M:%S GMT"
1524 #define RFC1123SSCANF "%3s, %d %3s %4d %2d:%2d:%2d GMT"
1528 EXPORT char* k_time_to_rfc(time_t t)
1530 strftime(b, sizeof(b), RFC1123STRF, gmtime(&t));
1534 EXPORT char* k_time_to_rfc_relative(int plus)
1536 time_t t=time(0)+plus;
1537 strftime(b, sizeof(b), RFC1123STRF, gmtime(&t));
1541 EXPORT time_t k_time_from_rfc(char* s)
1543 if(!s || strlen(s)!=29) return -1;
1544 struct tm tm; tm.tm_wday=0; tm.tm_yday=0; tm.tm_isdst=0;
1545 char wd[32], mn[32];
1546 int r=sscanf(s, RFC1123SSCANF, wd, &tm.tm_mday, mn, &tm.tm_year,
1547 &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
1549 tm.tm_mon=(int)k_hashtable_get(monthhash, mn);
1550 if(tm.tm_mon) tm.tm_mon -=1;
1555 EXPORT void k_time_get_now(char* buf, size_t size, char* format)
1566 strftime(buf, size, format, tm);
1569 /* -------------------------------------------------------------------------- */
1571 typedef struct hash_item hash_item;
1573 typedef struct hashtable{ struct hashtable* next;
1581 struct hash_item{ hash_item* next;
1588 /* -------------------------------------------------------------------------- */
1590 #define STRCMPCASE(tab, listkey, key)\
1591 ((tab)->ignorecase? strcasecmp((listkey), (key)): strcmp((listkey), (key)))
1593 #define WARN_SIZE(h)\
1594 if((h)->size && !((h)->size % BX)) k_log_out("%s# %d", (h)->name, (h)->size);
1596 EXPORT k_hashtable* k_hashtable_new(char* name, int ignorecase)
1599 tab=k_malloc(sizeof(hashtable));
1603 tab->lists=k_malloc((tab->buckets)*sizeof(hash_item*));
1604 tab->ignorecase=ignorecase;
1606 int i; for(i=0; i< tab->buckets; i++) tab->lists[i]=0;
1607 return (k_hashtable*)tab;
1610 k_hashtable* k_hashtable_dup2(k_hashtable* tab, int deep)
1613 hashtable* tah=(hashtable*)tab;
1615 tad=k_malloc(sizeof(hashtable));
1616 tad->name=tah->name;
1617 tad->buckets=tah->buckets;
1618 tad->size=tah->size;
1619 tad->lists=k_malloc((tah->buckets)*sizeof(hash_item*));
1620 tad->ignorecase=tah->ignorecase;
1625 for(i=0; i< tah->buckets; i++){
1626 for(lisp=&tah->lists[i], lisd=&tad->lists[i];
1628 lisp=&(*lisp)->next, lisd=&(*lisd)->next){
1630 (*lisd)=k_malloc(sizeof(hash_item));
1631 (*lisd)->key=k_strdup((*lisp)->key);
1636 (*lisd)->val=k_strdup((*lisp)->val);
1639 if(deep && (*lisp)->sub){
1640 (*lisd)->sub=k_hashtable_dup2((*lisp)->sub, 1);
1642 if(!(*lisd)->val && !(*lisd)->sub){
1648 tad->next=(hashtable*)k_hashtable_dup2(tab->next, deep);
1649 return (k_hashtable*)tad;
1652 EXPORT k_hashtable* k_hashtable_dup(k_hashtable* tab)
1654 return k_hashtable_dup2(tab, 0);
1657 EXPORT k_hashtable* k_hashtable_deep(k_hashtable* tab)
1659 return k_hashtable_dup2(tab, 1);
1662 EXPORT k_hashtable* k_hashtable_dip(k_hashtable* tab, char* includes[])
1665 hashtable* tah=(hashtable*)tab;
1667 tad=(hashtable*)k_hashtable_new(tah->name, tah->ignorecase);
1669 for(i=0; includes[i]; i++){
1670 char* in=k_hashtable_get((k_hashtable*)tah, includes[i]);
1673 k_hashtable_put((k_hashtable*)tad, includes[i], in);
1675 tad->next=(hashtable*)k_hashtable_dip(tab->next, includes);
1676 return (k_hashtable*)tad;
1679 EXPORT void k_hashtable_merge(k_hashtable* tab, k_hashtable* tam)
1681 hashtable* tan=(hashtable*)tam;
1684 for(i=0; i< tan->buckets; i++){
1685 for(lisp=&tan->lists[i]; (*lisp); lisp=&(*lisp)->next){
1686 char* key =(*lisp)->key;
1687 void* val =(*lisp)->val;
1688 int free=(*lisp)->free;
1689 k_hashtable* sub =(*lisp)->sub;
1690 if(!*key && free) continue;
1692 k_hashtable_put(tab, key, k_strdup(val));
1695 k_hashtable_sub(tab, key, k_hashtable_dup(sub));
1701 void k_hashtable_set_put(k_hashtable* tab, char* key, void* val, int free)
1703 if(!(tab && key && val)) return;
1704 hashtable* tah=(hashtable*)tab;
1706 lisp=&tah->lists[string_hash(key) % tah->buckets];
1707 while((*lisp) && STRCMPCASE(tah, (*lisp)->key, key)){
1708 lisp=&(*lisp)->next;
1711 (*lisp)=k_malloc(sizeof(hash_item));
1712 (*lisp)->key=k_strdup(key);
1721 if((*lisp)->free) k_free((*lisp)->val);
1722 k_hashtable_delete((*lisp)->sub);
1729 EXPORT void k_hashtable_set(k_hashtable* tab, char* key, void* val)
1731 k_hashtable_set_put(tab, key, val, 0);
1734 EXPORT void k_hashtable_put_int(k_hashtable* tab, char* key, int val)
1736 snprintf(tmpbuf, TMPBUFSIZE, "%d", val);
1737 k_hashtable_set_put(tab, key, k_strdup(tmpbuf), 1);
1740 EXPORT void k_hashtable_put(k_hashtable* tab, char* key, void* val)
1742 k_hashtable_set_put(tab, key, val, 1);
1745 EXPORT void k_hashtable_put_dup(k_hashtable* tab, char* key, char* val)
1747 k_hashtable_set_put(tab, key, k_strdup(val), 1);
1750 EXPORT void k_hashtable_sub(k_hashtable* tab, char* key, k_hashtable* sub)
1752 if(!(tab && key && sub)) return;
1754 hashtable* tah=(hashtable*)tab;
1756 lisp=&tah->lists[string_hash(key) % tah->buckets];
1757 while((*lisp) && STRCMPCASE(tah, (*lisp)->key, key)){
1758 lisp=&(*lisp)->next;
1761 (*lisp)=k_malloc(sizeof(hash_item));
1762 (*lisp)->key=k_strdup(key);
1771 k_hashtable* val =(*lisp)->val;
1772 k_hashtable* head=(*lisp)->sub;
1774 if(val) k_log_err("key '%s' in use: no sub!", key);
1775 else (*lisp)->sub=sub;
1778 while(head->next) head=head->next;
1784 EXPORT void* k_hashtable_get(k_hashtable* tab, char* key)
1786 if(!(tab && key)) return 0;
1787 hashtable* tah=(hashtable*)tab;
1789 list=tah->lists[string_hash(key) % tah->buckets];
1790 while(list && STRCMPCASE(tah, list->key, key)){
1793 return list? (list->val? list->val: list->sub): 0;
1796 EXPORT int k_hashtable_get_int(k_hashtable* tab, char* key)
1798 char* val=k_hashtable_get(tab, key);
1799 return val? atoi(val): 0;
1802 EXPORT char* k_hashtable_get_dup(k_hashtable* tab, char* key)
1804 char* v=k_hashtable_get(tab, key);
1808 EXPORT int k_hashtable_is(k_hashtable* tab, char* key, char* val)
1810 char* v=k_hashtable_get(tab, key);
1811 return (v && val && !strcmp(v, val));
1814 EXPORT int k_hashtable_isi(k_hashtable* tab, char* key, char* val)
1816 char* v=k_hashtable_get(tab, key);
1817 return (v && val && !strcasecmp(v, val));
1820 EXPORT int k_hashtable_isn(k_hashtable* tab, char* key, char* val, size_t size)
1822 char* v=k_hashtable_get(tab, key);
1823 return (v && val && !strncmp(v, val, size));
1826 EXPORT void* k_hashtable_extract(k_hashtable* tab, char* key)
1828 hashtable* tah=(hashtable*)tab;
1831 lisp=&tah->lists[string_hash(key) % tah->buckets];
1832 while((*lisp) && STRCMPCASE(tah, (*lisp)->key, key)){
1833 lisp=&(*lisp)->next;
1837 next= (*lisp)->next;
1838 k_free((*lisp)->key);
1840 if(!val) val=(*lisp)->sub;
1849 EXPORT void k_hashtable_remove(k_hashtable* tab, char* key)
1851 hashtable* tah=(hashtable*)tab;
1854 lisp=&tah->lists[string_hash(key) % tah->buckets];
1855 while((*lisp) && STRCMPCASE(tah, (*lisp)->key, key)){
1856 lisp=&(*lisp)->next;
1859 next= (*lisp)->next;
1860 k_free((*lisp)->key);
1861 if((*lisp)->free) k_free((*lisp)->val);
1862 k_hashtable_delete((*lisp)->sub);
1870 EXPORT void k_hashtable_delete(k_hashtable* tab)
1873 hashtable* tah=(hashtable*)tab;
1877 for(i=0; i< tah->buckets; i++){
1882 if(list->free) k_free(list->val);
1883 k_hashtable_delete(list->sub);
1889 k_hashtable_delete((k_hashtable*)tah->next);
1893 EXPORT void k_hashtable_apply(k_hashtable* tab,
1894 k_hashtable_apply_fn fn,
1898 hashtable* tah=(hashtable*)tab;
1901 for(i=0; i< tah->buckets; i++){
1902 for(lisp=&tah->lists[i]; (*lisp); lisp=&(*lisp)->next){
1904 (*fn)(arg, (*lisp)->key, (*lisp)->val);
1907 (*fn)(arg, (*lisp)->key, (*lisp)->sub);
1913 void k_hashtable_show2(k_hashtable* tab, int chars)
1916 hashtable* tah=(hashtable*)tab;
1917 if(!chars) k_log_out("%s size=%d", tah->name, tah->size);
1920 for(i=0; i< tah->buckets; i++){
1921 for(lisp=&tah->lists[i]; (*lisp); lisp=&(*lisp)->next){
1923 if(*((*lisp)->key)){
1925 (*lisp)->key, (char*)((*lisp)->val));
1929 k_log_out("buck %d key '%s' val %x sub %x",
1930 i, (*lisp)->key, (*lisp)->val, (*lisp)->sub);
1936 EXPORT void k_hashtable_show(k_hashtable* tab)
1938 k_hashtable_show2(tab,0);
1941 EXPORT void k_hashtable_show_chars(k_hashtable* tab)
1943 k_hashtable_show2(tab,1);
1946 int k_hashtable_snprintf_xi(k_hashtable* tab,
1953 if(!tab){ if(size) *buf=0; return 0; }
1956 hashtable* tah=(hashtable*)tab;
1962 for(i=0; i< tah->buckets; i++){
1963 for(lisp=&tah->lists[i]; (*lisp); lisp=&(*lisp)->next){
1964 if(!*((*lisp)->key)) continue;
1965 if(check_i((*lisp)->key, includes, tah->ignorecase)) continue;
1966 if(check_x((*lisp)->key, excludes, tah->ignorecase)) continue;
1969 n=snprintf(at, ln, "%s%s %s" CRLF, ind, (*lisp)->key,
1970 (char*)((*lisp)->val));
1972 if(n>=ln) return size;
1976 k_hashtable* sub=(*lisp)->sub;
1978 n=snprintf(at, ln, "%s%s" CRLF,
1981 if(n>=ln) return size;
1984 n=k_hashtable_snprintf_xi(sub, at, ln, 0, 0,
1987 if(n>=ln) return size;
1990 }while((sub=sub->next));
1997 EXPORT int k_hashtable_snprintf(k_hashtable* tab, char* buf, size_t size)
1999 return k_hashtable_snprintf_xi(tab, buf, size, 0, 0, 0);
2002 EXPORT int k_hashtable_snprintf_i(k_hashtable* tab,
2007 return k_hashtable_snprintf_xi(tab, buf, size, includes, 0, 0);
2010 EXPORT int k_hashtable_snprintf_x(k_hashtable* tab,
2015 return k_hashtable_snprintf_xi(tab, buf, size, 0, excludes, 0);
2018 int check_i(char* key, char* includes[], int ignorecase)
2020 if(!includes) return 0;
2022 for(e=0; includes[e]; e++){
2023 if(ignorecase? !strcasecmp(key, includes[e]):
2024 !strcmp( key, includes[e]) ) break;
2026 return !includes[e];
2029 int check_x(char* key, char* excludes[], int ignorecase)
2031 if(!excludes) return 0;
2033 for(e=0; excludes[e]; e++){
2034 if(ignorecase? !strcasecmp(key, excludes[e]):
2035 !strcmp( key, excludes[e]) ) break;
2037 return !!excludes[e];
2040 unsigned int string_hash(char* p)
2043 while(*p) h=(h<<5)-h+tolower(*p++);
2048 /* -------------------------------------------------------------------------- */