|  | #include "std.h" | 
|  | #include "dat.h" | 
|  |  | 
|  | void | 
|  | lbkick(Logbuf *lb) | 
|  | { | 
|  | char *s; | 
|  | int n; | 
|  | Req *r; | 
|  |  | 
|  | while(lb->wait && lb->rp != lb->wp){ | 
|  | r = lb->wait; | 
|  | lb->wait = r->aux; | 
|  | if(lb->wait == nil) | 
|  | lb->waitlast = &lb->wait; | 
|  | r->aux = nil; | 
|  | if(r->ifcall.count < 5){ | 
|  | respond(r, "factotum: read request count too short"); | 
|  | continue; | 
|  | } | 
|  | s = lb->msg[lb->rp]; | 
|  | lb->msg[lb->rp] = nil; | 
|  | if(++lb->rp == nelem(lb->msg)) | 
|  | lb->rp = 0; | 
|  | n = r->ifcall.count; | 
|  | if(n < strlen(s)+1+1){ | 
|  | memmove(r->ofcall.data, s, n-5); | 
|  | n -= 5; | 
|  | r->ofcall.data[n] = '\0'; | 
|  | /* look for first byte of UTF-8 sequence by skipping continuation bytes */ | 
|  | while(n>0 && (r->ofcall.data[--n]&0xC0)==0x80) | 
|  | ; | 
|  | strcpy(r->ofcall.data+n, "...\n"); | 
|  | }else{ | 
|  | strcpy(r->ofcall.data, s); | 
|  | strcat(r->ofcall.data, "\n"); | 
|  | } | 
|  | r->ofcall.count = strlen(r->ofcall.data); | 
|  | free(s); | 
|  | respond(r, nil); | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | lbread(Logbuf *lb, Req *r) | 
|  | { | 
|  | if(lb->waitlast == nil) | 
|  | lb->waitlast = &lb->wait; | 
|  | *lb->waitlast = r; | 
|  | lb->waitlast = (Req**)(void*)&r->aux; | 
|  | r->aux = nil; | 
|  | lbkick(lb); | 
|  | } | 
|  |  | 
|  | void | 
|  | lbflush(Logbuf *lb, Req *r) | 
|  | { | 
|  | Req **l; | 
|  |  | 
|  | for(l=&lb->wait; *l; l=(Req**)(void*)&(*l)->aux){ | 
|  | if(*l == r){ | 
|  | *l = r->aux; | 
|  | r->aux = nil; | 
|  | if(*l == nil) | 
|  | lb->waitlast = l; | 
|  | closereq(r); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | lbappend(Logbuf *lb, char *fmt, ...) | 
|  | { | 
|  | va_list arg; | 
|  |  | 
|  | va_start(arg, fmt); | 
|  | lbvappend(lb, fmt, arg); | 
|  | va_end(arg); | 
|  | } | 
|  |  | 
|  | void | 
|  | lbvappend(Logbuf *lb, char *fmt, va_list arg) | 
|  | { | 
|  | char *s; | 
|  |  | 
|  | s = vsmprint(fmt, arg); | 
|  | if(s == nil) | 
|  | sysfatal("out of memory"); | 
|  | if(lb->msg[lb->wp]) | 
|  | free(lb->msg[lb->wp]); | 
|  | lb->msg[lb->wp] = s; | 
|  | if(++lb->wp == nelem(lb->msg)) | 
|  | lb->wp = 0; | 
|  | lbkick(lb); | 
|  | } | 
|  |  | 
|  | Logbuf logbuf; | 
|  |  | 
|  | void | 
|  | logread(Req *r) | 
|  | { | 
|  | lbread(&logbuf, r); | 
|  | } | 
|  |  | 
|  | void | 
|  | logflush(Req *r) | 
|  | { | 
|  | lbflush(&logbuf, r); | 
|  | } | 
|  |  | 
|  | void | 
|  | flog(char *fmt, ...) | 
|  | { | 
|  | va_list arg; | 
|  |  | 
|  | va_start(arg, fmt); | 
|  | lbvappend(&logbuf, fmt, arg); | 
|  | va_end(arg); | 
|  | } | 
|  |  |