Plan 9 from Bell Labs’s /usr/web/sources/extra/i/i.h

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include <u.h>
#include <libc.h>
#include <draw.h>
#include <ctype.h>
#include <thread.h>
#include "assert.h"

// UTILS
typedef struct List List;
typedef struct Strlist Strlist;
typedef struct Procinfo Procinfo;

// Thread group ids, used for distinguishing allocation arenas
enum {
	GRnone, GRmain, GRnet, GRprog, GRalert
};

// List of integers (and also generic list with next pointer at beginning)
struct List
{
	List*	next;
	int	val;
};

struct Strlist
{
	Strlist*	next;
	Rune*	val;
};

extern int		listlen(List* l);
extern List*	newlist(int val, List* rest);
extern Strlist*	newstrlist(Rune* val, Strlist* rest);
extern List*	revlist(List* l);
extern void	splitl(Rune* s, int n, Rune* cl, Rune** p1, int* n1, Rune** p2, int* n2);
extern void	splitr(Rune* s, int n, Rune* cl, Rune** p1, int* n1, Rune** p2, int* n2);
extern int		splitall(Rune* s, int n, Rune* cl, Rune** strarr, int* lenarr, int alen);
extern void	trimwhite(Rune* s, int n, Rune** pans, int* panslen);
extern Rune*	Strclass(Rune* s, Rune* cl);
extern Rune*	Strnclass(Rune* s, Rune* cl, int n);
extern Rune*	Strrclass(Rune* s, Rune* cl);
extern Rune*	Strnrclass(Rune* s, Rune* cl, int n);
extern int		inclass(Rune c, Rune* cl);
extern int		prefix(Rune* pre, Rune* s);
extern int		Strlen(Rune* s);
extern int		Strcmp(Rune* s1, Rune* s2);
extern int		Strncmpci(Rune* s1, int n1, Rune* s2);
extern int		Strncmp(Rune* s1, int n1, Rune* s2);
extern int		Streqn(Rune* s1, int n1, Rune* s2);
extern Rune*	Strrune(Rune* s, Rune c);
extern Rune*	Strnrune(Rune* s, Rune c, int n);
extern Rune*	Strdup(Rune* s);
extern Rune*	Strdup2(Rune* s, Rune* t);
extern Rune*	Strdup3(Rune* s, Rune* t, Rune* u);
extern Rune*	Strsubstr(Rune* s, int start, int stop);
extern Rune*	newstr(int n);
extern Rune*	Strndup(Rune* s, int n);
extern void	Strncpy(Rune* s1, Rune* s2, int n);
extern Rune*	Stradd(Rune*s1, Rune* s2, int n);
extern long	Strtol(Rune* s, Rune** eptr, int base);
extern Rune*	toStr(uchar* buf, int n, int chset);
extern Rune*	ltoStr(int n);
extern uchar*	fromStr(Rune* buf, int n, int chset);
extern int		max(int a, int b);
extern int		min(int a, int b);

extern void*	emalloc(int size);
extern void*	emallocz(int size);
extern void*	erealloc(void* p, int size);
extern void	freeshortlived(void);

extern void	meminit(int big);
extern int		validptr(void* p);
extern int		validStr(Rune* s);

extern Rune*	whitespace;
extern Rune*	notwhitespace;

// some constants used for buffer lengths
#define SMALLBUFSIZE 240
#define BIGBUFSIZE 2000
#define ATOMICIO 8192
#define STACKSIZE 32700
#define STACKSIZESMALL 8100

// URL
typedef struct ParsedUrl ParsedUrl;

enum {
	NOSCHEME,
	HTTP,
	HTTPS,
	FTP,
	FILE,
	GOPHER,
	MAILTO,
	NEWS,
	NNTP,
	TELNET,
	WAIS,
	PROSPERO ,
	UNKNOWN,
	NSCHEMES
};

// A ParsedUrl contains the whole url at the end,
// and pointers into that string for the various pieces of the url.
// together with counts for how long those pieces are.
// The individual pieces shouldn't be changed, except via the
// makeabsolute and addquery functions.
struct ParsedUrl
{
	int		scheme;			// HTTP, etc.
	Rune*	user;				// if have user:passwd@machine
	int		nuser;			// number of chars in user substring
	Rune*	passwd;
	int		npasswd;
	Rune*	host;				// machine name
	int		nhost;
	Rune*	port;				// if have :portnumber after machine
	int		nport;
	Rune*	pstart;			// Either '/' or empty
	int		npstart;
	Rune*	path;				// part after the '/', before query
	int		npath;
	Rune*	query;			// part after ?
	int		nquery;
	Rune*	frag;				// part after #
	int		nfrag;
	int		nurl;				// actual length of url array
	Rune		url[1];			// the whole thing
};

#pragma varargck	type "U"	ParsedUrl*

extern Rune*		schemes[];

extern void		urlinit(void);
extern ParsedUrl*	makeurl(Rune* s, int makeabs);
extern ParsedUrl*	copyurl(ParsedUrl* url);
extern ParsedUrl*	makeabsoluteurl(ParsedUrl* url, ParsedUrl* base);
extern ParsedUrl*	makequeryurl(ParsedUrl* url, Rune* q);
extern int			urlequal(ParsedUrl* a, ParsedUrl* b);
extern int			validurl(ParsedUrl* u);

// STRINTTAB
typedef struct StringInt StringInt;

// Element of String-Int table (used for keyword lookup)
struct StringInt
{
	Rune*	key;
	int		val;
};

extern int		lookup(StringInt* t, int n, Rune* key, int keylen, int* pans);
extern Rune*	revlookup(StringInt* t, int n, int val);

// IUTILS

typedef struct Config Config;
typedef struct ReqInfo ReqInfo;
typedef struct MaskedImage MaskedImage;
typedef struct CImage CImage;
typedef struct Netconn Netconn;
typedef struct Header Header;
typedef struct ByteSource ByteSource;
typedef struct ResourceState ResourceState;

// HTTP methods
enum {
	HGet,
	HPost
};

// Media types (must track mnames in chutils.c)
enum {
	ApplMsword,
	ApplOctets,
	ApplPdf,
	ApplPostscript,
	ApplRtf,
	ApplFramemaker,
	ApplMsexcel,
	ApplMspowerpoint,
	UnknownType,
	Audio32kadpcm,
	AudioBasic,
	ImageCgm,
	ImageG3fax,
	ImageGif,
	ImageIef,
	ImageJpeg,
	ImagePng,
	ImageTiff,
	ImageXBit,
	ImageXBit2,
	ImageXBitmulti,
	ImageXXBitmap,
	ModelVrml,
	MultiDigest,
	MultiMixed,
	TextCss,
	TextEnriched,
	TextHtml,
	TextJavascript,
	TextPlain,
	TextRichtext,
	TextSgml,
	TextTabSeparatedValues,
	TextXml,
	VideoMpeg,
	VideoQuicktime,
	NMEDIATYPES
};

// Charsets (must track chsetnames in chutils.c)
enum {
	UnknownCharset,
	US_Ascii,
	ISO_8859_1,
	UTF_8,
	Unicode,
	NCHARSETS
};

// Frame Target IDs
enum {
	FTtop,
	FTself,
	FTparent,
	FTblank
};

// Error codes.
// The HC codes can also be used as error codes
enum {
	ERRnone = 0,				// (no error)
	ERRaborted,				// User aborted the get
	ERRunsupscheme,			// Unsupported scheme
	ERRunexphscode,			// Unexpected HTTP answer code
	ERRredirloop,				// Redirect loop
	ERRstaterr,				// Can't get file status
	ERRreaderr,				// Read error
	ERRwriteerr,				// Write error
	ERReof,					// Unexpected end of file
	ERRconnecterr,				// Couldn't connect
	ERRftperr,					// FTP protocol error
	ERRftpnologin,				// FTP login failed
	ERRhttperr,				// HTTP protocol error
	ERRauthfailed,				// Authorization failed
	ERRunsupimg,				// Unsupported image type
	ERRnomem,				// Not enough memory
	ERRimgbad,				// Image encoding is bad
};

