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)