834 lines · 14.6 KB · C
RawDownload
/*  * 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. */ #include <u.h>#include <libc.h>#include <bio.h>#include <String.h>#include <thread.h>#include "wiki.h" /* * Get HTML and text templates from underlying file system. * Caches them, which means changes don't take effect for * up to Tcache seconds after they are made. *  * If the files are deleted, we keep returning the last * known copy. */enum {	WAIT = 60}; static char *name[2*Ntemplate] = { [Tpage]		"page.html", [Tedit]		"edit.html", [Tdiff]		"diff.html", [Thistory]		"history.html", [Tnew]		"new.html", [Toldpage]	"oldpage.html", [Twerror]		"werror.html", [Ntemplate+Tpage]	"page.txt", [Ntemplate+Tdiff]	"diff.txt", [Ntemplate+Thistory]	"history.txt", [Ntemplate+Toldpage]	"oldpage.txt", [Ntemplate+Twerror]	"werror.txt",}; static struct {	RWLock;	String *s;	ulong t;	Qid qid;} cache[2*Ntemplate]; static voidcacheinit(void){	int i;	static int x;	static Lock l; 	if(x)		return;	lock(&l);	if(x){		unlock(&l);		return;	} 	for(i=0; i<2*Ntemplate; i++)		if(name[i])			cache[i].s = s_copy("");	x = 1;	unlock(&l);} static String*gettemplate(int type){	int n;	Biobuf *b;	Dir *d;	String *s, *ns; 	if(name[type]==nil)		return nil; 	cacheinit(); 	rlock(&cache[type]);	if(0 && cache[type].t+Tcache >= time(0)){		s = s_incref(cache[type].s);		runlock(&cache[type]);		return s;	}	runlock(&cache[type]); //	d = nil;	wlock(&cache[type]);	if(0 && cache[type].t+Tcache >= time(0) || (d = wdirstat(name[type])) == nil)		goto Return; 	if(0 && d->qid.vers == cache[type].qid.vers && d->qid.path == cache[type].qid.path){		cache[type].t = time(0);		goto Return;	} 	if((b = wBopen(name[type], OREAD)) == nil)		goto Return; 	ns = s_reset(nil);	do		n = s_read(b, ns, Bsize);	while(n > 0);	Bterm(b);	if(n < 0) {		s_free(ns);		goto Return;	} 	s_free(cache[type].s);	cache[type].s = ns;	cache[type].qid = d->qid;	cache[type].t = time(0); Return:	free(d);	s = s_incref(cache[type].s);	wunlock(&cache[type]);	return s;} 	/* * Write wiki document in HTML. */static String*s_escappend(String *s, char *p, int pre){	char *q; 	while(q = strpbrk(p, pre ? "<>&" : " <>&")){		s = s_nappend(s, p, q-p);		switch(*q){		case '<':			s = s_append(s, "&lt;");			break;		case '>':			s = s_append(s, "&gt;");			break;		case '&':			s = s_append(s, "&amp;");			break;		case ' ':			s = s_append(s, "\n");		}		p = q+1;	}	s = s_append(s, p);	return s;} static char*mkurl(char *s, int ty){	char *p, *q; 	if(strncmp(s, "http:", 5)==0	|| strncmp(s, "https:", 6)==0	|| strncmp(s, "#", 1)==0	|| strncmp(s, "ftp:", 4)==0	|| strncmp(s, "mailto:", 7)==0	|| strncmp(s, "telnet:", 7)==0	|| strncmp(s, "file:", 5)==0)		return estrdup(s); 	if(strchr(s, ' ')==nil && strchr(s, '@')!=nil){		p = emalloc(strlen(s)+8);		strcpy(p, "mailto:");		strcat(p, s);		return p;	} 	if(ty == Toldpage)		p = smprint("../../%s", s);	else		p = smprint("../%s", s); 	for(q=p; *q; q++)		if(*q==' ')			*q = '_';	return p;} int okayinlist[Nwtxt] ={	[Wbullet]	1,	[Wlink]	1,	[Wman]	1,	[Wplain]	1,}; int okayinpre[Nwtxt] ={	[Wlink]	1,	[Wman]	1,	[Wpre]	1,}; int okayinpara[Nwtxt] ={	[Wpara]	1,	[Wlink]	1,	[Wman]	1,	[Wplain]	1,}; char*nospaces(char *s){	char *q;	s = strdup(s);	if(s == nil)		return nil;	for(q=s; *q; q++)		if(*q == ' ')			*q = '_';	return s;}	String*pagehtml(String *s, Wpage *wtxt, int ty){	char *p, tmp[40];	int inlist, inpara, inpre, t, tnext;	Wpage *w; 	inlist = 0;	inpre = 0;	inpara = 0; 	for(w=wtxt; w; w=w->next){		t = w->type;		tnext = Whr;		if(w->next)			tnext = w->next->type; 		if(inlist && !okayinlist[t]){			inlist = 0;			s = s_append(s, "\n</li>\n</ul>\n");		}		if(inpre && !okayinpre[t]){			inpre = 0;			s = s_append(s, "</pre>\n");		} 		switch(t){		case Wheading:			p = nospaces(w->text);			s = s_appendlist(s, 				"\n<a name=\"", p, "\" /><h3>", 				w->text, "</h3>\n", nil);			free(p);			break; 		case Wpara:			if(inpara){				s = s_append(s, "\n</p>\n");				inpara = 0;			}			if(okayinpara[tnext]){				s = s_append(s, "\n<p class='para'>\n");				inpara = 1;			}			break; 		case Wbullet:			if(!inlist){				inlist = 1;				s = s_append(s, "\n<ul>\n");			}else				s = s_append(s, "\n</li>\n");			s = s_append(s, "\n<li>\n");			break; 		case Wlink:			if(w->url == nil)				p = mkurl(w->text, ty);			else				p = w->url;			s = s_appendlist(s, "<a href=\"", p, "\">", nil);			s = s_escappend(s, w->text, 0);			s = s_append(s, "</a>");			if(w->url == nil)				free(p);			break; 		case Wman:			sprint(tmp, "%d", w->section);			s = s_appendlist(s, 				"<a href=\"http://plan9.bell-labs.com/magic/man2html/",				tmp, "/", w->text, "\"><i>", w->text, "</i>(",				tmp, ")</a>", nil);			break;					case Wpre:			if(!inpre){				inpre = 1;				s = s_append(s, "\n<pre>\n");			}			s = s_escappend(s, w->text, 1);			s = s_append(s, "\n");			break;				case Whr:			s = s_append(s, "<hr />");			break; 		case Wplain:			s = s_escappend(s, w->text, 0);			break;		}	}	if(inlist)		s = s_append(s, "\n</li>\n</ul>\n");	if(inpre)		s = s_append(s, "</pre>\n");	if(inpara)		s = s_append(s, "\n</p>\n");	return s;} static String*copythru(String *s, char **newp, int *nlinep, int l){	char *oq, *q, *r;	int ol; 	q = *newp;	oq = q;	ol = *nlinep;	while(ol < l){		if(r = strchr(q, '\n'))			q = r+1;		else{			q += strlen(q);			break;		}		ol++;	}	if(*nlinep < l)		*nlinep = l;	*newp = q;	return s_nappend(s, oq, q-oq);} static intdodiff(char *f1, char *f2){	int p[2]; 	if(pipe(p) < 0){		return -1;	} 	switch(fork()){	case -1:		return -1; 	case 0:		close(p[0]);		dup(p[1], 1);		execl("/bin/diff", "diff", f1, f2, nil);		_exits(nil);	}	close(p[1]);	return p[0];}  /* print document i grayed out, with only diffs relative to j in black */static String*s_diff(String *s, Whist *h, int i, int j){	char *p, *q, *pnew;	int fdiff, fd1, fd2, n1, n2;	Biobuf b;	char fn1[40], fn2[40];	String *new, *old;	int nline; 	if(j < 0)		return pagehtml(s, h->doc[i].wtxt, Tpage); 	strcpy(fn1, "/tmp/wiki.XXXXXX");	strcpy(fn2, "/tmp/wiki.XXXXXX");	if((fd1 = opentemp(fn1)) < 0 || (fd2 = opentemp(fn2)) < 0){		close(fd1);		s = s_append(s, "\nopentemp failed; sorry\n");		return s;	} 	new = pagehtml(s_reset(nil), h->doc[i].wtxt, Tpage);	old = pagehtml(s_reset(nil), h->doc[j].wtxt, Tpage);	write(fd1, s_to_c(new), s_len(new));	write(fd2, s_to_c(old), s_len(old)); 	fdiff = dodiff(fn2, fn1);	if(fdiff < 0)		s = s_append(s, "\ndiff failed; sorry\n");	else{		nline = 0;		pnew = s_to_c(new);		Binit(&b, fdiff, OREAD);		while(p = Brdline(&b, '\n')){			if(p[0]=='<' || p[0]=='>' || p[0]=='-')				continue;			p[Blinelen(&b)-1] = '\0';			if((p = strpbrk(p, "acd")) == nil)				continue;			n1 = atoi(p+1);			if(q = strchr(p, ','))				n2 = atoi(q+1);			else				n2 = n1;			switch(*p){			case 'a':			case 'c':				s = s_append(s, "<span class='old_text'>");				s = copythru(s, &pnew, &nline, n1-1);				s = s_append(s, "</span><span class='new_text'>");				s = copythru(s, &pnew, &nline, n2);				s = s_append(s, "</span>");				break;			}		}		close(fdiff);		s = s_append(s, "<span class='old_text'>");		s = s_append(s, pnew);		s = s_append(s, "</span>"); 	}	s_free(new);	s_free(old);	close(fd1);	close(fd2);	return s;} static String*diffhtml(String *s, Whist *h){	int i;	char tmp[50];	char *atime; 	for(i=h->ndoc-1; i>=0; i--){		s = s_append(s, "<hr /><div class='diff_head'>\n");		if(i==h->current)			sprint(tmp, "index.html");		else			sprint(tmp, "%lud", h->doc[i].time);		atime = ctime(h->doc[i].time);		atime[strlen(atime)-1] = '\0';		s = s_appendlist(s, 			"<a href=\"", tmp, "\">",			atime, "</a>", nil);		if(h->doc[i].author)			s = s_appendlist(s, ", ", h->doc[i].author, nil);		if(h->doc[i].conflict)			s = s_append(s, ", conflicting write");		s = s_append(s, "\n");		if(h->doc[i].comment)			s = s_appendlist(s, "<br /><i>", h->doc[i].comment, "</i>\n", nil);		s = s_append(s, "</div><hr />");		s = s_diff(s, h, i, i-1);	}	s = s_append(s, "<hr>");	return s;} static String*historyhtml(String *s, Whist *h){	int i;	char tmp[40];	char *atime; 	s = s_append(s, "<ul>\n");	for(i=h->ndoc-1; i>=0; i--){		if(i==h->current)			sprint(tmp, "index.html");		else			sprint(tmp, "%lud", h->doc[i].time);		atime = ctime(h->doc[i].time);		atime[strlen(atime)-1] = '\0';		s = s_appendlist(s, 			"<li><a href=\"", tmp, "\">",			atime, "</a>", nil);		if(h->doc[i].author)			s = s_appendlist(s, ", ", h->doc[i].author, nil);		if(h->doc[i].conflict)			s = s_append(s, ", conflicting write");		s = s_append(s, "\n");

Lines 1–500 of 834.