// Netconn states
enum {
	NCfree,
	NCidle,
	NCconnect,
	NCgethdr,
	NCgetdata,
	NCdone,
	NCerr,
	NNCSTATES
};

// Netget protocol values
enum {
	NGstartreq,
	NGwaitreq,
	NGstatechg,
	NGfreebs,
	NGabort,
	Punused,
	Pstart,
	Pconnected,
	Phavehdr,
	Phavedata,
	Pdone,
	Perr,
	Paborted,
	NNGVALUES
};

// Colors (RGB values in bottom bottom bytes)
// and extra Plan 9-style colors (with alpha in bottom byte)
enum {
	White = 0xFFFFFF,
	Black = 0x000000,
	Grey = 0xDDDDDD,
	DarkGrey = 0x9D9D9D,
	LightGrey = 0xEDEDED,
	DarkestGrey = 0x666666,
	Blue = 0x0000CC,
	Navy = 0x000080,
	Red = 0xFF0000,
	DarkRed = 0x9D0000,

	DGrey = 0xDDDDDDFF
};

// Header major status values (code/100)
enum {
	HSNone,
	HSInformation,
	HSOk,
	HSRedirect,
	HSError,
	HSServererr,
	NHSVALUES
};

// Individual status code values (HTTP, but use for other transports too)
enum {
	HCContinue = 100,
	HCSwitchProto = 101,
	HCOk = 200,
	HCCreated = 201,
	HCAccepted = 202,
	HCOkNonAuthoritative = 203,
	HCNoContent = 204,
	HCResetContent = 205,
	HCPartialContent = 206,
	HCMultipleChoices = 300,
	HCMovedPerm = 301,
	HCMovedTemp = 302,
	HCSeeOther = 303,
	HCNotModified = 304,
	HCUseProxy = 305,
	HCBadRequest = 400,
	HCUnauthorized = 401,
	HCPaymentRequired = 402,
	HCForbidden = 403,
	HCNotFound = 404,
	HCMethodNotAllowed = 405,
	HCNotAcceptable = 406,
	HCProxyAuthRequired = 407,
	HCRequestTimeout = 408,
	HCConflict = 409,
	HCGone = 410,
	HCLengthRequired = 411,
	HCPreconditionFailed = 412,
	HCRequestTooLarge = 413,
	HCRequestURITooLarge = 414,
	HCUnsupportedMedia = 415,
	HCRangeInvalid = 416,
	HCExpectFailed = 419,
	HCServerError = 500,
	HCNotImplemented = 501,
	HCBadGateway = 502,
	HCServiceUnavailable = 503,
	HCGatewayTimeout = 504,
	HCVersionUnsupported = 505,
	HCRedirectionFailed = 506,
	NHCCODES
};

// Max number of redirections tolerated
#define Maxredir 10

// Image level config options
enum {
		ImgNone,
		ImgNoAnim,
		ImgProgressive,
		ImgFull
};

// User Configuration Information (Options)
// Debug option letters:
//	'd' -> Basic operation info (navigation, etc.)
//	'e' -> Events (timing of progress through get/layout/image conversion)
//	'h' -> Build layout items from lex tokens
//	'i' -> Image conversion
//	'l' -> Layout
//	'n' -> transport (Network access)
//	'o' -> always use old http (http/1.0)
//	'p' -> synch Protocol between ByteSource/Netconn
//	'r' -> Resource usage
//	's' -> Scripts
//	't' -> Table layout
//	'u' -> use Uninstalled dis modules
//	'w' -> Warn about recoverable problems in retrieved pages
//	'x -> lex Html tokens

struct Config
{
	Rune*		userdir;		// where to find bookmarks, cache, etc.
	ParsedUrl*	starturl;		// never nil (could be last of command args)
	ParsedUrl*	homeurl;		// never nil
	ParsedUrl*	httpproxy;	// nil, if no proxy
	int			defaultwidth;	// of entire browser
	int			defaultheight;	// of entire browser
	int			x;			// initial x position for browser
	int			y;			// initial y position for browser
	int			nocache;		// true if shouldn't retrieve from or store to
	int			maxstale;		// allow cache hit even if exceed expiration by maxstale
	int			imagelvl;		// ImgNone, etc.
	int			imagecachenum;	// imcache.nlimit
	int			imagecachemem;	// imcache.memlimit
	int			docookies;	// allow cookie storage/sending?
	int			doscripts;		// allow scripts to execute?
	int			saveauthinfo;	// save auth info in file?
	int			showprogress;	// show progress area?
	int			usecci;		// allow external (CCI) control
	int			httpminor;	// use HTTP 1.httpminor
	Rune*		agentname;	// what to send in HTTP header
	int			nthreads;		// number of simultaneous gets allowed
	Rune*		dbgfile;		// file to write debug messages to
	uchar		dbg[128];		// ascii letters for different debugging kinds
};

// Information for fulfilling HTTP request
struct ReqInfo
{
	ParsedUrl*	url;		// should be absolute
	int			method;	// HGet or HPost
	uchar*		body;	// used for HPost
	int			bodylen;	// length of body array
	Rune*		auth;		// optional auth info
	int			target;	// target frame name
};

// An image, a possible mask, possible animation frame info
struct MaskedImage
{
	Image*	im;		// the image
	Image*	mask;	// if non-nil, a mask for the image
	int		delay;	// if animated, delay in millisec before next frame
	int		more;	// true if more frames follow
	int		bgcolor;	// if not -1, restore to this (RGB) color before next frame
	Point		origin;	// origin of im relative to first frame of an animation
};

// Cached Image info.
// If this is an animated image then len mims > 1
struct CImage
{
	CImage*			next;		// next (newer) image in cache
	ParsedUrl*		src;		// source of image
	ParsedUrl*		actual;	// what came back as actual source of image
	int				imhash;	// hash of src, for fast comparison
	int				width;
	int				height;
	int				refcnt;	// reference count of users of this image
	MaskedImage**	mims;	// frames
	int				mimslen;	// number of elems in mims
};

// An connection to some host
struct Netconn
{
	int			id;			// for debugging
	int			rnpid;		// runnetconn pid, when a proc
	int			rntid;		// runnetconn tid, when a thread
	Rune*		host;			// host name
	int			port;			// port number
	int			scheme;		// Url->HTTP, etc.
	int			cfd;			// Control fd
	int			dfd;			// Data fd
	int			state;		// NCfree, etc.
	ByteSource**	queue;		// bytesources processed by this netconn
							// following are indexes into queue
	int			qalloclen;		// allocated size (in slots) of queue
	int			qlen;			// queue[0:qlen] is queue of requests
	int			gocur;		// go thread currently processing
	int			ngcur;		// ng threads currently processing
	int			reqsent;		// next to send request for
	int			pipeline;		// are requests being pipelined?
	int			connected;	// are we connected to host?
	int			tstate;		// for use by transport
	int			tn1;			// for use by transport
	int			tn2;			// for use by transport
	uchar*		tbuf;			// for use by transport
	int			tbuflen;		// length of tbuf
};

// Info from an HTTP response header
struct Header
{
	int			code;	// HC... (detailed response code)
	ParsedUrl*	actual;	// actual request url (may be result of redir)
	ParsedUrl*	base;	// Content-Base or request url
	ParsedUrl*	location;	// Content-Location
	int			length;	// -1 if unknown
	int			mtype;	// TextHtml, etc.
	int			chset;	// for text types: ISO_8859, etc.
	Rune*		msg;		// possible message explaining status
	Rune*		refresh;	// used for server push
	Rune*		chal;		// used if code is HSneedauth
	Rune*		warn;	// should show this to user
};

// A source of raw bytes (with HTTP info)
struct ByteSource
{
	int		id;		// for debugging
	ReqInfo*	req;		// how/where to get bytes
	Header*	hdr;		// filled in from headers
	uchar*	data;		// all the data, maybe partially filled
	int		dalloclen;	// length of allocated data member
	int		edata;	// data[0:edata] is valid
	int		err;		// there was an error
	Netconn*	net;		// servicing fd, etc.
	int		refgo;	// go proc is still using
	int		refnc;	// netconn proc is still using

