#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. Load more
#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); }