shithub: riscv

Download patch

ref: 815c2ba22ba5d15cdedd39837d4edb4107eb0b32
parent: f62a2efb7add3ec40ca91adc514d5bdb6b0cd721
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Aug 1 07:20:28 EDT 2015

mothra: support for inline images and <image> tag

--- a/sys/src/cmd/mothra/forms.c
+++ b/sys/src/cmd/mothra/forms.c
@@ -129,7 +129,7 @@
 			form->method = 0;
 			form->fields = 0;
 			form->efields = 0;
-			if(g->state->link[0])
+			if(g->state->link)
 				form->action = strdup(g->state->link);
 			form->next = g->dst->form;
 			g->dst->form = form;
@@ -172,8 +172,10 @@
 		else if(cistrcmp(s, "image")==0){
 			f->type=SUBMIT;
 			s=pl_getattr(g->attr, "src");
-			if(s && *s)
-				nstrcpy(g->state->image, s, sizeof(g->state->image));
+			if(s && *s){
+				free(g->state->image);
+				g->state->image = strdup(s);
+			}
 			s=pl_getattr(g->attr, "width");
 			if(s && *s)
 				g->state->width=strtolength(g, HORIZ, s);
--- a/sys/src/cmd/mothra/getpix.c
+++ b/sys/src/cmd/mothra/getpix.c
@@ -47,7 +47,7 @@
 		t->text=strdup(err);
 		w->changed=1;
 		close(fd);
-		return;
+		goto Out;
 	}
 	typ = snooptype(fd);
 	if(typ < 0 || typ >= nelem(pixcmd) || pixcmd[typ] == nil){
@@ -81,6 +81,9 @@
 	w->pix=p;
 	t->b=b;
 	w->changed=1;
+Out:
+	free(url.basename);
+	free(url.reltext);
 }
 
 void getpix(Rtext *t, Www *w){
--- a/sys/src/cmd/mothra/html.h
+++ b/sys/src/cmd/mothra/html.h
@@ -4,7 +4,7 @@
 #define	NSTACK	100	/* html grammar is not recursive, so 30 or so should do */
 #define	NHBUF	8192	/* Input buffer size */
 #define	NPEEKC	3	/* Maximum lookahead */
-#define	NTOKEN	4096	/* Maximum token length */
+#define	NTOKEN	65536	/* Maximum token length */
 #define	NATTR	512	/* Maximum number of attributes of a tag */
 typedef struct Pair Pair;
 typedef struct Tag Tag;
@@ -37,9 +37,9 @@
 	int strike;		/* flag of <strike> */
 	int width;		/* size of image */
 	int height;
-	char image[NNAME];	/* arg of <img> */
-	char link[NNAME];	/* arg of <a href=...> */
-	char name[NNAME];	/* arg of <a name=...> */
+	char *image;		/* arg of <img> */
+	char *link;		/* arg of <a href=...> */
+	char *name;		/* arg of <a name=...> */
 };
 
 /*
@@ -169,6 +169,7 @@
 	Tag_i,
 	Tag_iframe,
 	Tag_img,
+	Tag_image,
 	Tag_input,
 	Tag_ins,
 	Tag_isindex,
--- a/sys/src/cmd/mothra/html.syntax.c
+++ b/sys/src/cmd/mothra/html.syntax.c
@@ -47,6 +47,7 @@
 [Tag_i]		"i",		END,
 [Tag_iframe]	"iframe",	NOEND,
 [Tag_img]	"img",		NOEND,
+[Tag_image]	"image",	NOEND,
 [Tag_input]	"input",	NOEND,
 [Tag_ins]	"ins",		END,
 [Tag_isindex]	"isindex",	NOEND,
--- a/sys/src/cmd/mothra/mothra.c
+++ b/sys/src/cmd/mothra/mothra.c
@@ -636,9 +636,8 @@
 	char *name, *slash;
 	if(url == nil)
 		return nil;
-	if(url->fullname[0] || url->reltext[0])
-		name = urlstr(url);
-	else
+	name = urlstr(url);
+	if(name == nil || name[0] == 0)
 		name = "/";
 	if(slash = strrchr(name, '/'))
 		name = slash+1;
@@ -945,6 +944,9 @@
 }
 Url* selurl(char *urlname){
 	static Url url;
+
+	free(url.reltext);
+	free(url.basename);
 	seturl(&url, urlname, current ? current->url->fullname : "");
 	selection=&url;
 	message("selected: %s", urlstr(selection));
@@ -952,8 +954,8 @@
 	return selection;
 }
 void seturl(Url *url, char *urlname, char *base){
-	nstrcpy(url->reltext, urlname, sizeof(url->reltext));
-	nstrcpy(url->basename, base, sizeof(url->basename));
+	url->reltext = strdup(urlname);
+	url->basename = strdup(base);
 	url->fullname[0] = 0;
 	url->tag[0] = 0;
 	url->map = 0;
@@ -962,9 +964,13 @@
 	Url *v;
 	v=emalloc(sizeof(Url));
 	*v=*u;
+	v->reltext = strdup(u->reltext);
+	v->basename = strdup(u->basename);
 	return v;
 }
 void freeurl(Url *u){
+	free(u->reltext);
+	free(u->basename);
 	free(u);
 }
 
--- a/sys/src/cmd/mothra/mothra.h
+++ b/sys/src/cmd/mothra/mothra.h
@@ -24,9 +24,9 @@
 	int height;
 };
 struct Url{
+	char *basename;
+	char *reltext;
 	char fullname[NNAME];
-	char basename[NNAME];
-	char reltext[NNAME];
 	char tag[NNAME];
 	int map;		/* is this an image map? */
 };