	// consumer changes only these fields:
	int		lim;		// consumer has seen data[0:lim]
	int		seenhdr;	// consumer has seen hdr
};

// For debugging time and space usage
struct ResourceState
{
	int	ms;			// milliseconds
	int	mem;		// bytes of memory in use
	int	memavail;	// bytes of memory still available
};

extern Rune*			hmeth[];			// String rep of HGet, etc.
extern Rune*			mnames[];		// String rep of ApplMsword, etc.		
extern Rune*			chsetnames[];		// String rep of UnknownCharset, etc.
extern Rune*			ncstatenames[];	// String rep of NCfree, etc.
extern Rune*			hsnames[];		// String rep of HSNone, etc.
extern Config			config;			// configuration options
extern ResourceState	startres;			// starting resource state
extern int				dbg;				// config.dbg['d']
extern int				warn;			// dbg || config.dbg['w']
extern int				dbgev;			// config.dbg['e']

extern void			iutilsinit(int argc, char** argv);
extern ByteSource*		startreq(ReqInfo* req);
extern ByteSource*		waitreq(void);
extern ByteSource*		newstringbytesource(Rune* s);
extern void			freebs(ByteSource* bs);
extern void			abortgo(void);
extern void			netget(void* arg);
extern ReqInfo*		newreqinfo(ParsedUrl* url, int method, uchar* body,
						int bodylen, Rune* auth, int target);
extern MaskedImage*	newmaskedimage(Image* im);
extern CImage*		newcimage(ParsedUrl* src, int width, int height);
extern int				cimagematch(CImage* a, CImage* b);
extern int				cimagebytes(CImage* ci);
extern void			imcacheresetlimits(void);
extern CImage*		imcachelook(CImage* ci);
extern void			imcacheadd(CImage* ci);
extern void			imcachedeletelru(void);
extern void			imcacheclear(void);
extern int				imcacheneed(int nbytes);
extern Header*			newheader(void);
extern void			setmediatype(Header* h, Rune* name, uchar* first, int firstlen);
extern void			printheader(Header* h);
extern ResourceState	curresstate(void);
extern ResourceState	resstatesince(ResourceState rnew, ResourceState rold);
extern void			resstateprint(ResourceState r, char* msg);
extern int				getline(int fd, uchar* buf, int bufsize, int* pbstart, int* pbend,
						uchar** pans, int* panslen);
extern int				Strlookup(Rune** a, int n, Rune* s, int slen);
extern Rune*			hcphrase(int code);
extern Rune*			errphrase(int code);
extern int				hdraction(ByteSource* bs, int ismain, int nredirs,
						int* perror, Rune** pchallenge, ParsedUrl** predir);
extern StringInt*		makestrinttab(Rune** a, int n);
extern void			logtime(char* msg, int data);
extern int				color(Rune* s, int dflt);
extern int				targetid(Rune* s);
extern Rune*			targetname(int targid);
extern void			sendprogress(int bsid, int state, int pcnt, Rune* s);

// TRANSPORT
typedef struct Transport Transport;

struct Transport
{
	void	(*init)(void);
	void	(*connect)(Netconn* nc, ByteSource* bs);
	void	(*writereq)(Netconn* nc, ByteSource* bs);
	void	(*gethdr)(Netconn* nc, ByteSource* bs);
	void	(*getdata)(Netconn* nc, ByteSource* bs);
	int	(*defaultport)(int scheme);
};

extern void	httpinit(void);
extern void	httpconnect(Netconn* nc, ByteSource* bs);
extern void	httpwritereq(Netconn* nc, ByteSource* bs);
extern void	httpgethdr(Netconn* nc, ByteSource* bs);
extern void	httpgetdata(Netconn* nc, ByteSource* bs);
extern int		httpdefaultport(int scheme);
extern void	ftpinit(void);
extern void	ftpconnect(Netconn* nc, ByteSource* bs);
extern void	ftpwritereq(Netconn* nc, ByteSource* bs);
extern void	ftpgethdr(Netconn* nc, ByteSource* bs);
extern void	ftpgetdata(Netconn* nc, ByteSource* bs);
extern int		ftpdefaultport(int scheme);
extern void	fileinit(void);
extern void	fileconnect(Netconn* nc, ByteSource* bs);
extern void	filewritereq(Netconn* nc, ByteSource* bs);
extern void	filegethdr(Netconn* nc, ByteSource* bs);
extern void	filegetdata(Netconn* nc, ByteSource* bs);
extern int		filedefaultport(int scheme);
extern void	transportinit(void);


#define TRANSMAX (FILE+1)

extern Transport *transports[TRANSMAX];


// LEX
typedef struct Token Token;
typedef struct Attr Attr;
typedef struct TokenSource TokenSource;

// HTML 4.0 tags (plus blink, nobr)
// sorted in lexical order; used as array indices
enum {
	Notfound,
	Comment,
	Ta, Tabbr, Tacronym, Taddress, Tapplet, Tarea,
	Tb, Tbase, Tbasefont, Tbdo, Tbig, Tblink,
	Tblockquote, Tbody, Tbq, Tbr, Tbutton,
	Tcaption, Tcenter, Tcite, Tcode, Tcol, Tcolgroup,
	Tdd, Tdel, Tdfn, Tdir, Tdiv, Tdl, Tdt,
	Tem,
	Tfieldset, Tfont, Tform, Tframe, Tframeset,
	Th1, Th2, Th3, Th4, Th5, Th6,
	Thead, Thr, Thtml,
	Ti, Tiframe, Timg, Tinput, Tins, Tisindex,
	Tkbd,
	Tlabel, Tlegend, Tli, Tlink,
	Tmap, Tmenu, Tmeta,
	Tnobr, Tnoframes, Tnoscript,
	Tobject, Tol, Toptgroup, Toption,
	Tp, Tparam, Tpre,
	Tq,
	Ts, Tsamp, Tscript, Tselect, Tsmall,
	Tspan, Tstrike, Tstrong, Tstyle, Tsub, Tsup,
	Ttable, Ttbody, Ttd, Ttextarea, Ttfoot,
	Tth, Tthead, Ttitle, Ttr, Ttt,
	Tu, Tul,
	Tvar,
	Numtags,
	RBRA = Numtags,
	Data = Numtags+RBRA
};

//HTML 4.0 tag attributes
// Keep sorted in lexical order
enum {
	Aabbr, Aaccept_charset, Aaccess_key, Aaction,
	Aalign, Aalink, Aalt, Aarchive, Aaxis,
	Abackground, Abgcolor, Aborder,
	Acellpadding, Acellspacing, Achar, Acharoff,
	Acharset, Achecked, Acite, Aclass, Aclassid,
	Aclear, Acode, Acodebase, Acodetype, Acolor,
	Acols, Acolspan, Acompact, Acontent, Acoords,
	Adata, Adatetime, Adeclare, Adefer, Adir, Adisabled,
	Aenctype,
	Aface, Afor, Aframe, Aframeborder,
	Aheaders, Aheight, Ahref, Ahreflang, Ahspace, Ahttp_equiv,
	Aid, Aismap,
	Alabel, Alang, Alink, Alongdesc,
	Amarginheight, Amarginwidth, Amaxlength,
	Amedia, Amethod, Amultiple,
	Aname, Anohref, Anoresize, Anoshade, Anowrap,
	Aobject, Aonblur, Aonchange, Aonclick, Aondblclick,
	Aonfocus, Aonkeypress, Aonkeyup, Aonload,
	Aonmousedown, Aonmousemove, Aonmouseout,
	Aonmouseover, Aonmouseup, Aonreset, Aonselect,
	Aonsubmit, Aonunload,
	Aprofile, Aprompt,
	Areadonly, Arel, Arev, Arows, Arowspan, Arules,
	Ascheme, Ascope, Ascrolling, Aselected, Ashape,
	Asize, Aspan, Asrc, Astandby, Astart, Astyle, Asummary,
	Atabindex, Atarget, Atext, Atitle, Atype,
	Ausemap,
	Avalign, Avalue, Avaluetype, Aversion, Avlink, Avspace,
	Awidth,
	Numattrs
};

