/*
 * This file is part of the UCB release of Plan 9. It is subject to the license
 * terms in the LICENSE file found in the top-level directory of this
 * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
 * part of the UCB release of Plan 9, including this file, may be copied,
 * modified, propagated, or distributed except according to the terms contained
 * in the LICENSE file.
 */
/* Portions of this file are Copyright (C) 9front's team.
 * See /doc/license/9front-mit for details about the licensing.
 * See http://code.9front.org/hg/plan9front/ for a list of authors.
 */
#include "dat.h"

static void
logbufproc(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
logbufread(Logbuf *lb, Req *r)
{
	qlock(lb);
	if(lb->waitlast == nil)
		lb->waitlast = &lb->wait;
	*(lb->waitlast) = r;
	lb->waitlast = (Req **)&r->aux;
	r->aux = nil;
	logbufproc(lb);
	qunlock(lb);
}

void
logbufflush(Logbuf *lb, Req *r)
{
	Req **l;

	qlock(lb);
	for(l=&lb->wait; *l; l=(Req **)(&(*l)->aux)){
		if(*l == r){
			*l = r->aux;
			if(*l == nil)
				lb->waitlast = l;
			r->aux = nil;
			respond(r, "interrupted");
			break;
		}
	}
	qunlock(lb);
}

void
logbufappend(Logbuf *lb, char *buf)
{
	if(debug)
		fprint(2, "%s\n", buf);

	qlock(lb);
	if(lb->msg[lb->wp])
		free(lb->msg[lb->wp]);
	lb->msg[lb->wp] = estrdup9p(buf);
	if(++lb->wp == nelem(lb->msg))
		lb->wp = 0;
	logbufproc(lb);
	qunlock(lb);
}

Logbuf logbuf;

void
logread(Req *r)
{
	logbufread(&logbuf, r);
}

void
logflush(Req *r)
{
	logbufflush(&logbuf, r);
}

void
flog(char *fmt, ...)
{
	char buf[1024];
	va_list arg;

	va_start(arg, fmt);
	vseprint(buf, buf+sizeof buf, fmt, arg);
	va_end(arg);
	logbufappend(&logbuf, buf);
}

