extern queue squeue; // the three queues on which ranges reside extern queue bfqueue; extern queue ufqueue; extern double minfull; extern double coltol; int anymore(); // The following is used in some calls to range::enqueue(int = 0). #define ANDBLOCK 1 class page; enum { DRAFT = 0, FINAL = 1 }; // The mergestream currpage->stage serves as a staging area for page makeup: // when primed, it contains a minimal acceptable chunk of input ranges. // The page must either take or leave everything that's on stage. class mergestream : public queue { page *currpage; // current page that's accepting stuff public: mergestream(page *cp) { currpage = cp; unblock(); } void unblock(); int prime(); // stage next legal chunk void pend(); // process pending chunk on stage }; // The multicol currpage->twocol is the two-column piece of the page to which // two-column ranges are currently being added. // The page sets htavail to indicate how tall it is allowed to become. // All ranges on definite must be placed when the multicol is printed. // Each of these definite ranges also resides on one of column[0] and [1], // which represent the current best guess about how to divide definite // between the two columns. class multicol : public range { page *currpage; // current page that's accepting stuff stream definite; // definitely on page stream scratch; // for trial compositions stream column[2]; // left (0) and right (1) columns int leftblocked; // OK to add to left column? int htavail; // max possible ht, set by page::tryout() int prevhtavail; // max 2-colht last time we added something friend page; public: multicol(page *cp) { currpage = cp; leftblocked = 0; htavail = 0; prevhtavail = -1; setgoal(NOGOAL); } // the two-column piece behaves as part // of the stream of single-column input. int numcol() { return 1; } int nonempty() { return definite.more(); } void choosecol(range *, int);// add first arg to one or other column void choosecol(stream*, int);// add *all ranges on first arg* // to one or other column // NOT the same as a mapcar of the // preceding function over the ranges // on the first argument! void compose(int); // divide into two columns void tryout(); // decide which column gets stage contents void stretch(int); // justify both columns to given height int print(int curv, int col); int height(); // an upper bound on actual height int rawht() { return max(column[0].rawht(), column[1].rawht()); } void reheight(int *cv, int *mv) { *cv += height(); *mv = max(*mv, *cv); } void dump(); int isvbox() { return nonempty(); } // during trimspace() }; // These sentinel ranges are used to separate the ranges on twocol::definite // into the chunks in which they came from the staging area. // Thus, they preserve the results of the computation that was done to prime // page::stage. class sentrange : public range { public: sentrange() { } int numcol() { return 2; } int issentinel() { return 1; } }; class page { int pagesize; // allowed maximum height int prevncol; // was last item tried 1- or 2-column? int vsince; // how many vboxes from "current" BS // (to avoid putting a single line on // a page with a very large floatable) stream definite; // definitely on page, in input order stream scratch; // playground in which to alter page void cmdproc(); // process any of several commands void parmproc(); // process any of several parameters void tryout(); // see whether current stage contents fit void compose(int); // float and trim current page contents void makescratch(int); // fill scratch area void commit(); // accept the items on stage void welsh(); // reject the items on stage void adddef(range *r); // add to one of the definite queues // (definite or twocol->definite) public: mergestream *stage; friend mergestream; multicol *twocol; friend multicol; page(int p) { pagesize = p; prevncol = 1; vsince = 0; stage = new mergestream(this); twocol = new multicol(this); } ~page() { definite.freeall(); scratch.freeall(); } void fill(); int blank() { return !definite.more() && !twocol->definite.more();} void print(); }; // functions in page.c main(int, char **);