struct Token
{
	int		tag;		// Ta, etc
	Rune*	text;		// text in Data, attribute text in tag
	Attr*		attr;		// list of Attrs
	int		starti;	// index into source buffer of token start
};


struct Attr
{
	Attr*		next;		// in list of attrs for a token
	int		attid;		// Aabbr, etc.
	Rune*	value;
};


struct TokenSource
{
	int			i;		// index of next byte to use
	ByteSource*	b;
	int			chset;	// one of CU->US_Ascii, etc.
	int			mtype;	// CU->TextHtml or CU->TextPlain
	int			ihigh;	// high water mark of i
};

extern Rune*	tagnames[];
extern Rune*	attrnames[];

extern void			lexinit(void);
extern int				tokaval(Token* t, int attid, Rune** pans, int xfer);
extern TokenSource*	newtokensource(ByteSource* b, int chset, int mtype);
extern Attr*			newattr(int attid, Rune* value, Attr* link);
extern Token*			gettoks(TokenSource* ts, int* plen);


#pragma varargck	type "T"	Token*


// BUILD

typedef struct Item Item;
typedef struct Itext Itext;
typedef struct Irule Irule;
typedef struct Iimage Iimage;
typedef struct Iformfield Iformfield;
typedef struct Itable Itable;
typedef struct Ifloat Ifloat;
typedef struct Ispacer Ispacer;
typedef struct Itemlist Itemlist;
typedef struct Genattr Genattr;
typedef struct Formfield Formfield;
typedef struct Option Option;
typedef struct Form Form;
typedef struct Table Table;
typedef struct Tablecol Tablecol;
typedef struct Tablerow Tablerow;
typedef struct Tablecell Tablecell;
typedef struct Align Align;
typedef struct Dimen Dimen;
typedef struct Anchor Anchor;
typedef struct DestAnchor DestAnchor;
typedef struct Map Map;
typedef struct Area Area;
typedef struct Background Background;
typedef struct Kidinfo Kidinfo;
typedef struct Docinfo Docinfo;
typedef struct Stack Stack;
typedef struct Pstate Pstate;
typedef struct ItemSource ItemSource;
typedef struct Lay Lay;	// defined in Layout module

// Alignment types
enum {
	ALnone = 0, ALleft, ALcenter, ALright, ALjustify,
	ALchar, ALtop, ALmiddle, ALbottom, ALbaseline
};

struct Align
{
	uchar	halign;	// one of ALnone, ALleft, etc.
	uchar	valign;	// one of ALnone, ALtop, etc.
};

// A Dimen holds a dimension specification, especially for those
// cases when a number can be followed by a % or a * to indicate
// percentage of total or relative weight.
// Dnone means no dimension was specified

// To fit in a word, use top bits to identify kind, rest for value
enum {
	Dnone =		0,
	Dpixels =		(1<<29),
	Dpercent =	(2<<29),
	Drelative =	(3<<29),
	Dkindmask =	(3<<29),
	Dspecmask =	(~Dkindmask)
};

struct Dimen
{
	int	kindspec;		// kind | spec
};

// Background is either an image or a color.
// If both are set, the image has precedence.
struct Background
{
	CImage*	image;
	int		color;
};


// There are about a half dozen Item variants.
// The all look like this at the start, and then the tag
// field dictates what extra fields there are.
struct Item
{
	Item*	next;		// successor in list of items
	int		width;	// width in pixels (0 for floating items)
	int		height;	// height in pixels
	int		ascent;	// ascent (from top to baseline) in pixels
	int		anchorid;	// if nonzero, which anchor we're in
	int		state;	// flags and values (see below)
	Genattr*	genattr;	// generic attributes and events
	int		tag;		// variant discriminator: Itexttag, etc.
};

// Item variant tags
enum {
	Itexttag,
	Iruletag,
	Iimagetag,
	Iformfieldtag,
	Itabletag,
	Ifloattag,
	Ispacertag
};

struct Itext
{
	Item*	next;
	int		width;
	int		height;
	int		ascent;
	int		anchorid;
	int		state;
	Genattr*	genattr;
	int		tag;			// Itexttag
	Rune*	s;			// the characters
	int		fnt;			// style*NumSize+size (see font stuff, below)
	int		fg;			// Pixel (color) for text
	uchar	voff;			// Voffbias+vertical offset from baseline, in pixels (+ve == down)
	uchar	ul;			// ULnone, ULunder, or ULmid
};

struct Irule
{
	Item*	next;
	int		width;
	int		height;
	int		ascent;
	int		anchorid;
	int		state;
	Genattr*	genattr;
	int		tag;			// Iruletag
	uchar	align;		// alignment spec
	uchar	noshade;		// if true, don't shade
	int		size;			// size attr (rule height)
	Dimen	wspec;		// width spec
};


struct Iimage
{
	Item*	next;
	int		width;
	int		height;
	int		ascent;
	int		anchorid;
	int		state;
	Genattr*	genattr;
	int		tag;			// Iimagetag
	CImage*	ci;			// cached image (has src, actual width, height)
	int		imwidth;		// spec width (actual, if no spec)
	int		imheight;		// spec height (actual, if no spec)
	Rune*	altrep;		// alternate representation, in absence of image
	Map*	map;			// if non-nil, client side map
	int		ctlid;			// if animated
	uchar	align;		// vertical alignment
	uchar	hspace;		// in pixels; buffer space on each side
	uchar	vspace;		// in pixels; buffer space on top and bottom
	uchar	border;		// in pixels: border width to draw around image
	Iimage*	nextimage;	// next in list of document's images
};


struct Iformfield
{
	Item*		next;
	int			width;
	int			height;
	int			ascent;
	int			anchorid;
	int			state;
	Genattr*		genattr;
	int			tag;		// Iformtag
	Formfield		*formfield;
};


struct Itable
{
	Item*	next;
	int		width;
	int		height;
	int		ascent;
	int		anchorid;
	int		state;
	Genattr*	genattr;
	int		tag;			// Itabletag
	Table*	table;
};


struct Ifloat
{
	Item*	next;
	int		width;
	int		height;
	int		ascent;
	int		anchorid;
	int		state;
	Genattr*	genattr;
	int		tag;
	Item*	item;			// Ifloattag
	int		x;			// x coord of top (from right, if ALright)
	int		y;			// y coord of top
	uchar	side;			// margin it floats to: ALleft or ALright
	uchar	infloats;		// true if this has been added to a lay.floats
	Ifloat*	nextfloat;		// in list of floats
};


struct Ispacer
{
	Item*	next;
	int		width;
	int		height;
	int		ascent;
	int		anchorid;
	int		state;
	Genattr*	genattr;
	int		tag;			// Ispacertag
	int		spkind;		// ISPnull, etc.
};

// Item state flags and value fields
enum {
	IFbrk =			0x80000000,	// forced break before this item
	IFbrksp =			0x40000000,	// add 1 line space to break (IFbrk set too)
	IFnobrk =			0x20000000,	// break not allowed before this item
	IFcleft =			0x10000000,	// clear left floats (IFbrk set too)
	IFcright =			0x08000000,	// clear right floats (IFbrk set too)
	IFwrap =			0x04000000,	// in a wrapping (non-pre) line
	IFhang =			0x02000000,	// in a hanging (into left indent) item
	IFrjust =			0x01000000,	// right justify current line
	IFcjust =			0x00800000,	// center justify current line
	IFsmap =			0x00400000,	// image is server-side map
	IFindentshift =		8,
	IFindentmask =		(255<<IFindentshift),	// current indent, in tab stops
	IFhangmask =		255			// current hang into left indent, in 1/10th tabstops
};

// Bias added to Itext's voff field
enum { Voffbias = 128 };

