336 lines · 10.0 KB · C
RawDownload
const int	NOGOAL = -1; class stream; enum primeflush { NO, YES, EXPECTED, UNEXPECTED };	// mergestream::prime() // Ranges do two things.  They interpose a layer between slugs and the rest// of the program; this is important because of the grossness of the slug// data structure (made necessary by its origins in troff output).  Ranges also// group together other ranges into meaningful chunks like unbreakable stream// objects, floatable objects, and page headers and footers.// Member function height() returns a range's height as of the latest composition.// Member function rawht() returns the range's original height in the input.class range {  protected:	slug	*first;		// earliest slug in range	int	accumV;		// accumulated V to this point  public:	range()		{ first = 0; accumV = 0; }	range(slug *p)	{ first = p; accumV = 0; }	virtual ~range() { }	char	*headstr()		{		return first ? first->headstr() : (char*)""; }	char	*typename()		{ return first->typename(); }	int	serialno()		{ return first->serialno(); }	int	lineno()		{ return first->lineno(); }	virtual void	dump()		{ first->dump(); }	virtual void	rdump()		{ dump(); }	virtual int	print(int cv, int col)	{		first->slugout(col); return cv; }	virtual int	floatable()	{ return 0; }	virtual int	brkafter()	{ return 1; }	virtual int	isnested()	{ return 0; }	virtual int	issp()		{ return 0; }	virtual int	isvbox()	{ return 0; }	virtual int	isneed()	{ return 0; }	virtual int	iscmd()		{ return 0; }	virtual int	cmdtype()	{ return -1; }	virtual int	isparm()	{ return 0; }	virtual int	parmtype()	{ return -1; }	virtual int	parm()		{ return -1; }	virtual int	breakable()	{ return 0; }	virtual int	forceflush()	{ return UNEXPECTED; }	virtual int	pn()		{ return 0; }	virtual stream	*children()	{ return 0; }	// see page::peeloff()	virtual void	killkids()	{ }	virtual void	enqueue(int = 0);	virtual int	height()	{ return 0; }	virtual int	rawht()		{ return 0; }	virtual int	needht()	{ return 0; }	virtual void	reheight(int *, int *)	{ }	virtual void	rerawht(int *, int *)	{ }	virtual void	setheight(int) { }	virtual void	restore()	{ }		// goals of floatables	virtual int	goal()		{ return NOGOAL; }	int		accum()		{ return accumV; }	void		setaccum(int n)	{ accumV = n; }	virtual	void	setgoal(int)	{ }	virtual void	pickgoal(int, double)	{ }	virtual int	numcol()	{ return first->numcol(); }	virtual int	issentinel()	{ return 0; }	virtual range	*clone()	{ return 0; }	virtual int	breaking()	{ return 0; }	virtual void	setbreaking()	{ }}; class vboxrange : public range {	int	dv;		// inherited from slug	int	base;		// inherited from slug	int	brk;		// 0 => ok to break after, 1 => no break   public:	vboxrange(slug *p) : range(p) { dv = p->dv; base = p->base; brk = p->parm; }	void	dump() {		printf("#### VBOX brk? %d dv %d ht %d\n", brk, dv, dv+base); }	int	print(int cv, int col) {		printf("V%d\n", cv += dv); first->slugout(col); return cv+base; }	int	brkafter()		{ return !brk; }	int	isvbox()		{ return 1; }	int	forceflush()		{ return NO; }	int	height()		{ return dv + base; }	int	rawht()			{ return first->dv + first->base; }	void	reheight(int *cv, int *mv) {		*cv += dv+base; *mv = max(*mv, *cv); }	void	rerawht(int *cv, int *mv) {		*cv += rawht(); *mv = max(*mv, *cv); }}; class sprange : public range {	int dv;  public:	sprange(slug *p) : range(p) { dv = first->dv; }	void	dump() {		printf("#### SP dv %d (originally %d)\n", dv, first->dv); }	int	print(int cv, int col)	{		first->slugout(col); return cv + dv; }	int	issp()			{ return 1; }	int	forceflush()		{ return YES; }	int	height()		{ return dv; }	int	rawht()			{ return first->dv; }	void	reheight(int *, int *);	void	rerawht(int *, int *);	void	setheight(int n)	{ dv = n; }}; class tmrange : public range {  public:	tmrange(slug *p) : range(p)	{ }	int	forceflush()		{ return NO; }	int	print(int cv, int col)	{ first->slugout(col); return cv; }}; class coordrange : public range {  public:	coordrange(slug *p) : range(p)	{ }	int	forceflush()		{ return NO; }	int	print(int cv, int col)		{ first->slugout(col); printf(" Y %d\n", cv); return cv; }}; class nerange : public range {  public:	nerange(slug *p) : range(p)	{ }	int	isneed()		{ return 1; }	int	forceflush()		{ return YES; }	int	needht()		{ return first->dv; }}; class mcrange : public range {  public:	mcrange(slug *p) : range(p)	{ }	int	forceflush()		{ return YES; }}; class cmdrange : public range {  public:	cmdrange(slug *p) : range(p)	{ }	int	iscmd()			{ return 1; }	int	forceflush()		{ return YES; }	int	cmdtype()		{ return first->parm; }}; class parmrange : public range {  public:	parmrange(slug *p) : range(p)	{ }	int	isparm()		{ return 1; }	int	forceflush()		{ return YES; }	int	parmtype()		{ return first->parm; }	int	parm()			{ return first->parm2; }}; class bsrange : public range {  public:	bsrange(slug *p) : range(p)	{ }	int	forceflush()		{ return NO; }	int	print(int cv, int col)	{ first->slugout(col); return cv; }}; class endrange : public range {  public:	endrange(slug *p) : range(p)	{ }	int	forceflush()		{ return UNEXPECTED; }}; class eofrange : public range {  public:	eofrange(slug *p) : range(p)	{ }	int	forceflush()		{ return UNEXPECTED; }}; extern eofrange *lastrange;	// the EOF block (trailer, etc.) goes here int measure(stream *);int rawmeasure(stream *); // A nestrange packages together a sequence of ranges, its subrange.// Other parts of the program reach in and alter the dimensions of// some of these ranges, so when the height of a range is requested// it is computed completely afresh.// (Note:  the alternative, of keeping around many copies of ranges// with different dimensions, was abandoned because of the difficulty// of ensuring that exactly one copy of each original range would be// output.)class nestrange : public range {  protected:	stream	*subrange;	int isbreaking;	int rawdv;  public:	nestrange() : range()	{ subrange = 0; isbreaking = 0; rawdv = -1; }	nestrange(slug *p, stream *s) : range(p)				{ subrange = s; isbreaking = 0; rawdv = -1; }	void	rdump();	virtual void restore();	stream	*children()	{ return subrange; }	void	killkids();	int	height()	{ return measure(subrange); }	int	rawht()		{ if (rawdv < 0 || isbreaking) rawdv = rawmeasure(subrange);					return rawdv; }	void	reheight(int *cv, int *mv) {			*mv += measure(subrange); *cv = max(*mv, *cv); }	void	rerawht(int *cv, int *mv) {			*mv += rawht(); *cv = max(*mv, *cv); }	int	isnested()	{ return 1; }	int	forceflush()	{ return EXPECTED; }	int	print(int cv, int col);	int	breaking()	{ return isbreaking; }	void	setbreaking()	{ isbreaking++; }}; class usrange : public nestrange {  public:	usrange()	{ }	usrange(slug *p, stream *s) : nestrange(p, s) {}	void dump() { printf("#### US	dv %d\n", height()); }	range	*clone();}; class ufrange : public nestrange {	int	goalV, goal2;  public:	ufrange()	{ }	ufrange(slug *p, stream *s) : nestrange(p, s) {		goalV = p->parm; goal2 = p->parm2; }	void 	dump() { printf("#### UF   dv %d goal %d goal2 %d\n",		height(), goalV, goal2); }	int	floatable()	{ return 1; }	void	enqueue(int = 0);	range	*clone();	int	goal()		{ return goalV; }	void	setgoal(int n)	{ goalV = goal2 = n; }	void	pickgoal(int acv, double scale);	void	restore()	{ goalV = first->parm; goal2 = first->ht; }}; class bfrange : public nestrange {	int	goalV, goal2;  public:	bfrange()	{ }	bfrange(slug *p, stream *s) : nestrange(p, s) {		goalV = p->parm; goal2 = p->parm2; }	void 	dump() { printf("#### BF   dv %d goal %d goal2 %d\n",		height(), goalV, goal2); }	int	floatable()	{ return 1; }	void	enqueue(int = 0);	range	*clone();	int	goal()		{ return goalV; }	void	setgoal(int n)	{ goalV = goal2 = n; }	void	pickgoal(int acv, double scale);	void	restore()	{ goalV = first->parm; goal2 = first->parm2; }	int	breakable()	{ return 1; }	// can be broken}; class ptrange : public nestrange {	int	pgno;  public:	int	pn()	{ return pgno; }	ptrange(slug *p, stream *s) : nestrange(p, s) { pgno = p->parm; }	void 	dump() { printf("#### PT   pgno %d dv %d\n", pgno, height()); }}; class btrange : public nestrange {	int	pgno;  public:	btrange(slug *p, stream *s) : nestrange(p, s) { pgno = p->parm; }	void 	dump() { printf("#### BT   pgno %d dv %d\n", pgno, height()); }}; // A stream is a sequence of ranges; we use this data structure a lot// to traverse various sequences that crop up in page-making.class stream {  protected:public:	struct strblk {		// ranges are linked by these blocks		strblk	*next;		range	*rp;	};	strblk	*first;	strblk	*last;	strblk	*curr;  public:	stream()		{ curr = last = first = 0; }	stream(range *r)	{ curr = last = first = new strblk;					last->rp = r; last->next = 0; }	void	freeall();	// note:  not a destructor	void	dump();		// top level	void	rdump();	// recursive	int	restoreall();	range	*current()	{ return curr->rp; }	range	*next()		{ return curr && curr->next ? curr->next->rp : 0; }	void	advance()	{ curr = curr->next; }	range	*append(range *r);	void	split();	int	more()		{ return curr && curr->rp; }	int	height();	int	rawht();}; // A generator iterates through all the ranges of a stream// (not just the root ranges of nestranges).class generator {	stream	s;	generator *child;  public:	generator()		{ child = 0; }	generator(stream *sp)	{ s = *sp; child = 0; }	range	*next();}; extern stream	ptlist, btlist;		// page titles #undef INFINITY#define INFINITY 1000001 // A queue is a distinguished kind of stream.// It keeps its contents in order by the serial numbers of the ranges.// A queue can be blocked from dequeuing something to indicate// that it's not worth considering the queue again on a given page.class queue : public stream {	strblk	*newguy;  protected:	int	blocked;	void	check(char *);  public:	queue() : blocked(0)	{ }	range	*enqueue(range *r);	range	*dequeue();	void	block()		{ blocked = 1; }	void	unblock()	{ blocked = 0; }	int	more()		{ return !blocked && stream::more(); }	int	empty()		{ return !stream::more(); }	int	serialno()	{ return empty() ? INFINITY : current()->serialno(); }}; // functions in range.cvoid checkout();void startup(FILE *);