--- a/sys/src/cmd/mothra/rdhtml.c
+++ b/sys/src/cmd/mothra/rdhtml.c
@@ -62,7 +62,23 @@
 	}
 	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, linespace, 0, 0);
 	g->para=0;
@@ -110,15 +126,15 @@
 		space=1000000;
 	else if(nsp<=0)
 		space=0;
-	if(g->state->image[0]==0 && g->state->link[0]==0 && g->state->name[0]==0 && field==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[0])
+		if(g->state->image)
 			ap->image = strdup(g->state->image);
-		if(g->state->link[0])
+		if(g->state->link)
 			ap->link = strdup(g->state->link);
-		if(g->state->name[0])
+		if(g->state->name)
 			ap->name = strdup(g->state->name);
 		ap->ismap=g->state->ismap;
 		ap->width=g->state->width;
@@ -140,7 +156,7 @@
 		}
 	}
 	flags = 0;
-	if(g->state->link[0])
+	if(g->state->link)
 		flags |= PL_HOT;
 	if(g->state->strike)
 		flags |= PL_STR;
@@ -652,9 +668,9 @@
 	g.state->font=CWIDTH;
 	g.state->size=NORMAL;
 	g.state->pre=0;
-	g.state->image[0]=0;
-	g.state->link[0]=0;
-	g.state->name[0]=0;
+	g.state->image=0;
+	g.state->link=0;
+	g.state->name=0;
 	g.state->margin=0;
 	g.state->indent=20;
 	g.state->ismap=0;
@@ -688,9 +704,9 @@
 	g.state->font=ROMAN;
 	g.state->size=NORMAL;
 	g.state->pre=0;
-	g.state->image[0]=0;
-	g.state->link[0]=0;
-	g.state->name[0]=0;
+	g.state->image=0;
+	g.state->link=0;
+	g.state->name=0;
 	g.state->margin=0;
 	g.state->indent=25;
 	g.state->ismap=0;
@@ -722,11 +738,13 @@
 			if(sp->tag!=g.tag)
 				pl_pushstate(&g, g.tag);
 			else
-				for(;g.state!=sp;--g.state)
+				for(;g.state!=sp;--g.state){
 					if(tag[g.state->tag].action!=OPTEND)
 						htmlerror(g.name, g.lineno,
 							"end tag </%s> missing",
 							tag[g.state->tag].name);
+					pl_popstate(g.state);
+				}
 			break;
 		case END:
 			pl_pushstate(&g, g.tag);