// Spacer kinds
enum {
	ISPnull,			// 0 height and width
	ISPvline,			// height and ascent of current font
	ISPhspace,		// width of space in current font
	ISPgeneral		// other purposes (e.g., between markers and list)
};

struct Itemlist
{
	Itemlist*	next;
	Item*	val;
};

// Generic attributes and events (not many elements will have any of these set)
struct Genattr
{
	Rune*	id;
	Rune*	class;
	Rune*	style;
	Rune*	title;
	Attr*		events;
};

// Form field types
enum {
	Ftext,
	Fpassword,
	Fcheckbox,
	Fradio,
	Fsubmit,
	Fhidden,
	Fimage,
	Freset,
	Ffile,
	Fbutton,
	Fselect,
	Ftextarea
};


// Information about a field in a form
struct Formfield
{
	Formfield*	next;		// in list of fields for a form
	int			ftype;	// Ftext, Fpassword, etc.
	int			fieldid;	// serial no. of field within its form
	Form*		form;	// containing form
	Rune*		name;	// name attr
	Rune*		value;	// value attr
	int			size;		// size attr
	int			maxlength;	// maxlength attr
	int			rows;	// rows attr
	int			cols;		// cols attr
	uchar		flags;	// FFchecked, etc.
	Option*		options;	// for Fselect fields
	Item*		image;	// image item, for Fimage fields
	int			ctlid;		// identifies control for this field in layout
	Attr*			events;	// same as genattr->events of containing item
};

enum {
	FFchecked =	(1<<7),
	FFmultiple =	(1<<6)
};

// Option holds info about an option in a "select" form field
struct Option
{
	Option*	next;			// next in list of options for a field
	int		selected;		// true if selected initially
	Rune*	value;		// value attr
	Rune*	display;		// display string
};

// Form holds info about a form
struct Form
{
	Form*		next;		// in list of forms for document
	int			formid;	// serial no. of form within its doc
	Rune*		name;	// name or id attr (netscape uses name, HTML 4.0 uses id)
	ParsedUrl*	action;	// action attr
	int			target;	// target attr as targetid
	int			method;	// HGet or HPost
	int			nfields;	// number of fields
	Formfield*	fields;	// field's forms, in input order
};

// Flags used in various table structures
enum {
	TFparsing =	(1<<7),
	TFnowrap =	(1<<6),
	TFisth =		(1<<5)
};


// Information about a table
struct Table
{
	Table*		next;			// next in list of document's tables
	int			tableid;		// serial no. of table within its doc
	Tablerow*	rows;		// array of row specs (list during parsing)
	int			nrow;		// total number of rows
	Tablecol*		cols;			// array of column specs
	int			ncol;			// total number of columns
	Tablecell*		cells;			// list of unique cells
	int			ncell;		// total number of cells
	Tablecell***	grid;			// 2-D array of cells
	Align		align;		// alignment spec for whole table
	Dimen		width;		// width spec for whole table
	int			border;		// border attr
	int			cellspacing;	// cellspacing attr
	int			cellpadding;	// cellpadding attr
	Background	background;	// table background
	Item*		caption;		// linked list of Items, giving caption
	uchar		caption_place;	// ALtop or ALbottom
	Lay*			caption_lay;	// layout of caption
	int			totw;			// total width
	int			toth;			// total height
	int			caph;		// caption height
	int			availw;		// used for previous 3 sizes
	Token*		tabletok;		// token that started the table
	uchar		flags;		// Lchanged, perhaps
};


struct Tablecol
{
	int		width;
	Align	align;
	Point		pos;
};


struct Tablerow
{
	Tablerow*	next;			// Next in list of rows, during parsing
	Tablecell*		cells;			// Cells in row, linked through nextinrow
	int			height;
	int			ascent;
	Align		align;
	Background	background;
	Point			pos;
	uchar		flags;		// 0 or TFparsing
};


// A Tablecell is one cell of a table.
// It may span multiple rows and multiple columns.
// Cells are linked on two lists: the list for all the cells of
// a document (the next pointers), and the list of all the
// cells that start in a given row (the nextinrow pointers)
struct Tablecell
{
	Tablecell*		next;			// next in list of table's cells
	Tablecell*		nextinrow;	// next in list of row's cells
	int			cellid;		// serial no. of cell within table
	Item*		content;		// contents before layout
	Lay*			lay;			// layout of cell
	int			rowspan;		// number of rows spanned by this cell
	int			colspan;		// number of cols spanned by this cell
	Align		align;		// alignment spec
	uchar		flags;		// TFparsing, TFnowrap, TFisth
	Dimen		wspec;		// suggested width
	int			hspec;		// suggested height
	Background	background;	// cell background
	int			minw;		// minimum possible width
	int			maxw;		// maximum width
	int			ascent;		// cell's ascent
	int			row;			// row of upper left corner
	int			col;			// col of upper left corner
	Point			pos;			// nw corner of cell contents, in cell
};

// Anchor is for info about hyperlinks that go somewhere
struct Anchor
{
	Anchor*		next;		// next in list of document's anchors
	int			index;	// serial no. of anchor within its doc
	Rune*		name;	// name attr
	ParsedUrl*	href;		// href attr
	int			target;	// target attr as targetid
};


// DestAnchor is for info about hyperlinks that are destinations
struct DestAnchor
{
	DestAnchor*	next;		// next in list of document's destanchors
	int			index;	// serial no. of anchor within its doc
	Rune*		name;	// name attr
	Item*		item;		// the destination
};


// Maps (client side)
struct Map
{
	Map*	next;			// next in list of document's maps
	Rune*	name;		// map name
	Area*	areas;		// list of map areas
};


struct Area
{
	Area*		next;		// next in list of a map's areas
	int			shape;	// SHrect, etc.
	ParsedUrl*	href;		// associated hypertext link
	int			target;	// associated target frame
	Dimen*		coords;	// array of coords for shape
	int			ncoords;	// size of coords array
};

// Area shapes
enum {
	SHrect, SHcircle, SHpoly
};

// Fonts are represented by integers: style*NumSize + size

// Font styles
enum {
	FntR,			// roman
	FntI,			// italic
	FntB,			// bold
	FntT,			// typewriter
	NumStyle
};

// Font sizes
enum {
	Tiny,
	Small,
	Normal,
	Large,
	Verylarge,
	NumSize
};

enum {
	NumFnt = (NumStyle*NumSize),
	DefFnt = (FntR*NumSize+Normal)
};

// Lines are needed through some text items, for underlining or strikethrough
enum {
	ULnone, ULunder, ULmid
};

// List number types
enum {
	LTdisc, LTsquare, LTcircle, LT1, LTa, LTA, LTi, LTI
};

// Kidinfo flags
enum {
	FRnoresize =	(1<<0),
	FRnoscroll =	(1<<1),
	FRhscroll = 	(1<<2),
	FRvscroll =	(1<<3),
	FRhscrollauto = (1<<4),
	FRvscrollauto =	(1<<5)
};

// Information about child frame or frameset
struct Kidinfo
{
	Kidinfo*		next;		// in list of kidinfos for a frameset
	int			isframeset;

	// fields for "frame"
	ParsedUrl*	src;		// only nil if a "dummy" frame or this is frameset
	Rune*		name;	// always non-empty if this isn't frameset
	int			marginw;
	int			marginh;
	int			framebd;
	int			flags;

	// fields for "frameset"
	Dimen*		rows;	// array of row dimensions
	int			nrows;	// length of rows
	Dimen*		cols;		// array of col dimensions
	int			ncols;	// length of cols
	Kidinfo*		kidinfos;
	Kidinfo*		nextframeset;	// parsing stack
};


// Document info (global information about HTML page)
struct Docinfo
{
	// stuff from HTTP headers, doc head, and body tag
	ParsedUrl*	src;				// original source of doc
	ParsedUrl*	base;			// base URL of doc
	Rune*		doctitle;			// from <title> element
	Background	background;		// background specification
	Iimage*		backgrounditem;	// Image Item for doc background image, or nil
	int			text;				// doc foreground (text) color
	int			link;				// unvisited hyperlink color
	int			vlink;			// visited hyperlink color
	int			alink;			// highlighting hyperlink color
	int			target;			// target frame default
	int			chset;			// ISO_8859, etc.
	int			scripttype;		// CU->TextJavascript, etc.
	int			hasscripts;		// true if scripts used
	Rune*		refresh;			// content of <http-equiv=Refresh ...>
	Kidinfo*		kidinfo;			// if a frameset
	int			frameid;			// id of document frame

