#include <u.h>#include <libc.h>#include <ctype.h>#include <bio.h> typedef struct Tag Tag;typedef struct Attr Attr;typedef struct Text Text; struct Attr { char attr[64]; char val[256-64];}; struct Tag { Tag *up; char tag[32]; Attr attr[16]; int nattr; int opening; int closing; void (*close)(Text *, Tag *); union { void *aux; };}; struct Text { char* fontstyle; char* fontsize; int pre; int pos; int space; int output; char *bp; char *wp; int nb;}; void eatwhite(void);void parsetext(Text *, Tag *);int parsetag(Tag *);int parseattr(Attr *);void flushtext(Text *);char* getattr(Tag *, char *);int gotattr(Tag *, char *, char *);int gotstyle(Tag *, char *, char *);void reparent(Text *, Tag *, Tag *);void debugtag(Tag *, char *); Biobuf in; voidemitbuf(Text *text, char *buf, int nbuf){ int nw; nw = text->wp - text->bp; if((text->nb - nw) < nbuf){ if(nbuf < 4096) text->nb = nw + 4096; else text->nb = nw + nbuf; text->bp = realloc(text->bp, text->nb); text->wp = text->bp + nw; } memmove(text->wp, buf, nbuf); text->wp += nbuf;} voidemitrune(Text *text, Rune r){ char buf[UTFmax+1]; if(r == '\r' || r =='\n'){ text->pos = 0; text->space = 0; }else text->pos++; emitbuf(text, buf, runetochar(buf, &r));} voidemit(Text *text, char *fmt, ...){ Rune buf[64]; va_list a; int i; if(fmt[0] == '.' && text->pos) emitrune(text, '\n'); va_start(a, fmt); runevsnprint(buf, nelem(buf), fmt, a); va_end(a); for(i=0; buf[i]; i++) emitrune(text, buf[i]);} voidrestoreoutput(Text *text, Tag *){ text->output = 1;} voidongarbage(Text *text, Tag *tag){ if(text->output == 0) return; tag->close = restoreoutput; text->output = 0;} voidonmeta(Text *, Tag *tag){ tag->closing = 1;} voidonp(Text *text, Tag *){ emit(text, ".LP\n");} voidrestorepre(Text *text, Tag *){ text->pre = 0; emit(text, ".DE\n");} voidonpre(Text *text, Tag *tag){ if(text->pre) return; tag->close = restorepre; text->pre = 1; emit(text, ".DS L\n");} voidonli(Text *text, Tag *tag){ if(tag->up && cistrcmp(tag->up->tag, "ol") == 0) emit(text, ".IP\n"); else emit(text, ".IP \\(bu\n"); if(tag->up) tag->up->close = onp;} voidonh(Text *text, Tag *tag){ emit(text, ".SH\n"); tag->close = onp;} voidonbr(Text *text, Tag *tag){ tag->closing = 1; emit(text, ".br\n"); if(cistrcmp(tag->tag, "hr") == 0) emit(text, "\\l'5i'\n.br\n");} voidfontstyle(Text *text, char *style){ if(strcmp(text->fontstyle, style) == 0) return; text->fontstyle = style; emit(text, "\\f%s", style);} voidfontsize(Text *text, char *size){ if(strcmp(text->fontsize, size) == 0) return; text->fontsize = size; emit(text, ".%s\n", size);} voidrestorefontstyle(Text *text, Tag *tag){ fontstyle(text, tag->aux);} voidrestorefontsize(Text *text, Tag *tag){ fontsize(text, tag->aux);} voidoni(Text *text, Tag *tag){ tag->aux = text->fontstyle; tag->close = restorefontstyle; fontstyle(text, "I");} voidonb(Text *text, Tag *tag){ tag->aux = text->fontstyle; tag->close = restorefontstyle; fontstyle(text, "B");} void onsmall(Text *text, Tag *tag);void onsup(Text *text, Tag *tag); voidonsub(Text *text, Tag *tag){ emit(text, "\\v\'0.5\'"); if(cistrcmp(tag->tag, "sub") == 0){ emit(text, "\\x\'0.5\'"); onsmall(text, tag); } else restorefontsize(text, tag); tag->close = onsup;} voidonsup(Text *text, Tag *tag){ emit(text, "\\v\'-0.5\'"); if(cistrcmp(tag->tag, "sup") == 0){ emit(text, "\\x\'-0.5\'"); onsmall(text, tag); }else restorefontsize(text, tag); tag->close = onsub;} /* * this is poor mans CSS handler. */voidonspan(Text *text, Tag *tag){ Attr *a; if(!tag->opening) return; for(a=tag->attr; a < tag->attr+tag->nattr; a++){ if(cistrcmp(a->attr, "class") != 0) continue; if(cistrcmp(a->val, "bold") == 0){ onb(text, tag); return; } if(cistrcmp(a->val, "italic") == 0){ oni(text, tag); return; } if(cistrcmp(a->val, "subscript") == 0){ strcpy(tag->tag, "sub"); onsub(text, tag); strcpy(tag->tag, "span"); return; } if(cistrcmp(a->val, "superscript") == 0){ strcpy(tag->tag, "sup"); onsup(text, tag); strcpy(tag->tag, "span"); return; } }} voidontt(Text *text, Tag *tag){ tag->aux = text->fontstyle; tag->close = restorefontstyle; fontstyle(text, "C");} voidonsmall(Text *text, Tag *tag){ tag->aux = text->fontsize; tag->close = restorefontsize; fontsize(text, "SM");} voidonbig(Text *text, Tag *tag){ tag->aux = text->fontsize; tag->close = restorefontsize; fontsize(text, "LG");} voidendquote(Text *text, Tag *tag){ if(cistrcmp(tag->tag, "q") == 0) emitrune(text, '"'); emit(text, ".QE\n");} voidonquote(Text *text, Tag *tag){ tag->close = endquote; if(cistrcmp(tag->tag, "q") == 0) emit(text, ".QS\n\""); else emit(text, ".QP\n");} typedef struct Table Table;struct Table{ char *bp; int nb; Table *next; Table *prev; int enclose; int brk; char fmt[4]; Text save;}; Tag*tabletag(Tag *tag){ if(tag == nil) return nil; if(cistrcmp(tag->tag, "table") == 0) return tag; return tabletag(tag->up);} voiddumprows(Text *text, Table *s, Table *e){ for(; s != e; s = s->next){ if(s->enclose) emit(text, "T{\n"); if(s->nb <= 0) emit(text, "\\ "); else emitbuf(text, s->bp, s->nb); if(s->enclose) emit(text, "\nT}"); emitrune(text, s->brk ? '\n' : '\t'); }} voidendtable(Text *text, Tag *tag){ int i, cols, rows; Table *t, *h, *s; Tag *tt; /* reverse list */ h = nil; t = tag->aux; for(; t; t = t->prev){ t->next = h; h = t; } /* * nested table case, add our cells to the next table up. * this is the best we can do, tbl doesnt support nesting */ if(tt = tabletag(tag->up)){ while(t = h){ h = h->next; t->next = nil; t->prev = tt->aux; tt->aux = t; } return; } cols = 0; rows = 0; for(i = 0, t = h; t; t = t->next){ i++; if(t->brk){ rows++; if(i > cols) cols = i; i = 0; } } i = 0; for(t = h; t; t = t->next){ i++; if(t->brk){ while(i < cols){ s = mallocz(sizeof(Table), 1); strcpy(s->fmt, "L"); s->brk = t->brk; t->brk = 0; s->next = t->next; t->next = s; i++; } break; } } s = h; while(s){ emit(text, ".TS\n"); if(gotattr(tag, "align", "center")) emit(text, "center ;\n"); i = 0; for(t = s; t; t = t->next){ emit(text, "%s", t->fmt); if(t->brk){ emitrune(text, '\n'); if(++i > 30){ t = t->next; break; } }else emitrune(text, ' '); } emit(text, ".\n"); dumprows(text, s, t); emit(text, ".TE\n"); s = t; } while(t = h){ h = t->next; free(t->bp); free(t); }} voidontable(Text *, Tag *tag){ tag->aux = nil; tag->close = endtable;} voidendcell(Text *text, Tag *tag){ Table *t; Tag *tt; int i; if((tt = tabletag(tag)) == nil) return; if(cistrcmp(tag->tag, "tr") == 0){ if(t = tt->aux) t->brk = 1; } else { t = tag->aux; t->bp = text->bp; t->nb = text->wp - text->bp; for(i=0; i<t->nb; i++) if(strchr(" \t\r\n", t->bp[i]) == nil) break; if(i > 0){ memmove(t->bp, t->bp+i, t->nb - i); t->nb -= i; } while(t->nb > 0 && strchr(" \t\r\n", t->bp[t->nb-1])) t->nb--; if(t->nb < 32){ for(i=0; i<t->nb; i++) if(strchr("\t\r\n", t->bp[i])) break; t->enclose = i < t->nb; } else { t->enclose = 1; } if(gotstyle(tag, "text-align", "center") || gotstyle(tt, "text-align", "center")) strcpy(t->fmt, "C"); elseLines 1–500 of 968. Load more
#include <u.h> #include <libc.h> #include <ctype.h> #include <bio.h> typedef struct Tag Tag; typedef struct Attr Attr; typedef struct Text Text; struct Attr { char attr[64]; char val[256-64]; }; struct Tag { Tag *up; char tag[32]; Attr attr[16]; int nattr; int opening; int closing; void (*close)(Text *, Tag *); union { void *aux; }; }; struct Text { char* fontstyle; char* fontsize; int pre; int pos; int space; int output; char *bp; char *wp; int nb; }; void eatwhite(void); void parsetext(Text *, Tag *); int parsetag(Tag *); int parseattr(Attr *); void flushtext(Text *); char* getattr(Tag *, char *); int gotattr(Tag *, char *, char *); int gotstyle(Tag *, char *, char *); void reparent(Text *, Tag *, Tag *); void debugtag(Tag *, char *); Biobuf in; void emitbuf(Text *text, char *buf, int nbuf) { int nw; nw = text->wp - text->bp; if((text->nb - nw) < nbuf){ if(nbuf < 4096) text->nb = nw + 4096; else text->nb = nw + nbuf; text->bp = realloc(text->bp, text->nb); text->wp = text->bp + nw; } memmove(text->wp, buf, nbuf); text->wp += nbuf; } void emitrune(Text *text, Rune r) { char buf[UTFmax+1]; if(r == '\r' || r =='\n'){ text->pos = 0; text->space = 0; }else text->pos++; emitbuf(text, buf, runetochar(buf, &r)); } void emit(Text *text, char *fmt, ...) { Rune buf[64]; va_list a; int i; if(fmt[0] == '.' && text->pos) emitrune(text, '\n'); va_start(a, fmt); runevsnprint(buf, nelem(buf), fmt, a); va_end(a); for(i=0; buf[i]; i++) emitrune(text, buf[i]); } void restoreoutput(Text *text, Tag *) { text->output = 1; } void ongarbage(Text *text, Tag *tag) { if(text->output == 0) return; tag->close = restoreoutput; text->output = 0; } void onmeta(Text *, Tag *tag) { tag->closing = 1; } void onp(Text *text, Tag *) { emit(text, ".LP\n"); } void restorepre(Text *text, Tag *) { text->pre = 0; emit(text, ".DE\n"); } void onpre(Text *text, Tag *tag) { if(text->pre) return; tag->close = restorepre; text->pre = 1; emit(text, ".DS L\n"); } void onli(Text *text, Tag *tag) { if(tag->up && cistrcmp(tag->up->tag, "ol") == 0) emit(text, ".IP\n"); else emit(text, ".IP \\(bu\n"); if(tag->up) tag->up->close = onp; } void onh(Text *text, Tag *tag) { emit(text, ".SH\n"); tag->close = onp; } void onbr(Text *text, Tag *tag) { tag->closing = 1; emit(text, ".br\n"); if(cistrcmp(tag->tag, "hr") == 0) emit(text, "\\l'5i'\n.br\n"); } void fontstyle(Text *text, char *style) { if(strcmp(text->fontstyle, style) == 0) return; text->fontstyle = style; emit(text, "\\f%s", style); } void fontsize(Text *text, char *size) { if(strcmp(text->fontsize, size) == 0) return; text->fontsize = size; emit(text, ".%s\n", size); } void restorefontstyle(Text *text, Tag *tag) { fontstyle(text, tag->aux); } void restorefontsize(Text *text, Tag *tag) { fontsize(text, tag->aux); } void oni(Text *text, Tag *tag) { tag->aux = text->fontstyle; tag->close = restorefontstyle; fontstyle(text, "I"); } void onb(Text *text, Tag *tag) { tag->aux = text->fontstyle; tag->close = restorefontstyle; fontstyle(text, "B"); } void onsmall(Text *text, Tag *tag); void onsup(Text *text, Tag *tag); void onsub(Text *text, Tag *tag) { emit(text, "\\v\'0.5\'"); if(cistrcmp(tag->tag, "sub") == 0){ emit(text, "\\x\'0.5\'"); onsmall(text, tag); } else restorefontsize(text, tag); tag->close = onsup; } void onsup(Text *text, Tag *tag) { emit(text, "\\v\'-0.5\'"); if(cistrcmp(tag->tag, "sup") == 0){ emit(text, "\\x\'-0.5\'"); onsmall(text, tag); }else restorefontsize(text, tag); tag->close = onsub; } /* * this is poor mans CSS handler. */ void onspan(Text *text, Tag *tag) { Attr *a; if(!tag->opening) return; for(a=tag->attr; a < tag->attr+tag->nattr; a++){ if(cistrcmp(a->attr, "class") != 0) continue; if(cistrcmp(a->val, "bold") == 0){ onb(text, tag); return; } if(cistrcmp(a->val, "italic") == 0){ oni(text, tag); return; } if(cistrcmp(a->val, "subscript") == 0){ strcpy(tag->tag, "sub"); onsub(text, tag); strcpy(tag->tag, "span"); return; } if(cistrcmp(a->val, "superscript") == 0){ strcpy(tag->tag, "sup"); onsup(text, tag); strcpy(tag->tag, "span"); return; } } } void ontt(Text *text, Tag *tag) { tag->aux = text->fontstyle; tag->close = restorefontstyle; fontstyle(text, "C"); } void onsmall(Text *text, Tag *tag) { tag->aux = text->fontsize; tag->close = restorefontsize; fontsize(text, "SM"); } void onbig(Text *text, Tag *tag) { tag->aux = text->fontsize; tag->close = restorefontsize; fontsize(text, "LG"); } void endquote(Text *text, Tag *tag) { if(cistrcmp(tag->tag, "q") == 0) emitrune(text, '"'); emit(text, ".QE\n"); } void onquote(Text *text, Tag *tag) { tag->close = endquote; if(cistrcmp(tag->tag, "q") == 0) emit(text, ".QS\n\""); else emit(text, ".QP\n"); } typedef struct Table Table; struct Table { char *bp; int nb; Table *next; Table *prev; int enclose; int brk; char fmt[4]; Text save; }; Tag* tabletag(Tag *tag) { if(tag == nil) return nil; if(cistrcmp(tag->tag, "table") == 0) return tag; return tabletag(tag->up); } void dumprows(Text *text, Table *s, Table *e) { for(; s != e; s = s->next){ if(s->enclose) emit(text, "T{\n"); if(s->nb <= 0) emit(text, "\\ "); else emitbuf(text, s->bp, s->nb); if(s->enclose) emit(text, "\nT}"); emitrune(text, s->brk ? '\n' : '\t'); } } void endtable(Text *text, Tag *tag) { int i, cols, rows; Table *t, *h, *s; Tag *tt; /* reverse list */ h = nil; t = tag->aux; for(; t; t = t->prev){ t->next = h; h = t; } /* * nested table case, add our cells to the next table up. * this is the best we can do, tbl doesnt support nesting */ if(tt = tabletag(tag->up)){ while(t = h){ h = h->next; t->next = nil; t->prev = tt->aux; tt->aux = t; } return; } cols = 0; rows = 0; for(i = 0, t = h; t; t = t->next){ i++; if(t->brk){ rows++; if(i > cols) cols = i; i = 0; } } i = 0; for(t = h; t; t = t->next){ i++; if(t->brk){ while(i < cols){ s = mallocz(sizeof(Table), 1); strcpy(s->fmt, "L"); s->brk = t->brk; t->brk = 0; s->next = t->next; t->next = s; i++; } break; } } s = h; while(s){ emit(text, ".TS\n"); if(gotattr(tag, "align", "center")) emit(text, "center ;\n"); i = 0; for(t = s; t; t = t->next){ emit(text, "%s", t->fmt); if(t->brk){ emitrune(text, '\n'); if(++i > 30){ t = t->next; break; } }else emitrune(text, ' '); } emit(text, ".\n"); dumprows(text, s, t); emit(text, ".TE\n"); s = t; } while(t = h){ h = t->next; free(t->bp); free(t); } } void ontable(Text *, Tag *tag) { tag->aux = nil; tag->close = endtable; } void endcell(Text *text, Tag *tag) { Table *t; Tag *tt; int i; if((tt = tabletag(tag)) == nil) return; if(cistrcmp(tag->tag, "tr") == 0){ if(t = tt->aux) t->brk = 1; } else { t = tag->aux; t->bp = text->bp; t->nb = text->wp - text->bp; for(i=0; i<t->nb; i++) if(strchr(" \t\r\n", t->bp[i]) == nil) break; if(i > 0){ memmove(t->bp, t->bp+i, t->nb - i); t->nb -= i; } while(t->nb > 0 && strchr(" \t\r\n", t->bp[t->nb-1])) t->nb--; if(t->nb < 32){ for(i=0; i<t->nb; i++) if(strchr("\t\r\n", t->bp[i])) break; t->enclose = i < t->nb; } else { t->enclose = 1; } if(gotstyle(tag, "text-align", "center") || gotstyle(tt, "text-align", "center")) strcpy(t->fmt, "C"); else