1249 lines · 25.1 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <draw.h>#include <event.h>#include <panel.h>#include "mothra.h"#include "html.h"#include "rtext.h" typedef struct Fontdata Fontdata;struct Fontdata{	char *name;	Font *font;	int space;}fontlist[4][4]={/* original */	"lucidasans/unicode.7", 0, 0,	"lucidasans/unicode.8", 0, 0,	"lucidasans/unicode.10", 0, 0,	"lucidasans/unicode.13", 0, 0, 	"lucidasans/italicunicode.7", 0, 0,	"lucidasans/italicunicode.8", 0, 0,	"lucidasans/italicunicode.10", 0, 0,	"lucidasans/italicunicode.13", 0, 0, 	"lucidasans/boldunicode.7", 0, 0,	"lucidasans/boldunicode.8", 0, 0,	"lucidasans/boldunicode.10", 0, 0,	"lucidasans/boldunicode.13", 0, 0, 	"lucidasans/typeunicode.7", 0, 0,	"pelm/unicode.8", 0, 0,	"lucidasans/typeunicode.12", 0, 0,	"lucidasans/typeunicode.16", 0, 0,}; static struct{	char *prefix;	int len;}links[]={	{"http://", 7},	{"https://", 8},	{"gemini://", 9},	{"ftp://", 6},}; Font *pl_whichfont(int f, int s, int *space){	char name[NNAME]; 	assert(f >= 0 && f < 4);	assert(s >= 0 && s < 4); 	if(fontlist[f][s].font==0){		snprint(name, sizeof(name), "/lib/font/bit/%s.font", fontlist[f][s].name);		fontlist[f][s].font=openfont(display, name);		if(fontlist[f][s].font==0) fontlist[f][s].font=font;		fontlist[f][s].space=stringwidth(fontlist[f][s].font, "0");	}	if(space)		*space = fontlist[f][s].space;	return fontlist[f][s].font;} void getfonts(void){	int f, s;	for(f=0;f!=4;f++)		for(s=0;s!=4;s++)			pl_whichfont(f, s, nil);}void pl_pushstate(Hglob *g, int t){	++g->state;	if(g->state==&g->stack[NSTACK]){		htmlerror(g->name, g->lineno, "stack overflow at <%s>", tag[t].name);		--g->state;	}	g->state[0]=g->state[-1];	g->state->tag=t; 	if(g->state->name)		g->state->name = strdup(g->state->name);	if(g->state->link)		g->state->link = strdup(g->state->link);	if(g->state->image)		g->state->image = strdup(g->state->image);}void pl_popstate(Stack *state){	free(state->name);	state->name=0;	free(state->link);	state->link=0;	free(state->image);	state->image=0;} void pl_linespace(Hglob *g){	plrtbitmap(&g->dst->text, 1000000, 0, 0, linespace, 0, 0);	g->para=0;	g->linebrk=0;} int strtolength(Hglob *g, int dir, char *str){	double f;	Point p; 	f = atof(str);	if(cistrstr(str, "%"))		return 0;	if(cistrstr(str, "em")){		p=stringsize(pl_whichfont(g->state->font, g->state->size, nil), "M");		return floor(f*((dir==HORIZ) ? p.x : p.y));	}	return floor(f);} void pl_htmloutput(Hglob *g, int nsp, char *s, Field *field){	Font *f;	int space, indent, flags, voff;	Action *ap;	if(g->state->tag==Tag_title/*	|| g->state->tag==Tag_textarea */	|| g->state->tag==Tag_select){		if(s){			if(g->tp!=g->text && g->tp!=g->etext && g->tp[-1]!=' ')				*g->tp++=' ';			while(g->tp!=g->etext && *s) *g->tp++=*s++;			if(g->state->tag==Tag_title) g->dst->changed=1;			*g->tp='\0';		}		return;	}	voff = 0;	f=pl_whichfont(g->state->font, g->state->size, &space);	if(g->state->sub){		voff = g->state->sub * f->ascent / 2;		g->state->size = SMALL;		f=pl_whichfont(g->state->font, g->state->size, &space);	}	indent=g->state->margin;	if(g->para){		space=1000000;		indent+=g->state->indent;	}	else if(g->linebrk)		space=1000000;	else if(nsp<=0)		space=0;	if(g->state->image==0 && g->state->link==0 && g->state->name==0 && field==0)		ap=0;	else{		ap=emalloc(sizeof(Action));		if(g->state->image)			ap->image = strdup(g->state->image);		if(g->state->link)			ap->link = strdup(g->state->link);		if(g->state->name)			ap->name = strdup(g->state->name);		ap->ismap=g->state->ismap;		ap->width=g->state->width;		ap->height=g->state->height;		ap->field=field;	}	if(space<0) space=0;	if(indent<0) indent=0;	if(g->state->pre && s[0]=='\t'){		space=0;		while(s[0]=='\t'){			space++;			s++;		}		space=PL_TAB|space;		if(g->linebrk){			indent=space;			space=1000000;		}	}	flags = 0;	if(g->state->link)		flags |= PL_HOT;	if(g->state->strike)		flags |= PL_STR;	plrtstr(&g->dst->text, space, indent, voff, f, strdup(s), flags, ap);	g->para=0;	g->linebrk=0;	g->dst->changed=1;} /* * Buffered read, no translation * Save in cache. */int pl_bread(Hglob *g){	int n, c;	char err[1024];	if(g->hbufp==g->ehbuf){		n=read(g->hfd, g->hbuf, NHBUF);		if(n<=0){			if(n<0){				snprint(err, sizeof(err), "%r reading %s", g->name);				pl_htmloutput(g, 1, err, 0);			}			g->heof=1;			return EOF;		}		g->hbufp=g->hbuf;		g->ehbuf=g->hbuf+n;	}	c=*g->hbufp++&255;	if(c=='\n') g->lineno++;	return c;}/* * Read a character, translating \r\n, \n\r, \r and \n into \n * convert to runes. */int pl_readc(Hglob *g){	static int peek=-1;	char crune[UTFmax+1];	int c, n;	Rune r; 	if(peek!=-1){		c=peek;		peek=-1;	}	else		c=pl_bread(g);	if(c=='\r'){		c=pl_bread(g);		if(c!='\n') peek=c;		return '\n';	}	if(c=='\n'){		c=pl_bread(g);		if(c!='\r') peek=c;		return '\n';	} 	if(c < Runeself)		return c; 	crune[0]=c;	for (n=1; n<=sizeof(crune); n++){		if(fullrune(crune, n)){			chartorune(&r, crune);			return r;		}		c=pl_bread(g);		if(c==EOF)			return EOF;		crune[n]=c;	}	return c;}void pl_putback(Hglob *g, int c){	if(g->npeekc==NPEEKC) htmlerror(g->name, g->lineno, "too much putback!");	else if(c!=EOF) g->peekc[g->npeekc++]=c;}int pl_nextc(Hglob *g){	int c; 	if(g->heof) return EOF;	if(g->npeekc!=0) return g->peekc[--g->npeekc];	c=pl_readc(g);	if(c=='<'){		c=pl_readc(g);		if(c=='/'){			c=pl_readc(g);			pl_putback(g, c);			pl_putback(g, '/');			if('a'<=c && c<='z' || 'A'<=c && c<='Z') return STAG;			return '<';		}		pl_putback(g, c);		if(c=='!' || 'a'<=c && c<='z' || 'A'<=c && c<='Z' || c=='?') return STAG;		return '<';	}	if(c=='>') return ETAG;	return c;} char *unquot(char *src){	char *e, *dst;	int len; 	e=0;	while(*src && strchr(" \t\r\n", *src))		src++;	if(*src=='\'' || *src=='"'){		e=strrchr(src+1, *src);		src++;	}	if(e==0) e=strchr(src, 0);	len=e-src;	dst = emalloc(len+1);	memmove(dst, src, len);	dst[len]=0;	return dst;}int alnumchar(int c){	return 'a'<=c && c<='z' || 'A'<=c && c<='Z' || '0'<=c && c<='9';}int entchar(int c){	return c=='#' || alnumchar(c);} /* return url if text token looks like a hyperlink */char *linkify(char *s){	int i;	if(s == 0 && s[0] == 0)		return 0;	for(i = 0; i < nelem(links); i++)		if(!cistrncmp(s, links[i].prefix, links[i].len))			return strdup(s);	if(!cistrncmp(s, "www.", 4)){		int d, i; 		d = 1;		for(i=4; s[i]; i++){			if(s[i] == '.'){				if(s[i-1] == '.')					return 0;				d++;			} else if(!alnumchar(s[i]))				break;		}		if(d >= 2)			return smprint("http://%s", s);	}	return 0;} /* * remove entity references, in place. * Potential bug: *	This doesn't work if removing an entity reference can lengthen the string! *	Fortunately, this doesn't happen. */void pl_rmentities(Hglob *, char *s){	char *t, *u, c, svc;	t=s;	do{		c=*s++;		if(c=='&'		&& ((*s=='#' && strchr("0123456789Xx", s[1]))		  || 'a'<=*s && *s<='z'		  || 'A'<=*s && *s<='Z')){			u=s;			while(entchar(*s)) s++;			svc=*s;			*s = 0;			if(svc==';') s++;			if(strcmp(u, "lt") == 0)				*t++='<';			else if(strcmp(u, "gt") == 0)				*t++='>';			else if(strcmp(u, "quot") == 0)				*t++='"';			else if(strcmp(u, "apos") == 0)				*t++='\'';			else if(strcmp(u, "amp") == 0)				*t++='&';			else {				if(svc==';') s--;				*s=svc;				*t++='&';				while(u<s)					*t++=*u++;			}		}		else if((uchar)c == 0xc2 && (uchar)*s == 0xad)			s++; /* ignore soft hyphens */		else			*t++=c;	}while(c);}/* * Skip over white space */char *pl_whitespace(char *s){	while(*s==' ' || *s=='\t' || *s=='\n' || *s=='\r') s++;	return s;}/* * Skip over HTML word */char *pl_word(char *s){	if ('a'<=*s && *s<='z' || 'A'<=*s && *s<='Z') {		s++;		while('a'<=*s && *s<='z' || 'A'<=*s && *s<='Z' || '0'<=*s && *s<='9' || 			*s=='-' || *s=='.' || *s==':') s++;	}	return s;}/* * Skip to matching quote */char *pl_quote(char *s){	char q;	q=*s++;	while(*s!=q && *s!='\0') s++;	return s;}void pl_dnl(char *s){	char *t;	for(t=s;*s;s++) if(*s!='\r' && *s!='\n') *t++=*s;	*t='\0';}void pl_tagparse(Hglob *g, char *str){	char *s, *t, *name, c;	Pair *ap;	Tag *tagp;	g->tag=Tag_end;	ap=g->attr;	if(str[0]=='!'){	/* test should be strncmp(str, "!--", 3)==0 */		g->tag=Tag_comment;		ap->name=0;		return;	}	if(str[0]=='/') str++;	name=str;	s=pl_word(str);	if(*s!='/' && *s!=' ' && *s!='\n' && *s!='\t' && *s!='\0'){		htmlerror(g->name, g->lineno, "bad tag name in %s", str);		ap->name=0;		return;	}	if(*s!='\0') *s++='\0';	for(t=name;t!=s;t++) if('A'<=*t && *t<='Z') *t+='a'-'A';	/*	 * Binary search would be faster here	 */	for(tagp=tag;tagp->name;tagp++) if(strcmp(name, tagp->name)==0) break;	g->tag=tagp-tag;	if(g->tag==Tag_end) htmlerror(g->name, g->lineno, "no tag %s", name);	for(;;){		s=pl_whitespace(s);		if(*s=='\0'){			ap->name=0;			return;		}		ap->name=s;		s=pl_word(s);		t=pl_whitespace(s);		c=*t;		*s='\0';		for(s=ap->name;*s;s++) if('A'<=*s && *s<='Z') *s+='a'-'A';		if(c=='='){			s=pl_whitespace(t+1);			if(*s=='\'' || *s=='"'){				ap->value=s+1;				s=pl_quote(s);				if(*s=='\0'){					htmlerror(g->name, g->lineno,						"No terminating quote in rhs of attribute %s",						ap->name);					ap->name=0;					return;				}				*s++='\0';				pl_dnl(ap->value);			}			else{				/* read up to white space or > */				ap->value=s;				while(*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0') s++;				if(*s!='\0') *s++='\0';			}			pl_rmentities(g, ap->value);		}		else{			if(c!='\0') s++;			ap->value="";		}		if(ap==&g->attr[NATTR-1])			htmlerror(g->name, g->lineno, "too many attributes!");		else ap++;	}}int pl_getcomment(Hglob *g){	int c;	if((c=pl_nextc(g))=='-' && (c=pl_nextc(g))=='-'){		/* <!-- eats everything until --> or EOF */		for(;;){			while((c=pl_nextc(g))!='-' && c!=EOF)				;			if(c==EOF)				break;			if(pl_nextc(g)=='-'){				while((c=pl_nextc(g))=='-')					;				if(c==ETAG || c==EOF)					break;			}		}	} else {		/* <! eats everything until > or EOF */		while(c!=ETAG && c!=EOF)			c=pl_nextc(g);	}

Lines 1–500 of 1249.