	// info needed to respond to user actions
	Anchor*		anchors;			// list of href anchors
	DestAnchor*	dests;			// list of destination anchors
	Form*		forms;			// list of forms
	Table*		tables;			// list of tables
	Map*		maps;			// list of maps
	Iimage*		images;			// list of image items (through nextimage links)
};

// Parsing stuff

// A stack for holding integer values
enum {
	Nestmax = 20	// max nesting level of lists, font styles, etc.
};

struct Stack {
	int		n;				// next available slot (top of stack is stack[n-1])
	int		slots[Nestmax];	// stack entries
};

// Parsing state
struct Pstate
{
	Pstate*	next;			// in stack of Pstates
	int		skipping;		// true when we shouldn't add items
	int		skipwhite;		// true when we should strip leading space
	int		curfont;		// font index for current font
	int		curfg;		// current foreground color
	Background	curbg;	// current background
	int		curvoff;		// current baseline offset
	uchar	curul;		// current underline/strike state
	uchar	curjust;		// current justify state
	int		curanchor;	// current (href) anchor id (if in one), or 0
	int		curstate;		// current value of item state
	int		literal;		// current literal state
	int		inpar;		// true when in a paragraph-like construct
	int		adjsize;		// current font size adjustment
	Item*	items;		// dummy head of item list we're building
	Item*	lastit;		// tail of item list we're building
	Item*	prelastit;		// item before lastit
	Stack	fntstylestk;	// style stack
	Stack	fntsizestk;		// size stack
	Stack	fgstk;		// text color stack
	Stack	ulstk;		// underline stack
	Stack	voffstk;		// vertical offset stack
	Stack	listtypestk;	// list type stack
	Stack	listcntstk;		// list counter stack
	Stack	juststk;		// justification stack
	Stack	hangstk;		// hanging stack
};


struct ItemSource
{
	TokenSource*	ts;
	int			mtype;
	Docinfo*		doc;
	Pstate*		psstk;
	int			nforms;
	int			ntables;
	int			nanchors;
	int			nframes;
	Form*		curform;
	Map*		curmap;
	Table*		tabstk;
	Kidinfo*		kidstk;
};

extern void		buildinit(void);
extern ItemSource*	newitemsource(ByteSource* bs, Docinfo* di, int mtype);
extern Item*		getitems(ItemSource* is);
extern Background	makebackground(CImage* ci, int color);
extern Item*		newitext(Rune* s, int fnt, int fg, int voff, int ul);
extern Item*		newirule(int align, int size, int noshade, Dimen wspec);
extern Item*		newiimage(ParsedUrl* src, Rune* altrep, int align, int width, int height,
					int hspace, int vspace, int border, int ismap, Map* map);
extern Item*		newiformfield(Formfield* ff);
extern Item*		newitable(Table* t);
extern Item*		newifloat(Item* it, int side);
extern Item*		newispacer(int spkind);
extern Itemlist*		newitemlist(Item* val, Itemlist* rest);
extern void		printitems(Item* items, char* msg);
extern Genattr*		newgenattr(Rune* id, Rune* class, Rune* style, Rune* title, Attr* events);
extern Formfield*	newformfield(int ftype, int fieldid, Form* form, Rune* name,
					Rune* value, int size, int maxlength, Formfield* link);
extern Option*		newoption(int selected, Rune* value, Rune* display, Option* link);
extern Form*		newform(int formid, Rune* name, ParsedUrl* action,
					int target, int method, Form* link);
extern Table*		newtable(int tableid, Align align, Dimen width, int border,
					int cellspacing, int cellpadding, Background bg, Token* tok, Table* link);
extern Tablerow*	newtablerow(Align align, Background bg, int flags, Tablerow* link);
extern Tablecell*	newtablecell(int cellid, int rowspan, int colspan, Align align, Dimen wspec,
					int hspec, Background bg, int flags, Tablecell* link);
extern Anchor*		newanchor(int index, Rune* name, ParsedUrl* href, int target, Anchor* link);
extern DestAnchor*	newdestanchor(int index, Rune* name, Item* item, DestAnchor* link);
extern Dimen		makedimen(int kind, int spec);
extern int			dimenkind(Dimen d);
extern int			dimenspec(Dimen d);
extern Area*		newarea(int shape, ParsedUrl* href, int target, Area* link);
extern Kidinfo*		newkidinfo(int isframeset, Kidinfo* link);
extern Docinfo*	newdocinfo(void);
extern void		resetdocinfo(Docinfo* d);
extern int			validitem(Item* i);
extern int			validitems(Item* i);
extern int			validformfield(Formfield* f);
extern int			validtable(Table* t);
extern int			validtablerow(Tablerow* r);
extern int			validtablecol(Tablecol* c);
extern int			validtablecell(Tablecell* c);

#pragma varargck	type "I"	Item*

// LAYOUT

typedef struct Frame Frame;
typedef struct Framelist Framelist;
typedef struct Line Line;
typedef struct Loc Loc;
typedef struct Locelem Locelem;
typedef struct Control Control;
typedef struct Cbutton Cbutton;
typedef struct Centry Centry;
typedef struct Ccheckbox Ccheckbox;
typedef struct Cselect Cselect;
typedef struct Cscrollbar Cscrollbar;
typedef struct Canimimage Canimimage;
typedef struct Cprogbox Cprogbox;
typedef struct Clabel Clabel;

// Border relief size and types
enum {
	ReliefSunk, ReliefRaised,
	ReliefBd = 2
};

struct Frame
{
	int			id;			// unique id
	Docinfo*		doc;			// various global attributes from HTML and headers
	ParsedUrl*	src;			// original source of page
	Rune*		name;		// current name (assigned by parent frame, or by default)
	int			marginw;		// margin on sides
	int			marginh;		// margin on top and bottom
	int			framebd;		// frame border desired
	int			flags;		// FRnoresize, etc.
	Lay*			layout;		// representation of layout
	Control**		controls;		// array of controls
	int			controlslen;	// number of control slots allocated
	int			controlid;		// next control id to use
	Image*		cim;			// image where we draw contents
	Rectangle		r;			// part of cimage.r for this frame (including scrollbars)
	Rectangle		cr;			//part of r for contents (excluding scrollbars, including margins)
	Rectangle		totalr;		// total rectangle for page -- (0,0) is top left
	Rectangle		viewr;		// view: subrect of pager currently on screen
	Control*		vscr;			// vertical scrollbar
	Control*		hscr;			// horizontal scrollbar
	Frame*		parent;		// if this frame is in a frameset
	Framelist*		kids;			// if this frame is a frameset
};

struct Framelist {
	Framelist*	next;
	Frame*	val;
};

// Line flags
enum {
	Ldrawn  =		(1<<0),
	Lmoved =		(1<<1),
	Lchanged	=	(1<<2)
};

// Layout engine organizes Items into Lines
struct Line
{
	Line*	next;			// next line
	Line*	prev;			// previous line
	Item*	items;		// Items for the line
	Point		pos;			// position of line in frame cim coord system
	int		width;		// in pixels
	int		height;		// in pixels
	int		ascent;		// in pixels
	uchar	flags;		// Ldrawn, etc.
};


// A place where an item, or a where mouse or keyboard focus could be.
struct Loc
{
	Locelem*	le;		// array of Locelems, from outermost inward
	int		lelen;	// number of slots allocated for le
	int		n;		// number of slots in use
	Point		pos;		// offset in final item
};


struct Locelem
{
	int		kind;		// LEframe, etc.
	Point		pos;		// position in screen coords of this element
	Frame*	frame;	// root, or kid of previous (a frame)
	Line*	line;		// a line in lay of previous
	Item*	item;		// an item in previous (a line or item)
	Tablecell*	tcell;		// a cell in previous (a table item)
	Control*	control;	// a control in previous item, or scrollbar in previous frame
};

