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");
203 k_log_out("---------------------------------------------");
208 EXPORT OTHER_THREAD void c_running(int r)
213 EXPORT OTHER_THREAD void c_key(unsigned char key, int down)
218 EXPORT OTHER_THREAD void c_signal(int signum)
220 k_log_out("Received signal %d", signum);
223 /* -------------------------------------------------------------------------- */
225 EXPORT void k_gl_register_reshape(k_gl_reshape_event callback){
229 EXPORT void k_gl_register_draw(k_gl_draw_event callback){
233 EXPORT void k_gl_register_key(k_gl_key_event callback){
237 /* -------------------------------------------------------------------------- */
239 void init_hashtables(void)
241 connecting_chans=k_hashtable_new("Connecting Channels", 0);
242 current_chans =k_hashtable_new("Current Channels", 0);
243 monthhash =k_hashtable_new("Months", 1);
244 k_hashtable_set(monthhash, "Jan", (void*)1);
245 k_hashtable_set(monthhash, "Feb", (void*)2);
246 k_hashtable_set(monthhash, "Mar", (void*)3);
247 k_hashtable_set(monthhash, "Apr", (void*)4);
248 k_hashtable_set(monthhash, "May", (void*)5);
249 k_hashtable_set(monthhash, "Jun", (void*)6);
250 k_hashtable_set(monthhash, "Jul", (void*)7);
251 k_hashtable_set(monthhash, "Aug", (void*)8);
252 k_hashtable_set(monthhash, "Sep", (void*)9);
253 k_hashtable_set(monthhash, "Oct", (void*)10);
254 k_hashtable_set(monthhash, "Nov", (void*)11);
255 k_hashtable_set(monthhash, "Dec", (void*)12);
258 void init_logging(void)
260 snprintf(tmpbuf, TMPBUFSIZE, "%s.log", k_ciux);
261 logfile=FOPEN(tmpbuf, "a");
262 if(!logfile) k_log_err("couldn't open logfile %s", tmpbuf);
265 void init_modules(void)
267 char* patts[]={ "{*.dll,*.so}", 0};
268 char* temps[]={ "%s:", 0 };
269 k_dir_list(".", ".", patts, temps, dir_read, 0);
272 void dir_read(char* basedir,
281 if(!strncmp(data, MODPRE, strlen(MODPRE))){
282 k_ciux=k_strdup(data+strlen(MODPRE));
283 char* c=strchr(k_ciux, '.');
295 k_log_out("========================================");
297 load_module("ni", 0);
298 load_module("np", 0);
299 if(!is_np) load_module(k_ciux, 1);
301 k_log_out("========================================");
304 void load_module(char* name, int dot)
306 k_log_out("------------ %s --------------", name);
308 snprintf(dlname, 64, "%s%s%s%s", dot? "./": "", MODPRE, name, MODPOST);
309 MODULE module=DLOPEN(dlname);
311 k_module_loaded_fn loaded_fn=get_module_loaded_fn(name, module);
312 k_module_tick_fn tick_fn =get_module_tick_fn( name, module);
313 k_module_event_fn event_fn =get_module_event_fn( name, module);
314 if(loaded_fn && event_fn){
315 add_module_entry(name, tick_fn, event_fn);
318 else k_log_err("Couldn't load module %s (hooks)", dlname);
320 else k_log_err("Couldn't load module %s (dlopen) %s", dlname, DLERROR);
323 k_module_loaded_fn get_module_loaded_fn(char* name, MODULE module)
325 snprintf(tmpbuf, TMPBUFSIZE, "%s%s", name, NAME_OF_MODULE_LOADED_FN);
326 k_module_loaded_fn f=(k_module_loaded_fn)DLSYM(module, tmpbuf);
327 if(!f) k_log_err("no %s", tmpbuf);
331 k_module_tick_fn get_module_tick_fn(char* name, MODULE module)
333 snprintf(tmpbuf, TMPBUFSIZE, "%s%s", name, NAME_OF_MODULE_TICK_FN);
334 k_module_tick_fn f=(k_module_tick_fn)DLSYM(module, tmpbuf);
335 if(!f) k_log_err("no %s", tmpbuf);
339 k_module_event_fn get_module_event_fn(char* name, MODULE module)
341 snprintf(tmpbuf, TMPBUFSIZE, "%s%s", name, NAME_OF_MODULE_EVENT_FN);
342 k_module_event_fn f=(k_module_event_fn)DLSYM(module, tmpbuf);
343 if(!f) k_log_err("no %s", tmpbuf);
347 /* -------------------------------------------------------------------------- */
349 void add_module_entry(char* name,
350 k_module_tick_fn tick_fn,
351 k_module_event_fn event_fn)
353 if(nextmodule==MAX_MODULES){
354 k_fatal("Too many modules! Maximum %d", MAX_MODULES);
356 modules[nextmodule ].name =name;
357 modules[nextmodule ].tick_fn =tick_fn;
358 modules[nextmodule ].event_fn=event_fn;
359 modules[nextmodule++].queue =0;
362 event* event_new(void* data)
365 ev=k_malloc(sizeof(event));
371 EXPORT int k_event_post(char* module, void* data)
373 event* ev=event_new(data);
374 event** queue=get_module_queue(module);
376 k_log_err("k_event_post(%s): no such module", module);
379 if(!*queue) *queue=ev;
393 event** get_module_queue(char* name)
396 for(i=0; i< nextmodule; i++){
397 if(!strcmp(modules[i].name, name)) return &modules[i].queue;
405 for(i=0; i< nextmodule; i++){
406 for(j=0; modules[i].queue && j < MAX_EVENTS_PER_MODULE; j++){
407 event* event=modules[i].queue;
408 modules[i].queue=event->next;
410 (*modules[i].event_fn)(event->data);
414 for(i=0; i< nextmodule; i++){
415 if(modules[i].queue) return 1;
420 /* -------------------------------------------------------------------------- */
425 ke=k_malloc(sizeof(key_event));
433 OTHER_THREAD void got_key(unsigned char key, int down)
435 if(!key_producer) return;
437 ke=k_malloc(sizeof(key_event));
441 key_producer->next=ke;
447 while(key_consumer!=key_producer){
448 key_event* ke=key_consumer->next;
449 if(key_fn) (*key_fn)(ke->key, ke->down);
450 k_free(key_consumer);
455 /* -}{----------------------------------------------------------------------- */
457 EXPORT char* k_channel_name(char* type, char* ip, int port, char* other)
460 int bufsize=TMPBUFSIZE;
462 if(type) ln+=snprintf(tmpbuf+ln, bufsize-ln, "|%s|", type);
463 else ln+=snprintf(tmpbuf+ln, bufsize-ln, "|-|");
464 if(ln>=bufsize) return 0;
466 if(ip) ln+=snprintf(tmpbuf+ln, bufsize-ln, "%s|", ip);
467 else ln+=snprintf(tmpbuf+ln, bufsize-ln, "-|");
468 if(ln>=bufsize) return 0;
470 if(port) ln+=snprintf(tmpbuf+ln, bufsize-ln, "%d|", port);
471 else ln+=snprintf(tmpbuf+ln, bufsize-ln, "-|");
472 if(ln>=bufsize) return 0;
474 if(other) ln+=snprintf(tmpbuf+ln, bufsize-ln, "%s|", other);
475 else ln+=snprintf(tmpbuf+ln, bufsize-ln, "-|");
476 if(ln>=bufsize) return 0;
478 return k_strdup(tmpbuf);
481 EXPORT k_channel* k_channel_connect_name(char* chanm,
482 k_channel_event rdcallback,
483 k_channel_event wrcallback)
485 if(k_hashtable_get(connecting_chans, chanm)){
486 if(1) k_log_out("Already connecting to %s", chanm);
489 k_hashtable_set(connecting_chans, chanm, chanm);
492 char* t=k_strdup(chanm);
493 char* a=strchr(t+1, '|'); *a++=0;
494 char* p=strchr(a, '|'); *p++=0;
495 char* o=strchr(p, '|'); *o++=0;
498 if(strstr(t, "-client")){
499 chan=k_channel_connect(t, a, pi, rdcallback, wrcallback, 0);
500 if(!chan) k_log_err("couldn't connect to %s:%d", a, pi);
503 if(strstr(t, "-server") && *a=='-'){
504 chan=k_channel_listen(t, pi, 0, rdcallback, wrcallback, 0);
505 if(!chan) k_log_err("couldn't listen on port %d", pi);
508 if(strstr(t, "-server")){
509 chan=k_channel_connect(t, a, pi, rdcallback, wrcallback, 0);
510 if(!chan) k_log_err("couldn't connect to %s:%d", a, pi);
522 EXPORT k_channel* k_channel_get_name(char* chanm)
524 k_channel* chan=k_hashtable_get(current_chans, chanm);
528 EXPORT void k_channel_show_all()
530 k_log_out("----------------------------------------");
531 k_hashtable_show(connecting_chans);
532 k_log_out("----------------------------------------");
533 k_hashtable_show(current_chans);
534 k_log_out("----------------------------------------");
537 void gen_conn_name(k_channel* chan)
539 char* t=chan->name+1;
540 char* a=strchr(t, '|'); *a++=0;
541 char* p=strchr(a, '|'); *p++=0;
542 char* o=strchr(p, '|'); *o++=0;
543 char* ip=inet_ntoa(chan->clientip);
547 static long uniquenum;
548 snprintf(b, 32, "%ld", ++uniquenum);
549 chan->name=k_channel_name(t, ip, pi, b);
556 /* -------------------------------------------------------------------------- */
558 EXPORT k_channel* k_channel_listen(char* name,
561 k_channel_event rdcallback,
562 k_channel_event wrcallback,
565 SOCK_T s=make_listen_socket(listenport);
568 struct in_addr noclientip=EMPTY_IN_ADDR;
569 k_channel* chan=register_k_channel(name,
579 int r=listen_socket(s, listenport);
581 unregister_k_channel(chan,1);
587 EXPORT k_channel* k_channel_connect(char* name,
590 k_channel_event rdcallback,
591 k_channel_event wrcallback,
594 SOCK_T s=make_connect_socket();
597 struct in_addr noclientip=EMPTY_IN_ADDR;
598 k_channel* chan=register_k_channel(name,
608 int r=connect_socket(s, listenhost, listenport);
610 unregister_k_channel(chan,1);
616 EXPORT k_channel* k_channel_send(k_channel* chan,
621 append_to_wrbuffers(chan, base, size, free);
622 set_callback(chan, SETCB_WR);
626 EXPORT char* k_channel_chop_div(k_channel* chan, char* divider)
628 return chop_from_rdbuffer_div(chan, divider);
631 EXPORT char* k_channel_chop_len(k_channel* chan, size_t size)
633 return chop_from_rdbuffer_len(chan, size);
636 EXPORT int k_channel_setbuf(k_channel* chan, char* rdbuffer, size_t size)
638 return set_rdbuffer(chan, rdbuffer, size);
641 EXPORT char* k_channel_getbuf(k_channel* chan)
643 return get_rdbuffer(chan);
646 EXPORT void k_channel_close(k_channel* chan)
648 unregister_k_channel(chan,0);
651 k_channel* register_k_channel(char* name,
655 k_channel_event rdcallback,
656 k_channel_event wrcallback,
659 struct in_addr clientip,
663 chan=k_malloc(sizeof(k_channel));
666 chan->listenhost=listenhost;
667 chan->listenport=listenport;
669 chan->rdcallback=rdcallback;
670 chan->wrcallback=wrcallback;
671 chan->context=context;
673 chan->clientip=clientip;
676 chan->priv=k_malloc(sizeof(k_channel_priv));
678 chan->priv->state=CHAN_OPEN;
679 chan->priv->event=0; /* what is this for? */
680 chan->priv->rwmask=0; /* what is this for? */
681 chan->priv->rdbuffer=(char*)k_malloc(RDSIZE); /* 40K per connection??!! */
682 chan->priv->rdbufpos=0;
683 chan->priv->rdbufsize=RDSIZE;
684 chan->priv->rdbufforeign=0;
685 chan->priv->wrbuffers=(wrbuffer*)k_malloc(WRSIZE*sizeof(wrbuffer));
686 chan->priv->wrbufpos=0;
687 chan->priv->wrbufsize=WRSIZE;
688 chan->priv->lingercount=LINGER_LOOPS;
691 set_callback(chan, SETCB_RD);
693 if(chan->listenhost){
694 set_callback(chan, SETCB_WR);
697 chan->next=k_channels;
703 void unregister_k_channel(k_channel* chan, int now)
705 int closing=CHAN_CLOSING(chan);
706 if(closing && !now) return;
707 int linger=chan->linger && !now;
708 chan->priv->state=linger? CHAN_LINGER: CHAN_CLOSE;
709 if(linger) un_set_callback(chan, SETCB_WR);
710 else un_set_callback(chan, SETCB_WR | SETCB_RD);
713 if(chan->rdcallback)(*chan->rdcallback)(chan, chan->priv->rdbufpos, -1);
715 if(chan->wrcallback)(*chan->wrcallback)(chan, chan->priv->wrbufpos, -1);
718 void chan_closed(k_channel* chan)
720 if(0) k_log_out("chan_closed %s", chan->name);
721 k_hashtable_remove(connecting_chans, chan->name);
722 k_hashtable_remove(current_chans, chan->name);
723 if(0) k_channel_show_all();
726 void do_regular_things(void)
729 remove_dead_k_channels();
732 void tick_modules(void)
735 for(i=0; i< nextmodule; i++){
736 k_module_tick_fn tf=modules[i].tick_fn;
741 void remove_dead_k_channels(void)
746 k_channel* cc=k_channels;
749 if( cc->priv->state==CHAN_CLOSE ||
750 (cc->priv->state==CHAN_LINGER && !cc->priv->lingercount--)){
751 un_set_callback(cc, SETCB_WR | SETCB_RD);
752 if(!cp) k_channels=cn;
754 SOCKET_CLOSE(cc->priv->SOCK);
755 for(i=0; i< cc->priv->wrbufpos; i++){
756 k_free(cc->priv->wrbuffers[i].free);
758 k_free(cc->priv->wrbuffers);
759 k_free(cc->priv->rdbuffer);
769 k_channel* find_k_channel_for_socket(SOCK_T s)
772 for(chan=k_channels; chan; chan=chan->next){
773 if(chan->priv->SOCK==s) break;
778 void show_open_channels(void)
780 k_channel* chan=k_channels;
782 if(chan->priv->state==CHAN_OPEN ){
783 if(0) k_log_out("chan open %x", chan->priv->SOCK);
785 if(chan->priv->state==CHAN_LINGER){
786 if(0) k_log_out("chan lingering %x", chan->priv->SOCK);
788 if(chan->priv->state==CHAN_CLOSE ){
789 if(0) k_log_out("chan closed %x", chan->priv->SOCK);
795 void readable_socket(k_channel* chan)
797 if(chan->type==CHAN_LISTEN){
798 register_connections(chan);
801 read_more_and_notify(chan);
805 void writeable_socket(k_channel* chan)
807 write_more_and_notify(chan);
810 void exception_socket(k_channel* chan)
812 if(0) k_log_out("exception_socket");
813 unregister_k_channel(chan,1);
816 void register_connections(k_channel* chan)
818 SOCK_T as=chan->priv->SOCK;
819 struct sockaddr_in iaddr;
820 struct sockaddr* iaddrp=(struct sockaddr*)&iaddr;
821 socklen_t size=sizeof(struct sockaddr_in);
824 int r=ACCEPT(as, iaddrp, &size, s);
827 if(ERRNO==INTERRUPTED) break;
828 if(ISNOTACTIVE(ERRNO)) break;
829 log_net_err("accept", ERRNO);
836 SOCKET_WRITE(s, chan->banner, strlen(chan->banner));
839 k_channel* chann=register_k_channel(chan->name,
849 gen_conn_name(chann);
850 k_hashtable_set(current_chans, chann->name, chann);
851 if(chann->rdcallback) (*chann->rdcallback)(chann, 0, 0);
855 void read_more_and_notify(k_channel* chan)
857 int pos=chan->priv->rdbufpos;
858 int size=SOCKET_READ(chan->priv->SOCK,
859 chan->priv->rdbuffer +pos,
860 chan->priv->rdbufsize-pos);
862 if(size==0){ size= -1; ERRNO=EPIPE; }
864 if(ERRNO==INTERRUPTED) return;
865 if(ISNOTACTIVE(ERRNO)) return;
866 log_net_err("socket_read", ERRNO);
867 unregister_k_channel(chan,1);
870 if(CHAN_CLOSING(chan)) return;
872 chan->priv->rdbufpos+=size;
874 if(chan->rdcallback){
875 (*chan->rdcallback)(chan, chan->priv->rdbufpos, size);
878 if(chan->priv->rdbufpos==chan->priv->rdbufsize){
879 if(chan->priv->rdbufforeign){
880 k_log_err("Run out of room in given buffer");
881 k_log_err("rdbufsize=%d", chan->priv->rdbufsize);
882 unregister_k_channel(chan,1);
885 chan->priv->rdbufsize*=2;
886 chan->priv->rdbuffer=k_realloc(chan->priv->rdbuffer,
887 chan->priv->rdbufsize);
888 if(0) k_log_out("rdbufsize=%d", chan->priv->rdbufsize);
889 // DoS vulnerability unless buffer size limited
893 void write_more_and_notify(k_channel* chan)
895 if(!chan->priv->wrbufpos){
897 k_hashtable_remove(connecting_chans, chan->name);
898 k_hashtable_set( current_chans, chan->name, chan);
900 if(chan->wrcallback) (*chan->wrcallback)(chan, 0, 0);
901 if(!chan->priv->wrbufpos) un_set_callback(chan, SETCB_WR); // Eerrk?
905 int writemax=MIN(WRITEMAX, chan->priv->wrbuffers[0].size);
906 int size=SOCKET_WRITE(chan->priv->SOCK,
907 chan->priv->wrbuffers[0].base,
910 if(size==0){ size= -1; ERRNO=NOTACTIVE; }
912 if(ERRNO==INTERRUPTED) return;
913 if(ISNOTACTIVE(ERRNO)) return;
914 log_net_err("socket_write", ERRNO);
915 unregister_k_channel(chan,1);
919 chop_from_wrbuffers(chan, size);
921 if(chan->wrcallback){
922 (*chan->wrcallback)(chan, chan->priv->wrbufpos, size);
925 if(!chan->priv->wrbufpos) un_set_callback(chan, SETCB_WR);
928 char* strnstr(char* haystack, size_t size, char* needle) // Errk!
930 if(!needle || !*needle) return haystack;
932 char* e=haystack+size;
933 for(h=haystack; h < e && *h; h++){
936 while(i < e && *i && *n && *i==*n){ i++; n++; }
942 char* chop_from_rdbuffer_div(k_channel* chan, char* divider)
944 char* s=strnstr(chan->priv->rdbuffer, chan->priv->rdbufpos, divider);
947 size_t size=(s+1 - chan->priv->rdbuffer);
949 char* chunk=k_memdup(chan->priv->rdbuffer, size);
950 char* e=chan->priv->rdbuffer+chan->priv->rdbufpos;
951 memmove(chan->priv->rdbuffer, s, e-s);
952 chan->priv->rdbufpos=e-s;
956 char* chop_from_rdbuffer_len(k_channel* chan, size_t size)
958 if(!size || size > chan->priv->rdbufpos) return 0;
959 char* chunk=k_memdup(chan->priv->rdbuffer, size);
960 char* s=chan->priv->rdbuffer+size;
961 char* e=chan->priv->rdbuffer+chan->priv->rdbufpos;
962 memmove(chan->priv->rdbuffer, s, e-s);
963 chan->priv->rdbufpos=e-s;
967 int set_rdbuffer(k_channel* chan, char* rdbuffer, size_t size)
969 if(chan->priv->rdbufforeign) return BUFFER_ALREADY_SET;
970 size_t pos=chan->priv->rdbufpos;
972 memcpy(rdbuffer, chan->priv->rdbuffer, size);
973 char* s=chan->priv->rdbuffer+size;
974 char* e=chan->priv->rdbuffer+pos;
975 memmove(chan->priv->rdbuffer, s, e-s);
976 chan->priv->rdbufpos=e-s;
977 return BUFFER_FILLED;
979 memcpy(rdbuffer, chan->priv->rdbuffer, pos);
980 k_free(chan->priv->rdbuffer);
981 chan->priv->rdbuffer=rdbuffer;
982 chan->priv->rdbufsize=size;
983 chan->priv->rdbufforeign=1;
987 char* get_rdbuffer(k_channel* chan)
989 if(!chan->priv->rdbufforeign) return 0;
990 char* rdbuffer=chan->priv->rdbuffer;
991 chan->priv->rdbuffer=(char*)k_malloc(RDSIZE);
992 chan->priv->rdbufpos=0;
993 chan->priv->rdbufsize=RDSIZE;
994 chan->priv->rdbufforeign=0;
998 void append_to_wrbuffers(k_channel* chan, char* base, size_t size, int free)
1000 if(chan->priv->wrbufpos==chan->priv->wrbufsize){
1001 chan->priv->wrbufsize*=2;
1002 chan->priv->wrbuffers=k_realloc(chan->priv->wrbuffers,
1003 chan->priv->wrbufsize *
1005 if(0) k_log_out("wrbufsize=%d", chan->priv->wrbufsize);
1007 chan->priv->wrbuffers[chan->priv->wrbufpos].base=base;
1008 chan->priv->wrbuffers[chan->priv->wrbufpos].size=size;
1009 chan->priv->wrbuffers[chan->priv->wrbufpos].free=free? base: 0;
1010 chan->priv->wrbufpos++;
1013 void chop_from_wrbuffers(k_channel* chan, size_t size)
1015 if(chan->priv->wrbuffers[0].size != size){
1016 chan->priv->wrbuffers[0].base+=size;
1017 chan->priv->wrbuffers[0].size-=size;
1020 k_free(chan->priv->wrbuffers[0].free);
1021 chan->priv->wrbufpos--;
1023 for(i=0; i< chan->priv->wrbufpos; i++){
1024 chan->priv->wrbuffers[i]=chan->priv->wrbuffers[i+1];
1029 /* -------------------------------------------------------------------------- */
1031 SOCK_T make_listen_socket(int listenport)
1034 int r=SOCKET(AF_INET, SOCK_STREAM, IPPROTO_TCP, s);
1037 log_net_err("socket", ERRNO);
1040 SET_NON_BLOCKING(s);
1043 struct sockaddr_in iaddr;
1044 struct sockaddr* iaddrp=(struct sockaddr*)&iaddr;
1045 iaddr=make_sockaddr_in(INADDR_ANY, listenport);
1047 r=BIND(s, iaddrp, sizeof(iaddr));
1050 log_net_err("bind", ERRNO);
1058 SOCK_T make_connect_socket(void)
1061 int r=SOCKET(AF_INET, SOCK_STREAM, IPPROTO_TCP, s);
1064 log_net_err("socket", ERRNO);
1067 SET_NON_BLOCKING(s);
1072 int listen_socket(SOCK_T s, int listenport)
1074 if(0) k_log_out("Listening on port %d", listenport);
1075 int r=LISTEN(s, 128);
1078 log_net_err("listen", ERRNO);
1085 int connect_socket(SOCK_T s, char* listenhost, int listenport)
1087 if(0) k_log_out("Hanging on gethostbyname for %s", listenhost);
1088 struct hostent* hostaddr=gethostbyname(listenhost);
1094 struct sockaddr_in iaddr;
1095 struct sockaddr* iaddrp=(struct sockaddr*)&iaddr;
1096 iaddr=make_sockaddr_in(0, listenport);
1097 memcpy(&iaddr.sin_addr, hostaddr->h_addr, hostaddr->h_length);
1099 if(0) k_log_out("Connect: %s(%s):%d ",
1100 listenhost, inet_ntoa(iaddr.sin_addr), listenport);
1102 int r=CONNECT(s, iaddrp, sizeof(iaddr));
1104 if(r== -1 && ERRNO==INTERRUPTED) continue;
1105 if(r== -1 && !ISCONNECTING(ERRNO)){
1106 log_net_err("connect", ERRNO);
1116 SOCK_T make_udp_listen_socket(int listenport)
1120 struct sockaddr_in iaddr;
1121 struct sockaddr* iaddrp=(struct sockaddr*)&iaddr;
1123 r=SOCKET(AF_INET, SOCK_DGRAM, IPPROTO_UDP, s);
1126 log_net_err("socket", ERRNO);
1132 iaddr=make_sockaddr_in(INADDR_ANY, listenport);
1134 r=BIND(s, iaddrp, sizeof(iaddr));
1137 log_net_err("bind", ERRNO);
1145 EXPORT SOCK_T make_udp_send_socket(char* listenhost, int listenport)
1149 struct sockaddr_in iaddr;
1150 struct sockaddr* iaddrp=(struct sockaddr*)&iaddr;
1152 r=SOCKET(AF_INET, SOCK_DGRAM, IPPROTO_UDP, s);
1155 log_net_err("socket", ERRNO);
1159 struct hostent* hostaddr=gethostbyname(listenhost);
1161 log_net_err("gethostbyname", h_errno);
1166 iaddr=make_sockaddr_in(0, listenport);
1167 memcpy(&iaddr.sin_addr, hostaddr->h_addr, hostaddr->h_length);
1169 r=CONNECT(s, iaddrp, sizeof(iaddr));
1172 log_net_err("connect", ERRNO);
1180 struct sockaddr_in make_sockaddr_in(unsigned long address, unsigned int port)
1182 struct sockaddr_in iaddr;
1183 struct sockaddr* iaddrp=(struct sockaddr*)&iaddr;
1184 memset(iaddrp, 0, sizeof(iaddr));
1185 iaddr.sin_addr.s_addr=htonl(address);
1186 iaddr.sin_port =htons(port);
1187 iaddrp->sa_family=AF_INET;
1191 void log_net_err(char* where, int e)
1193 if(0) k_log_out("Network (%s): %s (%d)", where, str_error(e), e);
1196 /* -------------------------------------------------------------------------- */
1198 EXPORT void k_file_stat(char* basedir,
1200 k_file_event callback,
1203 snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", basedir, filename);
1204 char* fullname=tmpbuf;
1206 k_stat kstat={0,0,0,0};
1208 stat_only(fullname, &kstat);
1209 (*callback)(basedir, filename, 0, 0, kstat, context);
1212 EXPORT void k_file_read(char* basedir,
1216 k_file_event callback,
1219 snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", basedir, filename);
1220 char* fullname=tmpbuf;
1223 k_stat kstat={0,0,0,0};
1226 if(write && !ensure_dir(fullname)){
1227 (*callback)(basedir, filename, 0, 0, kstat, context);
1231 stat_only(fullname, &kstat);
1232 if(!kstat.type && !write){
1233 (*callback)(basedir, filename, 0, 0, kstat, context);
1236 filehandle=open_only(fullname, write);
1238 (*callback)(basedir, filename, 0, 0, kstat, context);
1241 if(!kstat.type || (write && kstat.size!=size)){
1242 if(ftruncate(filehandle, size)){
1244 (*callback)(basedir, filename, 0, 0, kstat, context);
1250 if(!write) size=kstat.size;
1251 else kstat.size=size;
1253 if(size>MAX_FILESIZE){
1254 (*callback)(basedir, filename, 0, 0, kstat, context);
1257 int dommap=(size >= mmapsize);
1259 int prot=(write? PROT_WRITE: 0)|PROT_READ;
1263 if(size==0) data=dommap? dummy_empty_data: k_malloc(1);
1265 if(dommap) data=mmap_name( 0, size, prot, MAP_SHARED, fullname, 0);
1266 else data=mmap_malloc(0, size, prot, MAP_SHARED, fullname, 0);
1268 if(data==MAP_FAILED){
1269 (*callback)(basedir, filename, 0, 0, kstat, context);
1272 (*callback)(basedir, filename, data, dommap, kstat, context);
1275 EXPORT int k_file_sync(char* data, size_t size)
1277 int r=msync(data, size, MS_ASYNC);
1281 EXPORT void k_file_write(char* basedir,
1285 k_file_event callback,
1288 snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", basedir, filename);
1289 char* fullname=tmpbuf;
1292 k_stat kstat={0,0,0,0};
1294 if(!ensure_dir(fullname)){
1295 (*callback)(basedir, filename, 0, 0, kstat, context);
1299 filehandle=open_only(fullname, 1);
1301 (*callback)(basedir, filename, 0, 0, kstat, context);
1304 if(datalength!=0) kstat.size=WRITEFILE(filehandle, data, datalength);
1305 if(kstat.size== -1){
1307 (*callback)(basedir, filename, 0, 0, kstat, context);
1311 (*callback)(basedir, filename, data, 0, kstat, context);
1314 EXPORT void k_dir_list(char* basedir,
1318 k_file_event callback,
1321 snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", basedir, dirname);
1322 char* fullname=k_strdup(tmpbuf);
1324 k_stat kstat={ STAT_D, 0, 0, 0 };
1326 int size=TMPBUFSIZE;
1328 for(i=0; format[i]; i++){
1329 int n=dir_list(buf, size, fullname, pattern[i], format[i]);
1331 (*callback)(basedir, dirname, 0, 0, kstat, context);
1337 kstat.size=TMPBUFSIZE-size;
1338 (*callback)(basedir, dirname, k_strdup(tmpbuf), 0, kstat, context);
1342 int dir_list(char* buf, int size, char* fullname, char* pattern, char* format)
1344 DIR* d=opendir(fullname);
1351 while((de=readdir(d))){
1353 char* name=de->d_name;
1354 if(*name=='.') continue;
1356 if(pattern && *pattern &&
1357 !k_string_matches_pattern(name, pattern)) continue;
1359 int n=snprintf(b, s, format, name, name, name, name, name);
1360 if(n< 0 || n>=s){ closedir(d); return -1; }
1367 int ensure_dir(char* fullname)
1369 char* e=strrchr(fullname, '/');
1372 k_stat kstat={0,0,0,0};
1373 stat_only(fullname, &kstat);
1374 if(kstat.type!=STAT_D){
1376 stat_only(fullname, &kstat);
1379 return kstat.type==STAT_D;
1382 /* -------------------------------------------------------------------------- */
1384 EXPORT int k_string_matches_pattern(char* string, char* pattern)
1387 strncpy(patt, pattern, 32);
1393 char* e=strpbrk(pattern, ",}");
1396 if(k_string_matches_pattern(string, pattern)) return 1;
1404 return k_string_ends_with(string, pattern);
1409 EXPORT int k_string_ends_with(char* string, char* postfix)
1411 char* i=string+strlen(string)-strlen(postfix);
1412 if(i<string) return 0;
1413 return !strcmp(i, postfix);
1416 EXPORT void k_string_url_decode(char* s)
1420 if(s[0]=='%' && isxdigit(s[1]) && isxdigit(s[2])){
1421 *t=hex_to_int(s[1])*16+hex_to_int(s[2]);
1432 char hex_to_int(char c)
1435 (c >= '0' && c <= '9')? c-'0':
1436 (c >= 'A' && c <= 'F')? c-'A'+10:
1437 (c >= 'a' && c <= 'f')? c-'a'+10: 0;
1440 /* -------------------------------------------------------------------------- */
1442 EXPORT void k_log_out(char* format, ...)
1445 va_start(ap, format);
1447 VPRINTFOUT(format,ap);
1452 vsnprintf(logbuf, LOGBUFSIZE,format,ap);
1453 *(logbuf+LOGBUFSIZE-2)='\n';
1454 *(logbuf+LOGBUFSIZE-1)=0;
1455 write_to_logfile_cern_style(logbuf,0);
1460 EXPORT void k_log_err(char* format, ...)
1463 va_start(ap, format);
1465 VPRINTFERR(format,ap);
1470 vsnprintf(logbuf, LOGBUFSIZE,format,ap);
1471 *(logbuf+LOGBUFSIZE-2)='\n';
1472 *(logbuf+LOGBUFSIZE-1)=0;
1473 write_to_logfile_cern_style(logbuf,1);
1478 EXPORT void k_fatal(char* format, ...)
1481 va_start(ap, format);
1482 k_log_out(format, ap);
1484 k_log_out("Terminating Cilux");
1485 k_log_out("---------------------");
1489 void write_to_logfile_cern_style(char* text, int error)
1491 if(!logfile) return;
1505 if(z >=0){ sgn='+'; }
1506 else{ sgn='-'; z= -z; }
1510 strftime(cern, sizeof(cern), CERNDATE, tm);
1512 snprintf(date, sizeof(date), "%s %c%02d%02d", cern, sgn, z/60, z%60);
1514 snprintf(date, sizeof(date), "%s", cern);
1516 FPRINTF(logfile, "[%s|%s] %s%s\n", date, k_ciux,
1517 error? "Warning: ": "", text);
1521 /* -------------------------------------------------------------------------- */
1523 #define EXAMPLE_DATE Fri, 04 Feb 2005 12:14:48 GMT
1524 #define RFC1123STRF "%a, %d %b %Y %H:%M:%S GMT"
1525 #define RFC1123SSCANF "%3s, %d %3s %4d %2d:%2d:%2d GMT"
1529 EXPORT char* k_time_to_rfc(time_t t)
1531 strftime(b, sizeof(b), RFC1123STRF, gmtime(&t));
1535 EXPORT char* k_time_to_rfc_relative(int plus)
1537 time_t t=time(0)+plus;
1538 strftime(b, sizeof(b), RFC1123STRF, gmtime(&t));
1542 EXPORT time_t k_time_from_rfc(char* s)
1544 if(!s || strlen(s)!=29) return -1;
1545 struct tm tm; tm.tm_wday=0; tm.tm_yday=0; tm.tm_isdst=0;
1546 char wd[32], mn[32];
1547 int r=sscanf(s, RFC1123SSCANF, wd, &tm.tm_mday, mn, &tm.tm_year,
1548 &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
1550 tm.tm_mon=(int)k_hashtable_get(monthhash, mn);
1551 if(tm.tm_mon) tm.tm_mon -=1;
1556 EXPORT void k_time_get_now(char* buf, size_t size, char* format)
1567 strftime(buf, size, format, tm);
1570 /* -------------------------------------------------------------------------- */
1572 typedef struct hash_item hash_item;
1574 typedef struct hashtable{ struct hashtable* next;
1582 struct hash_item{ hash_item* next;
1589 /* -------------------------------------------------------------------------- */
1591 #define STRCMPCASE(tab, listkey, key)\
1592 ((tab)->ignorecase? strcasecmp((listkey), (key)): strcmp((listkey), (key)))
1594 #define WARN_SIZE(h)\
1595 if((h)->size && !((h)->size % BX)) k_log_out("%s# %d", (h)->name, (h)->size);
1597 EXPORT k_hashtable* k_hashtable_new(char* name, int ignorecase)
1600 tab=k_malloc(sizeof(hashtable));
1604 tab->lists=k_malloc((tab->buckets)*sizeof(hash_item*));
1605 tab->ignorecase=ignorecase;
1607 int i; for(i=0; i< tab->buckets; i++) tab->lists[i]=0;
1608 return (k_hashtable*)tab;
1611 k_hashtable* k_hashtable_dup2(k_hashtable* tab, int deep)
1614 hashtable* tah=(hashtable*)tab;
1616 tad=k_malloc(sizeof(hashtable));
1617 tad->name=tah->name;
1618 tad->buckets=tah->buckets;
1619 tad->size=tah->size;
1620 tad->lists=k_malloc((tah->buckets)*sizeof(hash_item*));
1621 tad->ignorecase=tah->ignorecase;
1626 for(i=0; i< tah->buckets; i++){
1627 for(lisp=&tah->lists[i], lisd=&tad->lists[i];
1629 lisp=&(*lisp)->next, lisd=&(*lisd)->next){
1631 (*lisd)=k_malloc(sizeof(hash_item));
1632 (*lisd)->key=k_strdup((*lisp)->key);
1637 (*lisd)->val=k_strdup((*lisp)->val);
1640 if(deep && (*lisp)->sub){
1641 (*lisd)->sub=k_hashtable_dup2((*lisp)->sub, 1);
1643 if(!(*lisd)->val && !(*lisd)->sub){
1649 tad->next=(hashtable*)k_hashtable_dup2(tab->next, deep);
1650 return (k_hashtable*)tad;
1653 EXPORT k_hashtable* k_hashtable_dup(k_hashtable* tab)
1655 return k_hashtable_dup2(tab, 0);
1658 EXPORT k_hashtable* k_hashtable_deep(k_hashtable* tab)
1660 return k_hashtable_dup2(tab, 1);
1663 EXPORT k_hashtable* k_hashtable_dip(k_hashtable* tab, char* includes[])
1666 hashtable* tah=(hashtable*)tab;
1668 tad=(hashtable*)k_hashtable_new(tah->name, tah->ignorecase);
1670 for(i=0; includes[i]; i++){
1671 char* in=k_hashtable_get((k_hashtable*)tah, includes[i]);
1674 k_hashtable_put((k_hashtable*)tad, includes[i], in);
1676 tad->next=(hashtable*)k_hashtable_dip(tab->next, includes);
1677 return (k_hashtable*)tad;
1680 EXPORT void k_hashtable_merge(k_hashtable* tab, k_hashtable* tam)
1682 hashtable* tan=(hashtable*)tam;
1685 for(i=0; i< tan->buckets; i++){
1686 for(lisp=&tan->lists[i]; (*lisp); lisp=&(*lisp)->next){
1687 char* key =(*lisp)->key;
1688 void* val =(*lisp)->val;
1689 int free=(*lisp)->free;
1690 k_hashtable* sub =(*lisp)->sub;
1691 if(!*key && free) continue;
1693 k_hashtable_put(tab, key, k_strdup(val));
1696 k_hashtable_sub(tab, key, k_hashtable_dup(sub));
1702 void k_hashtable_set_put(k_hashtable* tab, char* key, void* val, int free)
1704 if(!(tab && key && val)) return;
1705 hashtable* tah=(hashtable*)tab;
1707 lisp=&tah->lists[string_hash(key) % tah->buckets];
1708 while((*lisp) && STRCMPCASE(tah, (*lisp)->key, key)){
1709 lisp=&(*lisp)->next;
1712 (*lisp)=k_malloc(sizeof(hash_item));
1713 (*lisp)->key=k_strdup(key);
1722 if((*lisp)->free) k_free((*lisp)->val);
1723 k_hashtable_delete((*lisp)->sub);
1730 EXPORT void k_hashtable_set(k_hashtable* tab, char* key, void* val)
1732 k_hashtable_set_put(tab, key, val, 0);
1735 EXPORT void k_hashtable_put_int(k_hashtable* tab, char* key, int val)
1737 snprintf(tmpbuf, TMPBUFSIZE, "%d", val);
1738 k_hashtable_set_put(tab, key, k_strdup(tmpbuf), 1);
1741 EXPORT void k_hashtable_put(k_hashtable* tab, char* key, void* val)
1743 k_hashtable_set_put(tab, key, val, 1);
1746 EXPORT void k_hashtable_put_dup(k_hashtable* tab, char* key, char* val)
1748 k_hashtable_set_put(tab, key, k_strdup(val), 1);
1751 EXPORT void k_hashtable_sub(k_hashtable* tab, char* key, k_hashtable* sub)
1753 if(!(tab && key && sub)) return;
1755 hashtable* tah=(hashtable*)tab;
1757 lisp=&tah->lists[string_hash(key) % tah->buckets];
1758 while((*lisp) && STRCMPCASE(tah, (*lisp)->key, key)){
1759 lisp=&(*lisp)->next;
1762 (*lisp)=k_malloc(sizeof(hash_item));
1763 (*lisp)->key=k_strdup(key);
1772 k_hashtable* val =(*lisp)->val;
1773 k_hashtable* head=(*lisp)->sub;
1775 if(val) k_log_err("key '%s' in use: no sub!", key);
1776 else (*lisp)->sub=sub;
1779 while(head->next) head=head->next;
1785 EXPORT void* k_hashtable_get(k_hashtable* tab, char* key)
1787 if(!(tab && key)) return 0;
1788 hashtable* tah=(hashtable*)tab;
1790 list=tah->lists[string_hash(key) % tah->buckets];
1791 while(list && STRCMPCASE(tah, list->key, key)){
1794 return list? (list->val? list->val: list->sub): 0;
1797 EXPORT int k_hashtable_get_int(k_hashtable* tab, char* key)
1799 char* val=k_hashtable_get(tab, key);
1800 return val? atoi(val): 0;
1803 EXPORT char* k_hashtable_get_dup(k_hashtable* tab, char* key)
1805 char* v=k_hashtable_get(tab, key);
1809 EXPORT int k_hashtable_is(k_hashtable* tab, char* key, char* val)
1811 char* v=k_hashtable_get(tab, key);
1812 return (v && val && !strcmp(v, val));
1815 EXPORT int k_hashtable_isi(k_hashtable* tab, char* key, char* val)
1817 char* v=k_hashtable_get(tab, key);
1818 return (v && val && !strcasecmp(v, val));
1821 EXPORT int k_hashtable_isn(k_hashtable* tab, char* key, char* val, size_t size)
1823 char* v=k_hashtable_get(tab, key);
1824 return (v && val && !strncmp(v, val, size));
1827 EXPORT void* k_hashtable_extract(k_hashtable* tab, char* key)
1829 hashtable* tah=(hashtable*)tab;
1832 lisp=&tah->lists[string_hash(key) % tah->buckets];
1833 while((*lisp) && STRCMPCASE(tah, (*lisp)->key, key)){
1834 lisp=&(*lisp)->next;
1838 next= (*lisp)->next;
1839 k_free((*lisp)->key);
1841 if(!val) val=(*lisp)->sub;
1850 EXPORT void k_hashtable_remove(k_hashtable* tab, char* key)
1852 hashtable* tah=(hashtable*)tab;
1855 lisp=&tah->lists[string_hash(key) % tah->buckets];
1856 while((*lisp) && STRCMPCASE(tah, (*lisp)->key, key)){
1857 lisp=&(*lisp)->next;
1860 next= (*lisp)->next;
1861 k_free((*lisp)->key);
1862 if((*lisp)->free) k_free((*lisp)->val);
1863 k_hashtable_delete((*lisp)->sub);
1871 EXPORT void k_hashtable_delete(k_hashtable* tab)
1874 hashtable* tah=(hashtable*)tab;
1878 for(i=0; i< tah->buckets; i++){
1883 if(list->free) k_free(list->val);
1884 k_hashtable_delete(list->sub);
1890 k_hashtable_delete((k_hashtable*)tah->next);
1894 EXPORT void k_hashtable_apply(k_hashtable* tab,
1895 k_hashtable_apply_fn fn,
1899 hashtable* tah=(hashtable*)tab;
1902 for(i=0; i< tah->buckets; i++){
1903 for(lisp=&tah->lists[i]; (*lisp); lisp=&(*lisp)->next){
1905 (*fn)(arg, (*lisp)->key, (*lisp)->val);
1908 (*fn)(arg, (*lisp)->key, (*lisp)->sub);
1914 void k_hashtable_show2(k_hashtable* tab, int chars)
1917 hashtable* tah=(hashtable*)tab;
1918 if(!chars) k_log_out("%s size=%d", tah->name, tah->size);
1921 for(i=0; i< tah->buckets; i++){
1922 for(lisp=&tah->lists[i]; (*lisp); lisp=&(*lisp)->next){
1924 if(*((*lisp)->key)){
1926 (*lisp)->key, (char*)((*lisp)->val));
1930 k_log_out("buck %d key '%s' val %x sub %x",
1931 i, (*lisp)->key, (*lisp)->val, (*lisp)->sub);
1937 EXPORT void k_hashtable_show(k_hashtable* tab)
1939 k_hashtable_show2(tab,0);
1942 EXPORT void k_hashtable_show_chars(k_hashtable* tab)
1944 k_hashtable_show2(tab,1);
1947 int k_hashtable_snprintf_xi(k_hashtable* tab,
1954 if(!tab){ if(size) *buf=0; return 0; }
1957 hashtable* tah=(hashtable*)tab;
1963 for(i=0; i< tah->buckets; i++){
1964 for(lisp=&tah->lists[i]; (*lisp); lisp=&(*lisp)->next){
1965 if(!*((*lisp)->key)) continue;
1966 if(check_i((*lisp)->key, includes, tah->ignorecase)) continue;
1967 if(check_x((*lisp)->key, excludes, tah->ignorecase)) continue;
1970 n=snprintf(at, ln, "%s%s %s" CRLF, ind, (*lisp)->key,
1971 (char*)((*lisp)->val));
1973 if(n>=ln) return size;
1977 k_hashtable* sub=(*lisp)->sub;
1979 n=snprintf(at, ln, "%s%s" CRLF,
1982 if(n>=ln) return size;
1985 n=k_hashtable_snprintf_xi(sub, at, ln, 0, 0,
1988 if(n>=ln) return size;
1991 }while((sub=sub->next));
1998 EXPORT int k_hashtable_snprintf(k_hashtable* tab, char* buf, size_t size)
2000 return k_hashtable_snprintf_xi(tab, buf, size, 0, 0, 0);
2003 EXPORT int k_hashtable_snprintf_i(k_hashtable* tab,
2008 return k_hashtable_snprintf_xi(tab, buf, size, includes, 0, 0);
2011 EXPORT int k_hashtable_snprintf_x(k_hashtable* tab,
2016 return k_hashtable_snprintf_xi(tab, buf, size, 0, excludes, 0);
2019 int check_i(char* key, char* includes[], int ignorecase)
2021 if(!includes) return 0;
2023 for(e=0; includes[e]; e++){
2024 if(ignorecase? !strcasecmp(key, includes[e]):
2025 !strcmp( key, includes[e]) ) break;
2027 return !includes[e];
2030 int check_x(char* key, char* excludes[], int ignorecase)
2032 if(!excludes) return 0;
2034 for(e=0; excludes[e]; e++){
2035 if(ignorecase? !strcasecmp(key, excludes[e]):
2036 !strcmp( key, excludes[e]) ) break;
2038 return !!excludes[e];
2041 unsigned int string_hash(char* p)
2044 while(*p) h=(h<<5)-h+tolower(*p++);
2049 /* -------------------------------------------------------------------------- */