⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tohtml.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#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");		if(h->doc[i].comment)			s = s_appendlist(s, "<br><i>", h->doc[i].comment, "</i>\n", nil);	}	s = s_append(s, "</ul>");	return s;		}String*tohtml(Whist *h, Wdoc *d, int ty){	char *atime;	char *p, *q, ver[40];	int nsub;	Sub sub[3];	String *s, *t;	t = gettemplate(ty);	if(p = strstr(s_to_c(t), "PAGE"))		q = p+4;	else{		p = s_to_c(t)+s_len(t);		q = nil;	}	nsub = 0;	if(h){		sub[nsub] = (Sub){ "TITLE", h->title };		nsub++;	}	if(d){		sprint(ver, "%lud", d->time);		sub[nsub] = (Sub){ "VERSION", ver };		nsub++;		atime = ctime(d->time);		atime[strlen(atime)-1] = '\0';		sub[nsub] = (Sub){ "DATE", atime };		nsub++;	}	s = s_reset(nil);	s = s_appendsub(s, s_to_c(t), p-s_to_c(t), sub, nsub);	switch(ty){	case Tpage:	case Toldpage:		s = pagehtml(s, d->wtxt, ty);		break;	case Tedit:		s = pagetext(s, d->wtxt, 0);		break;	case Tdiff:		s = diffhtml(s, h);		break;	case Thistory:		s = historyhtml(s, h);		break;	case Tnew:	case Twerror:		break;	}	if(q)		s = s_appendsub(s, q, strlen(q), sub, nsub);	s_free(t);	return s;}enum {	LINELEN = 70,};static String*s_appendbrk(String *s, char *p, char *prefix, int dosharp){	char *e, *w, *x;	int first, l;	Rune r;	first = 1;	while(*p){		s = s_append(s, p);		e = strrchr(s_to_c(s), '\n');		if(e == nil)			e = s_to_c(s);		else			e++;		if(utflen(e) <= LINELEN)			break;		x = e; l=LINELEN;		while(l--)			x+=chartorune(&r, x);		x = strchr(x, ' ');		if(x){			*x = '\0';			w = strrchr(e, ' ');			*x = ' ';		}else			w = strrchr(e, ' ');			if(w-s_to_c(s) < strlen(prefix))			break;				x = estrdup(w+1);		*w = '\0';		s->ptr = w;		s_append(s, "\n");		if(dosharp)			s_append(s, "#");		s_append(s, prefix);		if(!first)			free(p);		first = 0;		p = x;	}	if(!first)		free(p);	return s;}static voids_endline(String *s, int dosharp){	if(dosharp){		if(s->ptr == s->base+1 && s->ptr[-1] == '#')			return;		if(s->ptr > s->base+1 && s->ptr[-1] == '#' && s->ptr[-2] == '\n')			return;		s_append(s, "\n#");	}else{		if(s->ptr > s->base+1 && s->ptr[-1] == '\n')			return;		s_append(s, "\n");	}}String*pagetext(String *s, Wpage *page, int dosharp){	int inlist, inpara;	char *prefix, *sharp, tmp[40];	String *t;	Wpage *w;	inlist = 0;	inpara = 0;	prefix = "";	sharp = dosharp ? "#" : "";	s = s_append(s, sharp);	for(w=page; w; w=w->next){		switch(w->type){		case Wheading:			if(inlist){				prefix = "";				inlist = 0;			}			s_endline(s, dosharp);			if(!inpara){				inpara = 1;				s = s_appendlist(s, "\n", sharp, nil);			}			s = s_appendlist(s, w->text, "\n", sharp, "\n", sharp, nil);			break;		case Wpara:			s_endline(s, dosharp);			if(inlist){				prefix = "";				inlist = 0;			}			if(!inpara){				inpara = 1;				s = s_appendlist(s, "\n", sharp, nil);			}			break;		case Wbullet:			s_endline(s, dosharp);			if(!inlist)				inlist = 1;			if(inpara)				inpara = 0;			s = s_append(s, " *\t");			prefix = "\t";			break;		case Wlink:			if(inpara)				inpara = 0;			t = s_append(s_copy("["), w->text);			if(w->url == nil)				t = s_append(t, "]");			else{				t = s_append(t, " | ");				t = s_append(t, w->url);				t = s_append(t, "]");			}			s = s_appendbrk(s, s_to_c(t), prefix, dosharp);			s_free(t);			break;		case Wman:			if(inpara)				inpara = 0;			s = s_appendbrk(s, w->text, prefix, dosharp);			sprint(tmp, "(%d)", w->section);			s = s_appendbrk(s, tmp, prefix, dosharp);			break;					case Wpre:			if(inlist){				prefix = "";				inlist = 0;			}			if(inpara)				inpara = 0;			s_endline(s, dosharp);			s = s_appendlist(s, "! ", w->text, "\n", sharp, nil);			break;		case Whr:			s_endline(s, dosharp);			s = s_appendlist(s, "------------------------------------------------------ \n", sharp, nil);			break;		case Wplain:			if(inpara)				inpara = 0;			s = s_appendbrk(s, w->text, prefix, dosharp);			break;		}	}	s_endline(s, dosharp);	s->ptr--;	*s->ptr = '\0';	return s;}static String*historytext(String *s, Whist *h){	int i;	char tmp[40];	char *atime;	for(i=h->ndoc-1; i>=0; i--){		if(i==h->current)			sprint(tmp, "[current]");		else			sprint(tmp, "[%lud/]", h->doc[i].time);		atime = ctime(h->doc[i].time);		atime[strlen(atime)-1] = '\0';		s = s_appendlist(s, " * ", tmp, " ", atime, 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, "<i>", h->doc[i].comment, "</i>\n", nil);	}	return s;		}String*totext(Whist *h, Wdoc *d, int ty){	char *atime;	char *p, *q, ver[40];	int nsub;	Sub sub[3];	String *s, *t;	t = gettemplate(Ntemplate+ty);	if(p = strstr(s_to_c(t), "PAGE"))		q = p+4;	else{		p = s_to_c(t)+s_len(t);		q = nil;	}	nsub = 0;	if(h){		sub[nsub] = (Sub){ "TITLE", h->title };		nsub++;	}	if(d){		sprint(ver, "%lud", d->time);		sub[nsub] = (Sub){ "VERSION", ver };		nsub++;		atime = ctime(d->time);		atime[strlen(atime)-1] = '\0';		sub[nsub] = (Sub){ "DATE", atime };		nsub++;	}		s = s_reset(nil);	s = s_appendsub(s, s_to_c(t), p-s_to_c(t), sub, nsub);	switch(ty){	case Tpage:	case Toldpage:		s = pagetext(s, d->wtxt, 0);		break;	case Thistory:		s = historytext(s, h);		break;	case Tnew:	case Twerror:		break;	}	if(q)		s = s_appendsub(s, q, strlen(q), sub, nsub);	s_free(t);	return s;}String*doctext(String *s, Wdoc *d){	char tmp[40];	sprint(tmp, "D%lud", d->time);	s = s_append(s, tmp);	if(d->comment){		s = s_append(s, "\nC");		s = s_append(s, d->comment);	}	if(d->author){		s = s_append(s, "\nA");		s = s_append(s, d->author);	}	if(d->conflict)		s = s_append(s, "\nX");	s = s_append(s, "\n");	s = pagetext(s, d->wtxt, 1);	return s;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -