💾 Archived View for runjimmyrunrunyoufuckerrun.com › src › htmlfmt.c captured on 2021-12-17 at 13:26:06.

View Raw

More Information

-=-=-=-=-=-=-

#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include <html.h>
int br, wrap, nfn, nallocfn = 64, width = 70;
char *defcharset, **fn;
Rune *url, *l;
Biobuf out;
Anchor *curanchor;
void*
emalloc(ulong n){
	void *p;
	p = malloc(n);
	if(p == nil)
		sysfatal("malloc: %r");
	memset(p, 0, n);
	return p;
}
void*
erealloc(void *p, ulong n){
	p = realloc(p, n);
	if(p == nil)
		sysfatal("realloc: %r");
	return p;
}
void
spew(Rune *s){
	static int off;
	Rune *sp;
	int n;
	if(br & IFbrk){
		Bprint(&out, "%.*S\n", off, l);
		if(br & IFbrksp) Bputc(&out, '\n');
		br = off = 0;
	}
	if(s == nil || *s == 0)
		return;
	if(!wrap){
		Bprint(&out, "%S", s);
		return;
	}
	for(;;){
		n = runestrlen(s);
		if(off + n <= width){
			runestrncpy(l + off, s, n);
			off += n;
			return;
		}
		n = width - off;
		runestrncpy(l + off, s, n);
		s += n;
		sp = runestrrchr(l, ' ');
		if(sp == nil){ /*long line */
			off = 0;
			Bprint(&out, "%.*S", width, l);
			sp = runestrchr(s, ' ');
			if(sp == nil){
				Bprint(&out, "%S\n", s);
				return;
			}
			Bprint(&out, "%.*S\n", (int)(sp - s), s);
			s = sp + 1;
			continue;
		}
		n = sp - l;
		Bprint(&out, "%.*S\n", n, l);
		off = width - n - 1;
		runestrncpy(l, sp + 1, off);
	}
}
void
addfn(Rune *ref){
	static Rune *a = L"⁰¹²³⁴⁵⁶⁷⁸⁹";
	Rune *num, *r;
	num = runesmprint("%d", nfn + 1);
	if(num == nil) sysfatal("smprint: %r");
	for(r = num; *r; r++)
		*r = a[*r - '0'];
	if(nfn >= nallocfn)
		fn = erealloc(fn, (nallocfn <<= 1) * sizeof(char*));
	fn[nfn] = smprint("%S %S\n", num, ref);
	if(fn[nfn] == nil) sysfatal("smprint: %r");
	spew(num);
	free(num);
	nfn++;
}
void
render(Item *item){
	static Rune *ftype[] = {
		L"§ input: ", L"§ password: ", L"□ ", L"○ ",
		L"[submit] ", L"§ hidden: ", L"§ image: ", L"§ reset: ",
		L"§ file: ", L"§ button: ", L"§ dropdown: ", L"§ textarea: "
	};
	Itext *txt; Iimage *img; Area *area;
	Formfield *field; Option *opt;
	Table *table; Tablecell *cell;
	Item *subitem;
	br |= item->state;
	if(wrap ^ item->state & IFwrap){
		br |= IFbrk;
		wrap = item->state & IFwrap;
	}
	if(item->anchor != curanchor){
		if(curanchor != nil)
			addfn(curanchor->href);
		curanchor = item->anchor;
		return;
	}
	switch(item->tag){
	case Itexttag:
		txt = (Itext*)item;
		if(txt->ul == ULmid){
			spew(L"<strike>"); spew(txt->s); spew(L"</strike>");
		}else
			spew(txt->s);
		if(item->state & IFhangmask) /* list marker */
			spew(L" ");
		break;
	case Iruletag:
		br = IFbrk | IFbrksp;
		spew(nil);
		Bprint(&out, " %0*d ", width - 2, 0); /* hahaha */
		br = IFbrk | IFbrksp;
		break;
	case Iimagetag:
		img = (Iimage*)item;
		if(img->map != nil){
			if(curanchor != nil){
				addfn(curanchor->href);
				curanchor = nil;
			}
			br = IFbrk | IFbrksp;
			spew(L"§imagemap:");
			br = IFbrk;
		}
	fimage:
		spew(L"{");
		spew(img->altrep);
		addfn(img->imsrc);
		spew(L"}");
		if(img->map == nil)
			break;
		for(area = img->map->areas; area != nil; area = area->next){
			br = IFbrk;
			spew(area->anchor->name);
			addfn(area->anchor->href);
		}
		br = IFbrk | IFbrksp;
		break;
	case Iformfieldtag:
		br |= IFbrk;
		field = ((Iformfield*)item)->formfield;
		spew(ftype[field->ftype]);
		spew(field->name);
		spew(L": ");
		spew(field->value);
		if(field->ftype == Fimage){
			img = (Iimage*)field->image;
			goto fimage;
		}
		br = IFbrk;
		if(field->ftype == Fselect){
			spew(nil);
			for(opt = field->options; opt != nil; opt = opt->next)
				Bprint(&out, "→ %S (%S)\n", opt->display, opt->value);
		}
		break;
	case Itabletag:
		table = ((Itable*)item)->table;
		if(table->caption_place == ALtop)
			spew(table->caption);
		br |= IFbrk;
		cell = table->cells;
		while(cell != nil){
			for(subitem = cell->content; subitem != nil; subitem = subitem->next)
				render(subitem);
			if(cell->nextinrow == nil){
				br |= IFbrk;
				cell = cell->next;
				continue;
			}
			spew(L"\t");
			cell = cell->nextinrow;
		}
		br |= IFbrk;
		if(table->caption_place == ALbottom)
			spew(table->caption);
		break;
	case Ifloattag:
		for(subitem = ((Ifloat*)item)->item; subitem != nil; subitem = subitem->next)
			render(subitem);
		break;
	case Ispacertag:
		switch(((Ispacer*)item)->spkind){
		case ISPvline:
			br = IFbrk | IFbrksp;
			break;
		case ISPhspace: case ISPgeneral: default:
			if(!(br & IFbrk))
				spew(L" ");
		case ISPnull:
			break;
		}
		break;
	default:
		fprint(2, "unknown item tag %d\n", item->tag);
	}
}
void
frames(Kidinfo *k){
	while(k != nil){
		if(k->isframeset){
			Bprint(&out, "\nFrameset: %S", k->name);
			frames(k->kidinfos);
		}
		else
			Bprint(&out, "\nFrame: %S: %S", k->name, k->src);
		k = k->next;
	}
}
void
loadhtml(int fd){
	Docinfo *d;
	Item *items, *i;
	uchar *buf;
	long n, nbuf, nalloc;
	int p[2];
	if(pipe(p) < 0)
		sysfatal("pipe: %r");
	switch(fork()){
	case -1:
		sysfatal("fork: %r");
	case 0:
		dup(fd, 0);
		dup(p[1], 1);
		close(p[1]);
		close(p[0]);
		if(defcharset)
			execl("/bin/uhtml", "uhtml", "-c", defcharset, nil);
		execl("/bin/uhtml", "uhtml", nil);
		execl("/bin/cat", "cat", nil);
		sysfatal("execl: %r");
	}
	close(p[1]);
	buf = erealloc(nil, nalloc = 8192);
	nbuf = 0;
	while(n = read(p[0], buf + nbuf, nalloc - nbuf))
		if((nbuf += n) > nalloc / 2)
			buf = erealloc(buf, nalloc <<= 1);
	close(p[0]);
	close(fd);
	if(nbuf == 0){
		free(buf);
		return;
	}
	buf = erealloc(buf, nbuf);
	items = parsehtml(buf, nbuf, url, TextHtml, UTF_8, &d);
	free(buf);
	Bprint(&out, "%S", d->doctitle);
	frames(d->kidinfo);
	br = IFbrk | IFbrksp;
	for(i = items; i != nil; i = i->next)
		render(i);
	if(curanchor != nil)
		addfn(curanchor->href);
	br = IFbrk;
	spew(nil);
	freeitems(items);
	freedocinfo(d);
}
void
usage(void){
	fprint(2, "usage: %s [-c charset] [-u URL] [-l length] [file ...]\n", argv0);
	exits("usage");
}
void
main(int argc, char *argv[]){
	int i, fd;
	char *s;
	ARGBEGIN{
	case 'c':
		defcharset = EARGF(usage());
		break;
	case 'l': case 'w':
		s = EARGF(usage());
		width = atoi(s);
		if(width < 1)
			usage();
		break;
	case 'u':
		s = EARGF(usage());
		free(url);
		url = emalloc((utflen(s) + 1) * sizeof(Rune));
		for(i = 0; *s; i++)
			s += chartorune(url + i, s);
		break;
	default:
		usage();
	}ARGEND
	Binit(&out, 1, OWRITE);
	l = emalloc(width * sizeof(Rune));
	fn = erealloc(nil, nallocfn * sizeof(char*));
	s = nil;
	if(argc == 0)
		loadhtml(0);
	else
		for(i = 0; i < argc; i++){
			fd = open(argv[i], OREAD);
			if(fd < 0){
				fprint(2, "skipping %s: open: %r\n", argv[i]);
				s = "open error";
				continue;
			}
			if(i) Bputc(&out, '\n');
			if(argc > 1) Bprint(&out, "→ %s: ", argv[i]);
			loadhtml(fd);
		}
	free(l);
	if(nfn){
		Bwrite(&out, "\nReferences:\n", 13);
		for(i = 0; i < nfn; i++){
			Bwrite(&out, fn[i], strlen(fn[i]));
			free(fn[i]);
		}
	}
	free(fn);
	exits(s);
}