enum {
	LEframe, LEline, LEitem, LEtablecell, LEcontrol,
};

// There are a number of different Control structure variants
// They all start off like this.
struct Control
{
	Frame*		f;		// frame containing the control
	Formfield*	ff;		// formfield, if any, that control is for
	Rectangle		r;		// coords in f.cim coord system
	int			flags;	// CFactive, etc.
	int			tag;		// Cbuttontag, etc.: says which variant
};


struct Cbutton
{
	Frame*		f;
	Formfield*	ff;
	Rectangle		r;
	int			flags;
	int			tag;		// Cbuttontag
	Image*		pic;		// picture on button (if no label)
	Image*		picmask;	// mask for pic
	Image*		dpic;		// disabled ("greyed out") pic
	Image*		dpicmask;	// mask for dpic
	Rune*		label;	// label on button (if no pic), or else flyover hint
	int			dorelief;	// draw background & relief?
};


struct Centry
{
	Frame*		f;
	Formfield*	ff;
	Rectangle		r;
	int			flags;
	int			tag;		// Centrytag
	Rune*		s;		// current contents
	int			curs;		// index of character in s that cursor is before
	int			left;		// index of character in s that is at left of window
	int			linewrap;	// true if supposed to line-wrap
};


struct Ccheckbox
{
	Frame*		f;
	Formfield*	ff;
	Rectangle		r;
	int			flags;
	int			tag;		// Ccheckboxtag
	int			isradio;	// true if for radio button
};


struct Cselect
{
	Frame*		f;
	Formfield*	ff;
	Rectangle		r;
	int			flags;
	int			tag;
	Cscrollbar*	scr;		// Scrollbar, if needed
	int			nvis;		// number of visible options
	int			first;		// index of current top visible option
	Option*		options;	// an array of the options
	int			noptions;	// length of options
};


struct Cscrollbar
{
	Frame*		f;
	Formfield*	ff;
	Rectangle		r;
	int			flags;
	int			tag;		// Cscrollbartag
	int			top;		// pixels in trough above/left of slider
	int			bot;		// pixels in trough below/right of slider
	int			dragv;	// drag point
	int			mindelta;	// need delta of at least this (pixels)
	Control*		ctl;		// if non-nil, scrolls this control
};


struct Canimimage
{
	Frame*		f;
	Formfield*	ff;
	Rectangle		r;
	int			flags;
	int			tag;		// Canimimagetag
	CImage*		cim;		// contains mims array to animate
	int			cur;		// current slot in mims array
	int			redraw;	// need to redraw all?
	Background	bg;		// if need restore-to-background
};


struct Cprogbox
{
	Frame*		f;
	Formfield*	ff;
	Rectangle		r;
	int			flags;
	int			tag;		// Cprogboxtag
	int			state;	// Pstart, etc.
	int			pcnt;		// percent done
	int			bsid;		// bytesource id
	Rune*		src;		// bytesource req.url
	Rune*		err;		// possible error string
};


struct Clabel
{
	Frame*		f;
	Formfield*	ff;
	Rectangle		r;
	int			flags;
	int			tag;		// Clabeltag
	Rune*		s;		// text of label
};

// Control variants
enum {
	Cbuttontag,
	Centrytag,
	Ccheckboxtag,
	Cselecttag,
	Cscrollbartag,
	Canimimagetag,
	Cprogboxtag,
	Clabeltag
};

// Control flags
enum {
	CFactive =	(1<<0),
	CFenabled =	(1<<1),
	CFhasfocus =	(1<<2),
	CFscrvert =	(1<<3),
	CFscracta1 =	(1<<4),
	CFscracta2 =	(1<<5),
	CFscracttr1 =	(1<<6),
	CFscracttr2 =	(1<<7),
	CFscrallact = (CFactive|CFscracta1|CFscracta2|CFscracttr1|CFscracttr2)
};

// Control actions
enum {
	CAnone,
	CAscrollpage,
	CAscrollline,
	CAscrolldelta,
	CAscrollabs,
	CAbuttonpush,
	CAflyover,
	CAreturnkey,
	CAtabkey,
	CAkeyfocus
};

// Result of layout
struct Lay
{
	Line*		start;			// fake before-the-first-line
	Line*		end;			// fake after-the-last-line
	int			targetwidth;	// target width
	int			width;		// actual width
	int			height;		// actual height
	int			margin;		// extra space on all four sides
	Ifloat*		floats;		// floats, from bottom up
	Background	background;	// background for layout
	uchar		just;			// default line justification
	uchar		flags;		// Lchanged
};


extern void		layoutinit(void);
extern int			layout(Frame* f, ByteSource* bs, uchar** pbuf);
extern void		drawrelief(Image* im, Rectangle r, int style);
extern void		drawborder(Image* im, Rectangle r, int n, int color);
extern void		drawfill(Image* im, Rectangle r, int color);
extern void		drawstring(Image* im, Point p, Rune* s);
extern Point		measurestring(Rune* s);
extern Frame*		newkid(Frame* parent, Kidinfo* ki, Rectangle r);
extern Frame*		newframe(void);
extern Frame*		newkid(Frame* parent, Kidinfo* ki, Rectangle r);
extern Framelist*	newframelist(Frame* frame, Framelist* next);
extern void		resetframe(Frame* f);
extern int			addcontrol(Frame* f, Control* c);
extern Point		lptosp(Frame* f, Point lp);
extern Point		sptolp(Frame* f, Point sp);
extern void		xscroll(Frame* f, int kind, int val);
extern void		yscroll(Frame* f, int kind, int val);
extern Loc*		findloc(Frame* f, Point p, Item* it);
extern Line*		newline(void);
extern Loc*		newloc(void);
extern void		addloc(Loc* loc, int kind, Point pos);
extern Frame*		lastframe(Loc* loc);
extern void		printloc(Loc* loc, char* msg);
extern Control*	newff(Frame* f, Formfield* ff);
extern Control*	newscroll(Frame* f, int isvert, int length, int breadth);
extern Control*	newentry(Frame* f, int nh, int nv, int linewrap);
extern Control*	newbutton(Frame* f, Image* pic, Image* picmask,
					Rune* lab, Iimage* it, int candisable, int dorelief);
extern Control*	newcheckbox(Frame* f, int isradio);
extern Control*	newselect(Frame* f, int nvis, Option* options, int noptions);
extern Control*	newanimimage(Frame* f, CImage* cim, Background bg);
extern Control*	newprogbox(Frame* f);
extern Control*	newlabel(Frame* f, Rune* s);
extern void		disable(Control* b);
extern void		enable(Control* b);
extern void		losefocus(Control* b);
extern void		gainfocus(Control* b);
extern void		scrollset(Control* sc, int v1, int v2, int vmax, int mindelta);
extern void		entryset(Control* e, Rune* s);
extern int			dokey(Control* c, int keychar);
extern int			domouse(Control* c, Point p, int mtype);
extern void		resetctl(Control* c);
extern void		drawctl(Control* c, int flush);
extern Lay*		newlay(int targetwidth, int just, int margin, Background bg);


// IMG

typedef struct ImageSource ImageSource;
typedef struct Jpegstate Jpegstate;
typedef struct Huffman Huffman;
typedef struct Framecomp Framecomp;
typedef struct Scancomp Scancomp;
typedef struct Gifstate Gifstate;
typedef struct GifEntry GifEntry;

enum {
	Mimerror,
	Mimnone,
	Mimpartial,
	Mimdone
};

struct ImageSource
{
	int			width;
	int			height;
	int			origw;
	int			origh;
	int			mtype;
	int			i;
	int			curframe;
	ByteSource*	bs;
	Gifstate*		gstate;
	Jpegstate*		jstate;
	int			err;
	jmp_buf		getmimsave;
};


