2 /* -------------------------------------------------------------------------- */
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 /* -------------------------------------------------------------------------- */
154 /* -------------------------------------------------------------------------- */
156 EXPORT void c_init(CONSOLE console,
159 void (*terminate)(void))
164 k_terminate=terminate;
169 if(LOAD_MODULES_EARLY){
176 EXPORT C_RUN_RV c_run(C_RUN_ARG arg)
180 if(!LOAD_MODULES_EARLY){
186 if(reshape_fn)(*reshape_fn)(640,480);
187 if(draw_fn) (*draw_fn)();
189 k_log_out("Cilux U-Web Exchange started");
190 k_log_out("%s", k_version);
191 k_log_out("---------------------------------------------");
193 int queue_events_to_do=0;
195 if(running==2) poller(queue_events_to_do);
196 if(running==1) SLEEP_MS(LOOP_TICK);
197 if(running==0) break;
199 if(running==2) queue_events_to_do=run_queues();
201 if(running==0) break;
204 k_log_out("Cilux U-Web Exchange terminated");
209 EXPORT OTHER_THREAD void c_running(int r)
214 EXPORT OTHER_THREAD void c_key(unsigned char key, int down)
219 EXPORT OTHER_THREAD void c_signal(int signum)
221 k_log_out("Received signal %d", signum);
224 /* -------------------------------------------------------------------------- */
226 EXPORT void k_gl_register_reshape(k_gl_reshape_event callback){
230 EXPORT void k_gl_register_draw(k_gl_draw_event callback){
234 EXPORT void k_gl_register_key(k_gl_key_event callback){
238 /* -------------------------------------------------------------------------- */
240 void init_hashtables(void)
242 connecting_chans=k_hashtable_new("Connecting Channels", 0);
243 current_chans =k_hashtable_new("Current Channels", 0);
244 monthhash =k_hashtable_new("Months", 1);
245 k_hashtable_set(monthhash, "Jan", (void*)1);
246 k_hashtable_set(monthhash, "Feb", (void*)2);
247 k_hashtable_set(monthhash, "Mar", (void*)3);
248 k_hashtable_set(monthhash, "Apr", (void*)4);
249 k_hashtable_set(monthhash, "May", (void*)5);
250 k_hashtable_set(monthhash, "Jun", (void*)6);
251 k_hashtable_set(monthhash, "Jul", (void*)7);
252 k_hashtable_set(monthhash, "Aug", (void*)8);
253 k_hashtable_set(monthhash, "Sep", (void*)9);
254 k_hashtable_set(monthhash, "Oct", (void*)10);
255 k_hashtable_set(monthhash, "Nov", (void*)11);
256 k_hashtable_set(monthhash, "Dec", (void*)12);
259 void init_logging(void)
261 snprintf(tmpbuf, TMPBUFSIZE, "%s.log", k_ciux);
262 logfile=FOPEN(tmpbuf, "a");
263 if(!logfile) k_log_err("couldn't open logfile %s", tmpbuf);
266 void init_modules(void)
268 char* patts[]={ "{*.dll,*.so}", 0};
269 char* temps[]={ "%s:", 0 };
270 k_dir_list(".", ".", patts, temps, dir_read, 0);
273 void dir_read(char* basedir,
282 if(!strncmp(data, MODPRE, strlen(MODPRE))){
283 k_ciux=k_strdup(data+strlen(MODPRE));
284 char* c=strchr(k_ciux, '.');
296 k_log_out("========================================");
298 load_module("ni", 0);
299 load_module("np", 0);
300 if(!is_np) load_module(k_ciux, 1);
302 k_log_out("========================================");
305 void load_module(char* name, int dot)
307 k_log_out("------------ %s --------------", name);
309 snprintf(dlname, 64, "%s%s%s%s", dot? "./": "", MODPRE, name, MODPOST);
310 MODULE module=DLOPEN(dlname);
312 k_module_loaded_fn loaded_fn=get_module_loaded_fn(name, module);
313 k_module_tick_fn tick_fn =get_module_tick_fn( name, module);
314 k_module_event_fn event_fn =get_module_event_fn( name, module);
315 if(loaded_fn && event_fn){
316 add_module_entry(name, tick_fn, event_fn);
319 else k_log_err("Couldn't load module %s (hooks)", dlname);
321 else k_log_err("Couldn't load module %s (dlopen) %s", dlname, DLERROR);
324 k_module_loaded_fn get_module_loaded_fn(char* name, MODULE module)
326 snprintf(tmpbuf, TMPBUFSIZE, "%s%s", name, NAME_OF_MODULE_LOADED_FN);
327 k_module_loaded_fn f=(k_module_loaded_fn)DLSYM(module, tmpbuf);
328 if(!f) k_log_err("no %s", tmpbuf);
332 k_module_tick_fn get_module_tick_fn(char* name, MODULE module)
334 snprintf(tmpbuf, TMPBUFSIZE, "%s%s", name, NAME_OF_MODULE_TICK_FN);
335 k_module_tick_fn f=(k_module_tick_fn)DLSYM(module, tmpbuf);
336 if(!f) k_log_err("no %s", tmpbuf);
340 k_module_event_fn get_module_event_fn(char* name, MODULE module)
342 snprintf(tmpbuf, TMPBUFSIZE, "%s%s", name, NAME_OF_MODULE_EVENT_FN);
343 k_module_event_fn f=(k_module_event_fn)DLSYM(module, tmpbuf);
344 if(!f) k_log_err("no %s", tmpbuf);
348 /* -------------------------------------------------------------------------- */
350 void add_module_entry(char* name,
351 k_module_tick_fn tick_fn,
352 k_module_event_fn event_fn)
354 if(nextmodule==MAX_MODULES){
355 k_fatal("Too many modules! Maximum %d", MAX_MODULES);
357 modules[nextmodule ].name =name;
358 modules[nextmodule ].tick_fn =tick_fn;
359 modules[nextmodule ].event_fn=event_fn;
360 modules[nextmodule++].queue =0;
363 event* event_new(void* data)
366 ev=k_malloc(sizeof(event));
372 EXPORT int k_event_post(char* module, void* data)
374 event* ev=event_new(data);
375 event** queue=get_module_queue(module);
377 k_log_err("k_event_post(%s): no such module", module);
380 if(!*queue) *queue=ev;
394 event** get_module_queue(char* name)
397 for(i=0; i< nextmodule; i++){
398 if(!strcmp(modules[i].name, name)) return &modules[i].queue;
406 for(i=0; i< nextmodule; i++){
407 for(j=0; modules[i].queue && j < MAX_EVENTS_PER_MODULE; j++){
408 event* event=modules[i].queue;
409 modules[i].queue=event->next;
411 (*modules[i].event_fn)(event->data);
415 for(i=0; i< nextmodule; i++){
416 if(modules[i].queue) return 1;
421 /* -------------------------------------------------------------------------- */
426 ke=k_malloc(sizeof(key_event));
434 OTHER_THREAD void got_key(unsigned char key, int down)
436 if(!key_producer) return;
438 ke=k_malloc(sizeof(key_event));
442 key_producer->next=ke;
448 while(key_consumer!=key_producer){
449 key_event* ke=key_consumer->next;
450 if(key_fn) (*key_fn)(ke->key, ke->down);
451 k_free(key_consumer);
456 /* -}{----------------------------------------------------------------------- */
458 EXPORT char* k_channel_name(char* type, char* ip, int port, char* other)
461 int bufsize=TMPBUFSIZE;
463 if(type) ln+=snprintf(tmpbuf+ln, bufsize-ln, "|%s|", type);
464 else ln+=snprintf(tmpbuf+ln, bufsize-ln, "|-|");
465 if(ln>=bufsize) return 0;
467 if(ip) ln+=snprintf(tmpbuf+ln, bufsize-ln, "%s|", ip);
468 else ln+=snprintf(tmpbuf+ln, bufsize-ln, "-|");
469 if(ln>=bufsize) return 0;
471 if(port) ln+=snprintf(tmpbuf+ln, bufsize-ln, "%d|", port);
472 else ln+=snprintf(tmpbuf+ln, bufsize-ln, "-|");
473 if(ln>=bufsize) return 0;
475 if(other) ln+=snprintf(tmpbuf+ln, bufsize-ln, "%s|", other);
476 else ln+=snprintf(tmpbuf+ln, bufsize-ln, "-|");
477 if(ln>=bufsize) return 0;
479 return k_strdup(tmpbuf);
482 EXPORT k_channel* k_channel_connect_name(char* chanm,
483 k_channel_event rdcallback,
484 k_channel_event wrcallback)
486 if(k_hashtable_get(connecting_chans, chanm)){
487 if(1) k_log_out("Already connecting to %s", chanm);
490 k_hashtable_set(connecting_chans, chanm, chanm);
493 char* t=k_strdup(chanm);
494 char* a=strchr(t+1, '|'); *a++=0;
495 char* p=strchr(a, '|'); *p++=0;
496 char* o=strchr(p, '|'); *o++=0;
499 if(strstr(t, "-client")){
500 chan=k_channel_connect(t, a, pi, rdcallback, wrcallback, 0);
501 if(!chan) k_log_err("couldn't connect to %s:%d", a, pi);
504 if(strstr(t, "-server") && *a=='-'){
505 chan=k_channel_listen(t, pi, 0, rdcallback, wrcallback, 0);
506 if(!chan) k_log_err("couldn't listen on port %d", pi);
509 if(strstr(t, "-server")){
510 chan=k_channel_connect(t, a, pi, rdcallback, wrcallback, 0);
511 if(!chan) k_log_err("couldn't connect to %s:%d", a, pi);
523 EXPORT k_channel* k_channel_get_name(char* chanm)
525 k_channel* chan=k_hashtable_get(current_chans, chanm);
529 EXPORT void k_channel_show_all()
531 k_log_out("----------------------------------------");
532 k_hashtable_show(connecting_chans);
533 k_log_out("----------------------------------------");
534 k_hashtable_show(current_chans);
535 k_log_out("----------------------------------------");
538 void gen_conn_name(k_channel* chan)
540 char* t=chan->name+1;
541 char* a=strchr(t, '|'); *a++=0;
542 char* p=strchr(a, '|'); *p++=0;
543 char* o=strchr(p, '|'); *o++=0;
544 char* ip=inet_ntoa(chan->clientip);
548 static long uniquenum;
549 snprintf(b, 32, "%ld", ++uniquenum);
550 chan->name=k_channel_name(t, ip, pi, b);
557 /* -------------------------------------------------------------------------- */
559 EXPORT k_channel* k_channel_listen(char* name,
562 k_channel_event rdcallback,
563 k_channel_event wrcallback,
566 SOCK_T s=make_listen_socket(listenport);
569 struct in_addr noclientip=EMPTY_IN_ADDR;
570 k_channel* chan=register_k_channel(name,
580 int r=listen_socket(s, listenport);
582 unregister_k_channel(chan,1);
588 EXPORT k_channel* k_channel_connect(char* name,
591 k_channel_event rdcallback,
592 k_channel_event wrcallback,
595 SOCK_T s=make_connect_socket();
598 struct in_addr noclientip=EMPTY_IN_ADDR;
599 k_channel* chan=register_k_channel(name,
609 int r=connect_socket(s, listenhost, listenport);
611 unregister_k_channel(chan,1);
617 EXPORT k_channel* k_channel_send(k_channel* chan,
622 append_to_wrbuffers(chan, base, size, free);
623 set_callback(chan, SETCB_WR);
627 EXPORT char* k_channel_chop_div(k_channel* chan, char* divider)
629 return chop_from_rdbuffer_div(chan, divider);
632 EXPORT char* k_channel_chop_len(k_channel* chan, size_t size)
634 return chop_from_rdbuffer_len(chan, size);
637 EXPORT int k_channel_setbuf(k_channel* chan, char* rdbuffer, size_t size)
639 return set_rdbuffer(chan, rdbuffer, size);
642 EXPORT char* k_channel_getbuf(k_channel* chan)
644 return get_rdbuffer(chan);
647 EXPORT void k_channel_close(k_channel* chan)
649 unregister_k_channel(chan,0);
652 k_channel* register_k_channel(char* name,
656 k_channel_event rdcallback,
657 k_channel_event wrcallback,
660 struct in_addr clientip,
664 chan=k_malloc(sizeof(k_channel));
667 chan->listenhost=listenhost;
668 chan->listenport=listenport;
670 chan->rdcallback=rdcallback;
671 chan->wrcallback=wrcallback;
672 chan->context=context;
674 chan->clientip=clientip;
677 chan->priv=k_malloc(sizeof(k_channel_priv));
679 chan->priv->state=CHAN_OPEN;
680 chan->priv->event=0; /* what is this for? */
681 chan->priv->rwmask=0; /* what is this for? */
682 chan->priv->rdbuffer=(char*)k_malloc(RDSIZE); /* 40K per connection??!! */
683 chan->priv->rdbufpos=0;
684 chan->priv->rdbufsize=RDSIZE;
685 chan->priv->rdbufforeign=0;
686 chan->priv->wrbuffers=(wrbuffer*)k_malloc(WRSIZE*sizeof(wrbuffer));
687 chan->priv->wrbufpos=0;
688 chan->priv->wrbufsize=WRSIZE;
689 chan->priv->lingercount=LINGER_LOOPS;
692 set_callback(chan, SETCB_RD);
694 if(chan->listenhost){
695 set_callback(chan, SETCB_WR);
698 chan->next=k_channels;
704 void unregister_k_channel(k_channel* chan, int now)
706 int closing=CHAN_CLOSING(chan);
707 if(closing && !now) return;
708 int linger=chan->linger && !now;
709 chan->priv->state=linger? CHAN_LINGER: CHAN_CLOSE;
710 if(linger) un_set_callback(chan, SETCB_WR);
711 else un_set_callback(chan, SETCB_WR | SETCB_RD);
714 if(chan->rdcallback)(*chan->rdcallback)(chan, chan->priv->rdbufpos, -1);
716 if(chan->wrcallback)(*chan->wrcallback)(chan, chan->priv->wrbufpos, -1);
719 void chan_closed(k_channel* chan)
721 if(0) k_log_out("chan_closed %s", chan->name);
722 k_hashtable_remove(connecting_chans, chan->name);
723 k_hashtable_remove(current_chans, chan->name);
724 if(0) k_channel_show_all();
727 void do_regular_things(void)
730 remove_dead_k_channels();
733 void tick_modules(void)
736 for(i=0; i< nextmodule; i++){
737 k_module_tick_fn tf=modules[i].tick_fn;
742 void remove_dead_k_channels(void)
747 k_channel* cc=k_channels;
750 if( cc->priv->state==CHAN_CLOSE ||
751 (cc->priv->state==CHAN_LINGER && !cc->priv->lingercount--)){
752 un_set_callback(cc, SETCB_WR | SETCB_RD);
753 if(!cp) k_channels=cn;
755 SOCKET_CLOSE(cc->priv->SOCK);
756 for(i=0; i< cc->priv->wrbufpos; i++){
757 k_free(cc->priv->wrbuffers[i].free);
759 k_free(cc->priv->wrbuffers);
760 k_free(cc->priv->rdbuffer);
770 k_channel* find_k_channel_for_socket(SOCK_T s)
773 for(chan=k_channels; chan; chan=chan->next){
774 if(chan->priv->SOCK==s) break;
779 void show_open_channels(void)
781 k_channel* chan=k_channels;
783 if(chan->priv->state==CHAN_OPEN ){
784 if(0) k_log_out("chan open %x", chan->priv->SOCK);
786 if(chan->priv->state==CHAN_LINGER){
787 if(0) k_log_out("chan lingering %x", chan->priv->SOCK);
789 if(chan->priv->state==CHAN_CLOSE ){
790 if(0) k_log_out("chan closed %x", chan->priv->SOCK);
796 void readable_socket(k_channel* chan)
798 if(chan->type==CHAN_LISTEN){
799 register_connections(chan);
802 read_more_and_notify(chan);
806 void writeable_socket(k_channel* chan)
808 write_more_and_notify(chan);
811 void exception_socket(k_channel* chan)
813 if(0) k_log_out("exception_socket");
814 unregister_k_channel(chan,1);
817 void register_connections(k_channel* chan)
819 SOCK_T as=chan->priv->SOCK;
820 struct sockaddr_in iaddr;
821 struct sockaddr* iaddrp=(struct sockaddr*)&iaddr;
822 socklen_t size=sizeof(struct sockaddr_in);
825 int r=ACCEPT(as, iaddrp, &size, s);
828 if(ERRNO==INTERRUPTED) break;
829 if(ISNOTACTIVE(ERRNO)) break;
830 log_net_err("accept", ERRNO);
837 SOCKET_WRITE(s, chan->banner, strlen(chan->banner));
840 k_channel* chann=register_k_channel(chan->name,
850 gen_conn_name(chann);
851 k_hashtable_set(current_chans, chann->name, chann);
852 if(chann->rdcallback) (*chann->rdcallback)(chann, 0, 0);
856 void read_more_and_notify(k_channel* chan)
858 int pos=chan->priv->rdbufpos;
859 int size=SOCKET_READ(chan->priv->SOCK,
860 chan->priv->rdbuffer +pos,
861 chan->priv->rdbufsize-pos);
863 if(size==0){ size= -1; ERRNO=EPIPE; }
865 if(ERRNO==INTERRUPTED) return;
866 if(ISNOTACTIVE(ERRNO)) return;
867 log_net_err("socket_read", ERRNO);
868 unregister_k_channel(chan,1);
871 if(CHAN_CLOSING(chan)) return;
873 chan->priv->rdbufpos+=size;
875 if(chan->rdcallback){
876 (*chan->rdcallback)(chan, chan->priv->rdbufpos, size);
879 if(chan->priv->rdbufpos==chan->priv->rdbufsize){
880 if(chan->priv->rdbufforeign){
881 k_log_err("Run out of room in given buffer");
882 k_log_err("rdbufsize=%d", chan->priv->rdbufsize);
883 unregister_k_channel(chan,1);
886 chan->priv->rdbufsize*=2;
887 chan->priv->rdbuffer=k_realloc(chan->priv->rdbuffer,
888 chan->priv->rdbufsize);
889 if(0) k_log_out("rdbufsize=%d", chan->priv->rdbufsize);
890 // DoS vulnerability unless buffer size limited
894 void write_more_and_notify(k_channel* chan)
896 if(!chan->priv->wrbufpos){
898 k_hashtable_remove(connecting_chans, chan->name);
899 k_hashtable_set( current_chans, chan->name, chan);
901 if(chan->wrcallback) (*chan->wrcallback)(chan, 0, 0);
902 if(!chan->priv->wrbufpos) un_set_callback(chan, SETCB_WR); // Eerrk?
906 int writemax=MIN(WRITEMAX, chan->priv->wrbuffers[0].size);
907 int size=SOCKET_WRITE(chan->priv->SOCK,
908 chan->priv->wrbuffers[0].base,
911 if(size==0){ size= -1; ERRNO=NOTACTIVE; }
913 if(ERRNO==INTERRUPTED) return;
914 if(ISNOTACTIVE(ERRNO)) return;
915 log_net_err("socket_write", ERRNO);
916 unregister_k_channel(chan,1);
920 chop_from_wrbuffers(chan, size);
922 if(chan->wrcallback){
923 (*chan->wrcallback)(chan, chan->priv->wrbufpos, size);
926 if(!chan->priv->wrbufpos) un_set_callback(chan, SETCB_WR);
929 char* strnstr(char* haystack, size_t size, char* needle) // Errk!
931 if(!needle || !*needle) return haystack;
933 char* e=haystack+size;
934 for(h=haystack; h < e && *h; h++){
937 while(i < e && *i && *n && *i==*n){ i++; n++; }
943 char* chop_from_rdbuffer_div(k_channel* chan, char* divider)
945 char* s=strnstr(chan->priv->rdbuffer, chan->priv->rdbufpos, divider);
948 size_t size=(s+1 - chan->priv->rdbuffer);
950 char* chunk=k_memdup(chan->priv->rdbuffer, size);
951 char* e=chan->priv->rdbuffer+chan->priv->rdbufpos;
952 memmove(chan->priv->rdbuffer, s, e-s);
953 chan->priv->rdbufpos=e-s;
957 char* chop_from_rdbuffer_len(k_channel* chan, size_t size)
959 if(!size || size > chan->priv->rdbufpos) return 0;
960 char* chunk=k_memdup(chan->priv->rdbuffer, size);
961 char* s=chan->priv->rdbuffer+size;
962 char* e=chan->priv->rdbuffer+chan->priv->rdbufpos;
963 memmove(chan->priv->rdbuffer, s, e-s);
964 chan->priv->rdbufpos=e-s;
968 int set_rdbuffer(k_channel* chan, char* rdbuffer, size_t size)
970 if(chan->priv->rdbufforeign) return BUFFER_ALREADY_SET;
971 size_t pos=chan->priv->rdbufpos;
973 memcpy(rdbuffer, chan->priv->rdbuffer, size);
974 char* s=chan->priv->rdbuffer+size;
975 char* e=chan->priv->rdbuffer+pos;
976 memmove(chan->priv->rdbuffer, s, e-s);
977 chan->priv->rdbufpos=e-s;
978 return BUFFER_FILLED;
980 memcpy(rdbuffer, chan->priv->rdbuffer, pos);
981 k_free(chan->priv->rdbuffer);
982 chan->priv->rdbuffer=rdbuffer;
983 chan->priv->rdbufsize=size;
984 chan->priv->rdbufforeign=1;
988 char* get_rdbuffer(k_channel* chan)
990 if(!chan->priv->rdbufforeign) return 0;
991 char* rdbuffer=chan->priv->rdbuffer;
992 chan->priv->rdbuffer=(char*)k_malloc(RDSIZE);
993 chan->priv->rdbufpos=0;
994 chan->priv->rdbufsize=RDSIZE;
995 chan->priv->rdbufforeign=0;
999 void append_to_wrbuffers(k_channel* chan, char* base, size_t size, int free)
1001 if(chan->priv->wrbufpos==chan->priv->wrbufsize){
1002 chan->priv->wrbufsize*=2;
1003 chan->priv->wrbuffers=k_realloc(chan->priv->wrbuffers,
1004 chan->priv->wrbufsize *
1006 if(0) k_log_out("wrbufsize=%d", chan->priv->wrbufsize);
1008 chan->priv->wrbuffers[chan->priv->wrbufpos].base=base;
1009 chan->priv->wrbuffers[chan->priv->wrbufpos].size=size;
1010 chan->priv->wrbuffers[chan->priv->wrbufpos].free=free? base: 0;
1011 chan->priv->wrbufpos++;
1014 void chop_from_wrbuffers(k_channel* chan, size_t size)
1016 if(chan->priv->wrbuffers[0].size != size){
1017 chan->priv->wrbuffers[0].base+=size;
1018 chan->priv->wrbuffers[0].size-=size;
1021 k_free(chan->priv->wrbuffers[0].free);
1022 chan->priv->wrbufpos--;
1024 for(i=0; i< chan->priv->wrbufpos; i++){
1025 chan->priv->wrbuffers[i]=chan->priv->wrbuffers[i+1];
1030 /* -------------------------------------------------------------------------- */
1032 SOCK_T make_listen_socket(int listenport)
1035 int r=SOCKET(AF_INET, SOCK_STREAM, IPPROTO_TCP, s);
1038 log_net_err("socket", ERRNO);
1041 SET_NON_BLOCKING(s);
1044 struct sockaddr_in iaddr;
1045 struct sockaddr* iaddrp=(struct sockaddr*)&iaddr;
1046 iaddr=make_sockaddr_in(INADDR_ANY, listenport);
1048 r=BIND(s, iaddrp, sizeof(iaddr));
1051 log_net_err("bind", ERRNO);
1059 SOCK_T make_connect_socket(void)
1062 int r=SOCKET(AF_INET, SOCK_STREAM, IPPROTO_TCP, s);
1065 log_net_err("socket", ERRNO);
1068 SET_NON_BLOCKING(s);
1073 int listen_socket(SOCK_T s, int listenport)
1075 if(0) k_log_out("Listening on port %d", listenport);
1076 int r=LISTEN(s, 128);
1079 log_net_err("listen", ERRNO);
1086 int connect_socket(SOCK_T s, char* listenhost, int listenport)
1088 if(0) k_log_out("Hanging on gethostbyname for %s", listenhost);
1089 struct hostent* hostaddr=gethostbyname(listenhost);
1095 struct sockaddr_in iaddr;
1096 struct sockaddr* iaddrp=(struct sockaddr*)&iaddr;
1097 iaddr=make_sockaddr_in(0, listenport);
1098 memcpy(&iaddr.sin_addr, hostaddr->h_addr, hostaddr->h_length);
1100 if(0) k_log_out("Connect: %s(%s):%d ",
1101 listenhost, inet_ntoa(iaddr.sin_addr), listenport);
1103 int r=CONNECT(s, iaddrp, sizeof(iaddr));
1105 if(r== -1 && ERRNO==INTERRUPTED) continue;
1106 if(r== -1 && !ISCONNECTING(ERRNO)){
1107 log_net_err("connect", ERRNO);
1117 SOCK_T make_udp_listen_socket(int listenport)
1121 struct sockaddr_in iaddr;
1122 struct sockaddr* iaddrp=(struct sockaddr*)&iaddr;
1124 r=SOCKET(AF_INET, SOCK_DGRAM, IPPROTO_UDP, s);
1127 log_net_err("socket", ERRNO);
1133 iaddr=make_sockaddr_in(INADDR_ANY, listenport);
1135 r=BIND(s, iaddrp, sizeof(iaddr));
1138 log_net_err("bind", ERRNO);
1146 EXPORT SOCK_T make_udp_send_socket(char* listenhost, int listenport)
1150 struct sockaddr_in iaddr;
1151 struct sockaddr* iaddrp=(struct sockaddr*)&iaddr;
1153 r=SOCKET(AF_INET, SOCK_DGRAM, IPPROTO_UDP, s);
1156 log_net_err("socket", ERRNO);
1160 struct hostent* hostaddr=gethostbyname(listenhost);
1162 log_net_err("gethostbyname", h_errno);
1167 iaddr=make_sockaddr_in(0, listenport);
1168 memcpy(&iaddr.sin_addr, hostaddr->h_addr, hostaddr->h_length);
1170 r=CONNECT(s, iaddrp, sizeof(iaddr));
1173 log_net_err("connect", ERRNO);
1181 struct sockaddr_in make_sockaddr_in(unsigned long address, unsigned int port)
1183 struct sockaddr_in iaddr;
1184 struct sockaddr* iaddrp=(struct sockaddr*)&iaddr;
1185 memset(iaddrp, 0, sizeof(iaddr));
1186 iaddr.sin_addr.s_addr=htonl(address);
1187 iaddr.sin_port =htons(port);
1188 iaddrp->sa_family=AF_INET;
1192 void log_net_err(char* where, int e)
1194 if(0) k_log_out("Network (%s): %s (%d)", where, str_error(e), e);
1197 /* -------------------------------------------------------------------------- */
1199 EXPORT void k_file_stat(char* basedir,
1201 k_file_event callback,
1204 snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", basedir, filename);
1205 char* fullname=tmpbuf;
1207 k_stat kstat={0,0,0,0};
1209 stat_only(fullname, &kstat);
1210 (*callback)(basedir, filename, 0, 0, kstat, context);
1213 EXPORT void k_file_read(char* basedir,
1217 k_file_event callback,
1220 snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", basedir, filename);
1221 char* fullname=tmpbuf;
1224 k_stat kstat={0,0,0,0};
1227 if(write && !ensure_dir(fullname)){
1228 (*callback)(basedir, filename, 0, 0, kstat, context);
1232 stat_only(fullname, &kstat);
1233 if(!kstat.type && !write){
1234 (*callback)(basedir, filename, 0, 0, kstat, context);
1237 filehandle=open_only(fullname, write);
1239 (*callback)(basedir, filename, 0, 0, kstat, context);
1242 if(!kstat.type || (write && kstat.size!=size)){
1243 if(ftruncate(filehandle, size)){
1245 (*callback)(basedir, filename, 0, 0, kstat, context);
1251 if(!write) size=kstat.size;
1252 else kstat.size=size;
1254 if(size>MAX_FILESIZE){
1255 (*callback)(basedir, filename, 0, 0, kstat, context);
1258 int dommap=(size >= mmapsize);
1260 int prot=(write? PROT_WRITE: 0)|PROT_READ;
1264 if(size==0) data=dommap? dummy_empty_data: k_malloc(1);
1266 if(dommap) data=mmap_name( 0, size, prot, MAP_SHARED, fullname, 0);
1267 else data=mmap_malloc(0, size, prot, MAP_SHARED, fullname, 0);
1269 if(data==MAP_FAILED){
1270 (*callback)(basedir, filename, 0, 0, kstat, context);
1273 (*callback)(basedir, filename, data, dommap, kstat, context);
1276 EXPORT int k_file_sync(char* data, size_t size)
1278 int r=msync(data, size, MS_ASYNC);
1282 EXPORT void k_file_write(char* basedir,
1286 k_file_event callback,
1289 snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", basedir, filename);
1290 char* fullname=tmpbuf;
1293 k_stat kstat={0,0,0,0};
1295 if(!ensure_dir(fullname)){
1296 (*callback)(basedir, filename, 0, 0, kstat, context);
1300 filehandle=open_only(fullname, 1);
1302 (*callback)(basedir, filename, 0, 0, kstat, context);
1305 if(datalength!=0) kstat.size=WRITEFILE(filehandle, data, datalength);
1306 if(kstat.size== -1){
1308 (*callback)(basedir, filename, 0, 0, kstat, context);
1312 (*callback)(basedir, filename, data, 0, kstat, context);
1315 EXPORT void k_dir_list(char* basedir,
1319 k_file_event callback,
1322 snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", basedir, dirname);
1323 char* fullname=k_strdup(tmpbuf);
1325 k_stat kstat={ STAT_D, 0, 0, 0 };
1327 int size=TMPBUFSIZE;
1329 for(i=0; format[i]; i++){
1330 int n=dir_list(buf, size, fullname, pattern[i], format[i]);
1332 (*callback)(basedir, dirname, 0, 0, kstat, context);
1338 kstat.size=TMPBUFSIZE-size;
1339 (*callback)(basedir, dirname, k_strdup(tmpbuf), 0, kstat, context);
1343 int dir_list(char* buf, int size, char* fullname, char* pattern, char* format)
1345 DIR* d=opendir(fullname);
1352 while((de=readdir(d))){
1354 char* name=de->d_name;
1355 if(*name=='.') continue;
1357 if(pattern && *pattern &&
1358 !k_string_matches_pattern(name, pattern)) continue;
1360 int n=snprintf(b, s, format, name, name, name, name, name);
1361 if(n< 0 || n>=s){ closedir(d); return -1; }
1368 int ensure_dir(char* fullname)
1370 char* e=strrchr(fullname, '/');
1373 k_stat kstat={0,0,0,0};
1374 stat_only(fullname, &kstat);
1375 if(kstat.type!=STAT_D){
1377 stat_only(fullname, &kstat);
1380 return kstat.type==STAT_D;
1383 /* -------------------------------------------------------------------------- */
1385 EXPORT int k_string_matches_pattern(char* string, char* pattern)
1388 strncpy(patt, pattern, 32);
1394 char* e=strpbrk(pattern, ",}");
1397 if(k_string_matches_pattern(string, pattern)) return 1;
1405 return k_string_ends_with(string, pattern);
1410 EXPORT int k_string_ends_with(char* string, char* postfix)
1412 char* i=string+strlen(string)-strlen(postfix);
1413 if(i<string) return 0;
1414 return !strcmp(i, postfix);
1417 EXPORT void k_string_url_decode(char* s)
1421 if(s[0]=='%' && isxdigit(s[1]) && isxdigit(s[2])){
1422 *t=hex_to_int(s[1])*16+hex_to_int(s[2]);
1433 char hex_to_int(char c)
1436 (c >= '0' && c <= '9')? c-'0':
1437 (c >= 'A' && c <= 'F')? c-'A'+10:
1438 (c >= 'a' && c <= 'f')? c-'a'+10: 0;
1441 /* -------------------------------------------------------------------------- */
1443 EXPORT void k_log_out(char* format, ...)
1446 va_start(ap, format);
1448 VPRINTFOUT(format,ap);
1453 vsnprintf(logbuf, LOGBUFSIZE,format,ap);
1454 *(logbuf+LOGBUFSIZE-2)='\n';
1455 *(logbuf+LOGBUFSIZE-1)=0;
1456 write_to_logfile_cern_style(logbuf,0);
1461 EXPORT void k_log_err(char* format, ...)
1464 va_start(ap, format);
1466 VPRINTFERR(format,ap);
1471 vsnprintf(logbuf, LOGBUFSIZE,format,ap);
1472 *(logbuf+LOGBUFSIZE-2)='\n';
1473 *(logbuf+LOGBUFSIZE-1)=0;
1474 write_to_logfile_cern_style(logbuf,1);
1479 EXPORT void k_fatal(char* format, ...)
1482 va_start(ap, format);
1483 k_log_out(format, ap);
1485 k_log_out("Terminating Cilux");
1486 k_log_out("---------------------");
1490 void write_to_logfile_cern_style(char* text, int error)
1492 if(!logfile) return;
1506 if(z >=0){ sgn='+'; }
1507 else{ sgn='-'; z= -z; }
1511 strftime(cern, sizeof(cern), CERNDATE, tm);
1513 snprintf(date, sizeof(date), "%s %c%02d%02d", cern, sgn, z/60, z%60);
1515 snprintf(date, sizeof(date), "%s", cern);
1517 FPRINTF(logfile, "[%s|%s] %s%s\n", date, k_ciux,
1518 error? "Warning: ": "", text);
1522 /* -------------------------------------------------------------------------- */
1524 #define EXAMPLE_DATE Fri, 04 Feb 2005 12:14:48 GMT
1525 #define RFC1123STRF "%a, %d %b %Y %H:%M:%S GMT"
1526 #define RFC1123SSCANF "%3s, %d %3s %4d %2d:%2d:%2d GMT"
1530 EXPORT char* k_time_to_rfc(time_t t)
1532 strftime(b, sizeof(b), RFC1123STRF, gmtime(&t));
1536 EXPORT char* k_time_to_rfc_relative(int plus)
1538 time_t t=time(0)+plus;
1539 strftime(b, sizeof(b), RFC1123STRF, gmtime(&t));
1543 EXPORT time_t k_time_from_rfc(char* s)
1545 if(!s || strlen(s)!=29) return -1;
1546 struct tm tm; tm.tm_wday=0; tm.tm_yday=0; tm.tm_isdst=0;
1547 char wd[32], mn[32];
1548 int r=sscanf(s, RFC1123SSCANF, wd, &tm.tm_mday, mn, &tm.tm_year,
1549 &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
1551 tm.tm_mon=(int)k_hashtable_get(monthhash, mn);
1552 if(tm.tm_mon) tm.tm_mon -=1;
1557 EXPORT void k_time_get_now(char* buf, size_t size, char* format)
1568 strftime(buf, size, format, tm);
1571 /* -------------------------------------------------------------------------- */
1573 typedef struct hash_item hash_item;
1575 typedef struct hashtable{ struct hashtable* next;
1583 struct hash_item{ hash_item* next;
1590 /* -------------------------------------------------------------------------- */
1592 #define STRCMPCASE(tab, listkey, key)\
1593 ((tab)->ignorecase? strcasecmp((listkey), (key)): strcmp((listkey), (key)))
1595 #define WARN_SIZE(h)\
1596 if((h)->size && !((h)->size % BX)) k_log_out("%s# %d", (h)->name, (h)->size);
1598 EXPORT k_hashtable* k_hashtable_new(char* name, int ignorecase)
1601 tab=k_malloc(sizeof(hashtable));
1605 tab->lists=k_malloc((tab->buckets)*sizeof(hash_item*));
1606 tab->ignorecase=ignorecase;
1608 int i; for(i=0; i< tab->buckets; i++) tab->lists[i]=0;
1609 return (k_hashtable*)tab;
1612 k_hashtable* k_hashtable_dup2(k_hashtable* tab, int deep)
1615 hashtable* tah=(hashtable*)tab;
1617 tad=k_malloc(sizeof(hashtable));
1618 tad->name=tah->name;
1619 tad->buckets=tah->buckets;
1620 tad->size=tah->size;
1621 tad->lists=k_malloc((tah->buckets)*sizeof(hash_item*));
1622 tad->ignorecase=tah->ignorecase;
1627 for(i=0; i< tah->buckets; i++){
1628 for(lisp=&tah->lists[i], lisd=&tad->lists[i];
1630 lisp=&(*lisp)->next, lisd=&(*lisd)->next){
1632 (*lisd)=k_malloc(sizeof(hash_item));
1633 (*lisd)->key=k_strdup((*lisp)->key);
1638 (*lisd)->val=k_strdup((*lisp)->val);
1641 if(deep && (*lisp)->sub){
1642 (*lisd)->sub=k_hashtable_dup2((*lisp)->sub, 1);
1644 if(!(*lisd)->val && !(*lisd)->sub){
1650 tad->next=(hashtable*)k_hashtable_dup2(tab->next, deep);
1651 return (k_hashtable*)tad;
1654 EXPORT k_hashtable* k_hashtable_dup(k_hashtable* tab)
1656 return k_hashtable_dup2(tab, 0);
1659 EXPORT k_hashtable* k_hashtable_deep(k_hashtable* tab)
1661 return k_hashtable_dup2(tab, 1);
1664 EXPORT k_hashtable* k_hashtable_dip(k_hashtable* tab, char* includes[])
1667 hashtable* tah=(hashtable*)tab;
1669 tad=(hashtable*)k_hashtable_new(tah->name, tah->ignorecase);
1671 for(i=0; includes[i]; i++){
1672 char* in=k_hashtable_get((k_hashtable*)tah, includes[i]);
1675 k_hashtable_put((k_hashtable*)tad, includes[i], in);
1677 tad->next=(hashtable*)k_hashtable_dip(tab->next, includes);
1678 return (k_hashtable*)tad;
1681 EXPORT void k_hashtable_merge(k_hashtable* tab, k_hashtable* tam)
1683 hashtable* tan=(hashtable*)tam;
1686 for(i=0; i< tan->buckets; i++){
1687 for(lisp=&tan->lists[i]; (*lisp); lisp=&(*lisp)->next){
1688 char* key =(*lisp)->key;
1689 void* val =(*lisp)->val;
1690 int free=(*lisp)->free;
1691 k_hashtable* sub =(*lisp)->sub;
1692 if(!*key && free) continue;
1694 k_hashtable_put(tab, key, k_strdup(val));
1697 k_hashtable_sub(tab, key, k_hashtable_dup(sub));
1703 void k_hashtable_set_put(k_hashtable* tab, char* key, void* val, int free)
1705 if(!(tab && key && val)) return;
1706 hashtable* tah=(hashtable*)tab;
1708 lisp=&tah->lists[string_hash(key) % tah->buckets];
1709 while((*lisp) && STRCMPCASE(tah, (*lisp)->key, key)){
1710 lisp=&(*lisp)->next;
1713 (*lisp)=k_malloc(sizeof(hash_item));
1714 (*lisp)->key=k_strdup(key);
1723 if((*lisp)->free) k_free((*lisp)->val);
1724 k_hashtable_delete((*lisp)->sub);
1731 EXPORT void k_hashtable_set(k_hashtable* tab, char* key, void* val)
1733 k_hashtable_set_put(tab, key, val, 0);
1736 EXPORT void k_hashtable_put_int(k_hashtable* tab, char* key, int val)
1738 snprintf(tmpbuf, TMPBUFSIZE, "%d", val);
1739 k_hashtable_set_put(tab, key, k_strdup(tmpbuf), 1);
1742 EXPORT void k_hashtable_put(k_hashtable* tab, char* key, void* val)
1744 k_hashtable_set_put(tab, key, val, 1);
1747 EXPORT void k_hashtable_put_dup(k_hashtable* tab, char* key, char* val)
1749 k_hashtable_set_put(tab, key, k_strdup(val), 1);
1752 EXPORT void k_hashtable_sub(k_hashtable* tab, char* key, k_hashtable* sub)
1754 if(!(tab && key && sub)) return;
1756 hashtable* tah=(hashtable*)tab;
1758 lisp=&tah->lists[string_hash(key) % tah->buckets];
1759 while((*lisp) && STRCMPCASE(tah, (*lisp)->key, key)){
1760 lisp=&(*lisp)->next;
1763 (*lisp)=k_malloc(sizeof(hash_item));
1764 (*lisp)->key=k_strdup(key);
1773 k_hashtable* val =(*lisp)->val;
1774 k_hashtable* head=(*lisp)->sub;
1776 if(val) k_log_err("key '%s' in use: no sub!", key);
1777 else (*lisp)->sub=sub;
1780 while(head->next) head=head->next;
1786 EXPORT void* k_hashtable_get(k_hashtable* tab, char* key)
1788 if(!(tab && key)) return 0;
1789 hashtable* tah=(hashtable*)tab;
1791 list=tah->lists[string_hash(key) % tah->buckets];
1792 while(list && STRCMPCASE(tah, list->key, key)){
1795 return list? (list->val? list->val: list->sub): 0;
1798 EXPORT int k_hashtable_get_int(k_hashtable* tab, char* key)
1800 char* val=k_hashtable_get(tab, key);
1801 return val? atoi(val): 0;
1804 EXPORT char* k_hashtable_get_dup(k_hashtable* tab, char* key)
1806 char* v=k_hashtable_get(tab, key);
1810 EXPORT int k_hashtable_is(k_hashtable* tab, char* key, char* val)
1812 char* v=k_hashtable_get(tab, key);
1813 return (v && val && !strcmp(v, val));
1816 EXPORT int k_hashtable_isi(k_hashtable* tab, char* key, char* val)
1818 char* v=k_hashtable_get(tab, key);
1819 return (v && val && !strcasecmp(v, val));
1822 EXPORT int k_hashtable_isn(k_hashtable* tab, char* key, char* val, size_t size)
1824 char* v=k_hashtable_get(tab, key);
1825 return (v && val && !strncmp(v, val, size));
1828 EXPORT void* k_hashtable_extract(k_hashtable* tab, char* key)
1830 hashtable* tah=(hashtable*)tab;
1833 lisp=&tah->lists[string_hash(key) % tah->buckets];
1834 while((*lisp) && STRCMPCASE(tah, (*lisp)->key, key)){
1835 lisp=&(*lisp)->next;
1839 next= (*lisp)->next;
1840 k_free((*lisp)->key);
1842 if(!val) val=(*lisp)->sub;
1851 EXPORT void k_hashtable_remove(k_hashtable* tab, char* key)
1853 hashtable* tah=(hashtable*)tab;
1856 lisp=&tah->lists[string_hash(key) % tah->buckets];
1857 while((*lisp) && STRCMPCASE(tah, (*lisp)->key, key)){
1858 lisp=&(*lisp)->next;
1861 next= (*lisp)->next;
1862 k_free((*lisp)->key);
1863 if((*lisp)->free) k_free((*lisp)->val);
1864 k_hashtable_delete((*lisp)->sub);
1872 EXPORT void k_hashtable_delete(k_hashtable* tab)
1875 hashtable* tah=(hashtable*)tab;
1879 for(i=0; i< tah->buckets; i++){
1884 if(list->free) k_free(list->val);
1885 k_hashtable_delete(list->sub);
1891 k_hashtable_delete((k_hashtable*)tah->next);
1895 EXPORT void k_hashtable_apply(k_hashtable* tab,
1896 k_hashtable_apply_fn fn,
1900 hashtable* tah=(hashtable*)tab;
1903 for(i=0; i< tah->buckets; i++){
1904 for(lisp=&tah->lists[i]; (*lisp); lisp=&(*lisp)->next){
1906 (*fn)(arg, (*lisp)->key, (*lisp)->val);
1909 (*fn)(arg, (*lisp)->key, (*lisp)->sub);
1915 void k_hashtable_show2(k_hashtable* tab, int chars)
1918 hashtable* tah=(hashtable*)tab;
1919 if(!chars) k_log_out("%s size=%d", tah->name, tah->size);
1922 for(i=0; i< tah->buckets; i++){
1923 for(lisp=&tah->lists[i]; (*lisp); lisp=&(*lisp)->next){
1925 if(*((*lisp)->key)){
1927 (*lisp)->key, (char*)((*lisp)->val));
1931 k_log_out("buck %d key '%s' val %x sub %x",
1932 i, (*lisp)->key, (*lisp)->val, (*lisp)->sub);
1938 EXPORT void k_hashtable_show(k_hashtable* tab)
1940 k_hashtable_show2(tab,0);
1943 EXPORT void k_hashtable_show_chars(k_hashtable* tab)
1945 k_hashtable_show2(tab,1);
1948 int k_hashtable_snprintf_xi(k_hashtable* tab,
1955 if(!tab){ if(size) *buf=0; return 0; }
1958 hashtable* tah=(hashtable*)tab;
1964 for(i=0; i< tah->buckets; i++){
1965 for(lisp=&tah->lists[i]; (*lisp); lisp=&(*lisp)->next){
1966 if(!*((*lisp)->key)) continue;
1967 if(check_i((*lisp)->key, includes, tah->ignorecase)) continue;
1968 if(check_x((*lisp)->key, excludes, tah->ignorecase)) continue;
1971 n=snprintf(at, ln, "%s%s %s" CRLF, ind, (*lisp)->key,
1972 (char*)((*lisp)->val));
1974 if(n>=ln) return size;
1978 k_hashtable* sub=(*lisp)->sub;
1980 n=snprintf(at, ln, "%s%s" CRLF,
1983 if(n>=ln) return size;
1986 n=k_hashtable_snprintf_xi(sub, at, ln, 0, 0,
1989 if(n>=ln) return size;
1992 }while((sub=sub->next));
1999 EXPORT int k_hashtable_snprintf(k_hashtable* tab, char* buf, size_t size)
2001 return k_hashtable_snprintf_xi(tab, buf, size, 0, 0, 0);
2004 EXPORT int k_hashtable_snprintf_i(k_hashtable* tab,
2009 return k_hashtable_snprintf_xi(tab, buf, size, includes, 0, 0);
2012 EXPORT int k_hashtable_snprintf_x(k_hashtable* tab,
2017 return k_hashtable_snprintf_xi(tab, buf, size, 0, excludes, 0);
2020 int check_i(char* key, char* includes[], int ignorecase)
2022 if(!includes) return 0;
2024 for(e=0; includes[e]; e++){
2025 if(ignorecase? !strcasecmp(key, includes[e]):
2026 !strcmp( key, includes[e]) ) break;
2028 return !includes[e];
2031 int check_x(char* key, char* excludes[], int ignorecase)
2033 if(!excludes) return 0;
2035 for(e=0; excludes[e]; e++){
2036 if(ignorecase? !strcasecmp(key, excludes[e]):
2037 !strcmp( key, excludes[e]) ) break;
2039 return !!excludes[e];
2042 unsigned int string_hash(char* p)
2045 while(*p) h=(h<<5)-h+tolower(*p++);
2050 /* -------------------------------------------------------------------------- */