@@ -734,12 +752,12 @@
 		}
 		str=pl_getattr(g.attr, "id");
 		if(str && *str){
-			char swap[NNAME];
+			char *swap;
 
-			nstrcpy(swap, g.state->name, sizeof(swap));
-			nstrcpy(g.state->name, str, sizeof(g.state->name));
+			swap = g.state->name;
+			g.state->name = str;
 			pl_htmloutput(&g, 0, "", 0);
-			nstrcpy(g.state->name, swap, sizeof(g.state->name));
+			g.state->name = swap;
 		}
 		switch(g.tag){
 		default:
@@ -749,10 +767,12 @@
 		case Tag_end:	/* unrecognized start tag */
 			break;
 		case Tag_img:
+		case Tag_image:
 			str=pl_getattr(g.attr, "src");
-			if(str && *str)
-				nstrcpy(g.state->image, str, sizeof(g.state->image));
-			else {
+			if(str && *str){
+				free(g.state->image);
+				g.state->image = strdup(str);
+			} else {
 				Pair *a;
 
 				/*
@@ -764,8 +784,8 @@
 					if(strcmp(a->name, "longdesc") == 0)
 						continue;
 					if(str = linkify(a->value)){
-						nstrcpy(g.state->image, str, sizeof(g.state->image));
-						free(str);
+						free(g.state->image);
+						g.state->image = str;
 						break;
 					}
 				}
@@ -779,13 +799,14 @@
 				g.state->height=strtolength(&g, VERT, str);
 			str=pl_getattr(g.attr, "alt");
 			if(str==0 || *str == 0){
-				if(g.state->image[0])
+				if(g.state->image)
 					str=g.state->image;
 				else
 					str="[[image]]";
 			}
 			pl_htmloutput(&g, 0, str, 0);
-			g.state->image[0]=0;
+			free(g.state->image);
+			g.state->image=0;
 			g.state->ismap=0;
 			g.state->width=0;
 			g.state->height=0;
@@ -818,12 +839,16 @@
 			break;
 		case Tag_a:
 			str=pl_getattr(g.attr, "name");
-			if(str && *str)
-				nstrcpy(g.state->name, str, sizeof(g.state->name));
+			if(str && *str){
+				free(g.state->name);
+				g.state->name = strdup(str);
+			}
 			pl_htmloutput(&g, 0, "", 0);
 			str=pl_getattr(g.attr, "href");
-			if(str && *str)
-				nstrcpy(g.state->link, str, sizeof(g.state->link));
+			if(str && *str){
+				free(g.state->link);
+				g.state->link = strdup(str);
+			}
 			break;
 		case Tag_meta:
 			if((str=pl_getattr(g.attr, "http-equiv"))==0)
@@ -836,9 +861,10 @@
 				break;
 			str++;
 			pl_htmloutput(&g, 0, "[refresh: ", 0);
-			str=unquot(g.state->link, str, sizeof(g.state->link));
+			free(g.state->link);
+			g.state->link=unquot(buf, str, sizeof(buf));
 			pl_htmloutput(&g, 0, str, 0);
-			g.state->link[0]=0;
+			g.state->link=0;
 			pl_htmloutput(&g, 0, "]", 0);
 			g.linebrk=1;
 			g.spacc=0;
@@ -852,16 +878,21 @@
 			snprint(buf, sizeof(buf), "[%s: ", tag[g.tag].name);
 			pl_htmloutput(&g, 0, buf, 0);
 			str=pl_getattr(g.attr, "src");
-			if(str && *str)
-				nstrcpy(g.state->link, str, sizeof(g.state->link));
+			if(str && *str){
+				free(g.state->link);
+				g.state->link = strdup(str);
+			}
 			str=pl_getattr(g.attr, "name");
-			if(str && *str)
-				nstrcpy(g.state->name, str, sizeof(g.state->name));
-			else
+			if(str && *str){
+				free(g.state->name);
+				g.state->name = strdup(str);
+			} else
 				str = g.state->link;
 			pl_htmloutput(&g, 0, str, 0);
-			g.state->link[0]=0;
-			g.state->name[0]=0;
+			free(g.state->link);
+			g.state->link=0;
+			free(g.state->name);
+			g.state->name=0;
 			pl_htmloutput(&g, 0, "]", 0);
 			g.linebrk=1;
 			g.spacc=0;
@@ -1101,7 +1132,9 @@
 						"end tag mismatch <%s>...</%s>, "
 						"intervening tags popped",
 						tag[g.state->tag].name, tag[g.tag].name);
-				g.state=sp-1;
+
+				for(--sp; g.state!=sp; --g.state)
+					pl_popstate(g.state);
 			}
 		}
 		else if(g.state==g.stack)
@@ -1108,7 +1141,7 @@
 			htmlerror(g.name, g.lineno, "end tag </%s> at stack bottom",
 				tag[g.tag].name);
 		else
-			--g.state;
+			pl_popstate(g.state--);
 		switch(g.tag){
 		case Tag_select:
 		case Tag_form:
@@ -1148,19 +1181,22 @@
 	case TEXT:
 		if(g.state->isscript)
 			continue;
-		if(g.state->link[0]==0 && (str = linkify(g.token))){
-			nstrcpy(g.state->link, str, sizeof(g.state->link));
+		if(g.state->link==0 && (str = linkify(g.token))){
+			g.state->link=str; 
 			pl_htmloutput(&g, g.nsp, g.token, 0);
-			g.state->link[0] = 0;
-			free(str);
+			free(g.state->link);
+			g.state->link=0;
 		} else
 			pl_htmloutput(&g, g.nsp, g.token, 0);
 		break;
 	case EOF:
-		for(;g.state!=g.stack;--g.state)
+		for(;g.state!=g.stack;--g.state){
 			if(tag[g.state->tag].action!=OPTEND)
 				htmlerror(g.name, g.lineno,
 					"missing </%s> at EOF", tag[g.state->tag].name);
+			pl_popstate(g.state);
+		}
+		pl_popstate(g.state);
 		*g.tp='\0';
 		getpix(dst->text, dst);
 		finish(dst);
--- a/sys/src/cmd/mothra/url.c
+++ b/sys/src/cmd/mothra/url.c
@@ -6,6 +6,81 @@
 #include "mothra.h"
 
 static int
+hexdigit(int c)
+{
+	if(c >= '0' && c <= '9')
+		return c-'0';
+	if(c >= 'a' && c <= 'f')
+		return c-'a'+10;
+	if(c >= 'A' && c <= 'F')
+		return c-'A'+10;
+	return -1;
+}
+
+static int
+dechex(uchar *out, int lim, char *in, int n)
+{
+	uchar *start, *end;
+	int c;
+
+	start = out;
+	end = start + lim;
+	while(n-- > 0 && out < end){
+		c = *in++;
+		if(c == 0)
+			break;
+		if(c & 0x80)
+			return -1;
+		if(c == '%'){
+			n -= 2;
+			if(n < 0 || (c = hexdigit(*in++)) == -1)
+				return -1;
+			if((c = (c << 4) | hexdigit(*in++)) == -1)
+				return -1;
+		}
+		*out++ = c;
+	}
+	return out - start;
+}
+
+static int
+dataget(Url *url)
+{
+	int (*decfun)(uchar *, int, char *, int) = dechex;
+	char *s, *p;
+	int fd, n, m;
+
+	s = url->reltext;
+	if(cistrncmp(s, "data:", 5) != 0)
+		return -1;
+	s += 5;
+	if((p = strchr(s, ',')) != nil){
+		*p = 0;
+		if(strstr(s, "base64") != nil)
+			decfun = dec64;
+		*p = ',';
+		s = p+1;
+	} else
+		s = strchr(s, 0);
+	n = strlen(s);
+	m = n+64;
+	p = malloc(m);
+	strcpy(p, "/tmp/duXXXXXXXXXXX");
+	if((fd = create(mktemp(p), ORDWR|ORCLOSE, 0600)) < 0){
+		free(p);
+		return -1;
+	}
+	if((m = (*decfun)((uchar*)p, m, s, n)) < 0 || write(fd, p, m) != m){
+		free(p);
+		close(fd);
+		return -1;
+	}
+	free(p);
+	seek(fd, 0, 0);
+	return fd;
+}
+
+static int
 fileget(Url *url)
 {
 	char *rel, *base, *x;
@@ -109,6 +184,8 @@
 	int n, fd;
 
 	if(body < 0){
+		if((fd = dataget(url)) >= 0)
+			return fd;
 		if((fd = fileget(url)) >= 0)
 			return fd;
 		if((fd = webclone(url, buf, sizeof(buf))) < 0)