struct Jpegstate
{
	int			sr;
	int			cnt;
	int			Nf;
	Framecomp*	comp;
	uchar		mode;
	int			X;
	int			Y;
	int**			qt;
	Huffman**	dcht;
	Huffman**	acht;
	int			Ns;
	Scancomp*	scomp;
	int			Ss;
	int			Se;
	int			Ah;
	int			Al;
	int			ri;
	int			nseg;
	int*			nblock;
	int**			dccoeff;
	int***		accoeff;
	int			nacross;
	int			ndown;
	int			Hmax;
	int			Vmax;
};


struct Huffman
{
	int*	bits;
	int*	size;
	int*	code;
	int*	val;
	int	mincode[17];
	int	maxcode[17];
	int	valptr[17];
	int	value[256];
	int	shift[256];
};


struct Framecomp
{
	int	C;
	int	H;
	int	V;
	int	Tq;
};


struct Scancomp
{
	int	C;
	int	tdc;
	int	tac;
};


struct Gifstate
{
	int		fields;
	int		bgrnd;
	int		aspect;
	int		flags;
	int		delay;
	uchar	trindex;
	GifEntry*	tbl;
	uchar*	globalcmap;
	int		globalcmaplen;
	uchar*	cmap;
	int		cmaplen;
};


struct GifEntry
{
	int	prefix;
	int	exten;
};


extern void			imginit(void);
extern int				supported(int mtype);
extern int				closest_rgbpix(int r, int g, int b);
extern ImageSource*	newimagesource(ByteSource* bs, int w, int h);
extern int				getmim(ImageSource* is, MaskedImage** pans);


// EVENT

typedef struct EV EV;
typedef struct ScriptEvent ScriptEvent;

enum {
	EVkeytag,
	EVmousetag,
	EVmovetag,
	EVresizetag,
	EVexposetag,
	EVhidetag,
	EVquittag,
	EVstoptag,
	EValerttag,
	EVformtag,
	EVgotag,
	EVanimtag,
	EVprogresstag,
	EVdelaytag
};

struct EV
{
	int	tag;					// EVkeytag, etc.
	int	genframeid;			// frame that generated event (or -1)
	union {
		int	keychar;			// Unicode char for pressed key

		struct {
			Point p;			// coords of pointer
			int mtype;			// Mmove, etc.
		} mouse;

		Point	movept;			// new top-left of moved window

		Rectangle resizer;		// new window place and size

		struct {
			Rune* msg;		// message to show
			Channel* sync;		// wait for answer
		} alert;

		struct {
			int	frameid;		// which frame form is in
			int	formid;		// which form in the frame
			int	ftype;		// EFsubmit or EFreset
		} form;

		struct {
			ParsedUrl* url;		// where to go
			int target;			// frame to replace
			int gtype;			// EGnormal, etc.
		} go;

		struct {
			int	frameid;		// frame where ai lives
			Canimimage*	ai;	// advance frame for this image
		} anim;

		struct {
			int	bsid;			// byte source id
			int	state;		// Pstart, etc.
			int	pcnt;			// percent done
			Rune*	s;		// message
		} progress;

		struct {
			int	millisecs;		// time to wait before acting on ev
			EV*	ev;			// the delayed event
		} delay;
	} u;
};

// Events sent to scripting engines
struct ScriptEvent
{
	int	kind;
	int	frameid;
	int	formid;
	int	fieldid;
	int	anchorid;
	int	x;
	int	y;
	int	which;
};

// some special keychars (use Unicode Private Area)
enum {
	Kup = 0xF000,
	Kdown,
	Khome,
	Kleft,
	Kright
};

// Mouse event subtypes
enum {
	Mmove,
	Mlbuttondown,
	Mlbuttonup,
	Mldrag,
	Mmbuttondown,
	Mmbuttonup,
	Mmdrag,
	Mrbuttondown,
	Mrbuttonup,
	Mrdrag
};

// Form event subtypes
enum {
	EFsubmit,
	EFreset
};

// Go event subtypes
enum {
	EGnormal, EGreload, EGforward, EGback, EGhome, EGbookmarks
};

extern Channel*	evchan;

extern void	eventinit(void);
extern EV	evgo(ParsedUrl* u, int targ, int gtype, int genframeid);
extern EV	evmouse(Point p, int mtype);
extern EV	evkey(int keycode);

#pragma varargck	type "M"	EV*

// GUI

extern Rectangle	rmain;
extern Rectangle	rctl;
extern Rectangle	rprog;

extern void	guiinit(void);
extern void	pushclipr(Rectangle r);
extern void	replaceclipr(Rectangle r);
extern void	popclipr(void);
extern Image*	makepopup(int width, int height);


// ICONS

// Built-in icon identifiers
enum {
	IClogo,
	ICback,
	ICfwd,
	ICreload,
	ICstop,
	IChist,
	ICbmark,
	ICexit,
	NICONS
};

extern Image*	geticon(int icon, Image** pmask);


// I

typedef struct GoSpec GoSpec;
typedef struct DocConfig DocConfig;
typedef struct HistNode HistNode;
typedef struct HistNode_list HistNode_list;
typedef struct History History;
typedef struct AuthInfo AuthInfo;
typedef struct CtlLayout CtlLayout;
typedef struct ProgLayout ProgLayout;
typedef struct PopupLayout PopupLayout;
typedef struct PopupAns PopupAns;

// package up info related to a navigation command
struct GoSpec
{
	int			kind;		// GoNormal, etc.
	ParsedUrl*	url;		// destination (absolute)
	int			meth;	// HGet or HPost
	Rune*		body;	// used if HPost
	int			target;	// name of target frame
	Rune*		auth;		// optional auth info
	HistNode*		histnode;	// if kind is GoHistnode
};

enum {
	GoNormal,
	GoHistnode,
	GoBookmarks,
	GoHistory,
	GoStop
};

// Information about a set of frames making up the screen
struct DocConfig
{
	Rune*	framename;	// nonempty, except possibly for topconfig
	Rune*	title;
	int		initconfig;		// true unless this is a frameset and some subframe changed
	GoSpec*	gospec;
	// TODO: add current y pos and form field values
};


// Information about a particular screen configuration
struct HistNode
{
	DocConfig*		topconfig;		// config of top (whole doc, or frameset root)
	DocConfig**		kidconfigs;	// configs for kid frames (if a frameset)
	int				nkids;
	HistNode_list*		preds;		// edges in (via normal navigation)
	HistNode_list*		succs;		// edges out (via normal navigation)
};

// For keeping lists of HistNodes
struct HistNode_list
{
	HistNode_list*		next;		// in list
	HistNode*			histnode;
};


// The browsing history
struct History
{
	HistNode**	h;		// array of all visited HistNodes, in LRU order
	int			hlen;		// allocated length of h
	int			n;		// h[0:n] is valid part of h
};


// Authentication strings
struct AuthInfo
{
	AuthInfo*	next;			// in list of all auths
	Rune*	realm;
	Rune*	credentials;
};


// Indices into layout controls array
enum {
	CLCbackbut, CLCfwdbut, CLCreloadbut, CLCstopbut, CLChistbut,
	CLCbmarkbut, CLCexitbut, CLCentry,
	NUMCLCS
};

struct CtlLayout
{
	Image*	logoicon;
	Point		logopos;
	Point		butspos;
	Point		entrypos;
	Point		statuspos;
	Control*	controls[NUMCLCS];
	Rune*	status;
};

struct ProgLayout
{
	Control**	box;
	int		boxlen;
	int		nused;
	Point		first;
	int		dx;
};

struct PopupLayout
{
	int		kind;			// PopupNone, PopupAuth, PopupSaveAs, or PopupAlert
	Control**	controls;
	int		ncontrols;
	Control*	okbut;
	Control*	cancelbut;
};

enum {
	PopupNone,
	PopupAuth,
	PopupSaveAs,
	PopupAlert
};

struct PopupAns
{
	int		code;
	Rune*	s;
};


extern void	fatalerror(char* msg);
extern void	finish(void);
extern void	trace(char* msg, ...);

// GC
extern void gcinit(void);

// DEBUGGING
extern void poolshow(void);

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].