diff options
Diffstat (limited to 'src/cmd/mpm/queue.cc')
-rw-r--r-- | src/cmd/mpm/queue.cc | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/src/cmd/mpm/queue.cc b/src/cmd/mpm/queue.cc new file mode 100644 index 00000000..d065ac82 --- /dev/null +++ b/src/cmd/mpm/queue.cc @@ -0,0 +1,235 @@ +#include "misc.h" +#include "slug.h" +#include "range.h" +#include "page.h" + +queue squeue; +queue bfqueue; +queue ufqueue; + +// We use the stream function current() to access a queue's head. +// Thus, queue member curr should always point to its first range. +void queue::check(char *whence) +{ + if (dbg & 8) { + char *p; + if (this == &squeue) + p = "squeue"; + else if (this == &bfqueue) + p = "bfqueue"; + else if (this == &ufqueue) + p = "ufqueue"; + else + p = "weird queue"; + printf("#checking %s\n", p); + } + if (first != curr) + ERROR "check(%s): first != curr, line %d\n", whence, curr->rp->lineno() FATAL; +} + +// When ranges are told to enqueue themselves, they are being rejected from the +// stage back onto their original queues. +// They reset any parameters that may have been altered by staging or trial +// composition. + +void range::enqueue(int block) +{ + squeue.enqueue(this); + if (block) + squeue.block(); +} + +void ufrange::enqueue(int block) +{ + restore(); // both goal positions + ufqueue.enqueue(this); + if (block) + ufqueue.block(); +} + +void bfrange::enqueue(int block) +{ + restore(); // both goal positions + bfqueue.enqueue(this); + if (block) + bfqueue.block(); +} + +int anymore() +{ + return !(squeue.empty() && ufqueue.empty() && bfqueue.empty()); +} + +void mergestream::unblock() +{ + squeue.unblock(); + bfqueue.unblock(); + ufqueue.unblock(); +} + +// Fill the staging area with a minimal chunk of input ranges. +int mergestream::prime() +{ + if (dbg & 4) + printf("#entering mergestream::prime()\n"); + if (!empty()) + return 1; + int brkok = 1; // is it OK to break after the last + // VBOX that was added to the stage? + int needheight = -1; // minimum acceptable height of the + // chunk being constructed on stage + // If the range at the head of any queue is breaking, + // deal with it first. + if (squeue.more() && squeue.current()->breaking()) + enqueue(squeue.dequeue()); + else if (bfqueue.more() && (bfqueue.current()->breaking() || + (bfqueue.serialno() < squeue.serialno()))) + enqueue(bfqueue.dequeue()); + else if (ufqueue.more() && (ufqueue.current()->breaking() || + (ufqueue.serialno() < squeue.serialno()))) + enqueue(ufqueue.dequeue()); + else while (squeue.more()) { + // Fill the stage with enough ranges to be a valid chunk. + range *r = squeue.dequeue(); + if (r->isvbox()) { // VBOX + if (dbg & 16) + printf("#VBOX: !empty: %d; brkok: %d; vsince: %d\n", + !empty(), brkok, currpage->vsince); + if (!empty() // there's something there + && brkok + // it's OK to break here + && currpage->vsince >= 2 + // enough stream has gone onto this page + && rawht() >= needheight + // current need has been satisfied + ) { + // the stage already contains enough + // ranges, so this one can wait + r->enqueue(); + break; + } else { + if (r->rawht() > 0) { + ++currpage->vsince; + brkok = r->brkafter(); + } + enqueue(r); + } + } else if (r->isnested() || r->issp()) { // US, SP + if (!empty() && rawht() >= needheight) { + // enough already, wait + r->enqueue(); + break; + } + currpage->vsince = 0; + enqueue(r); + if (height() >= needheight) + break; + } else if (r->isneed()) { // NE + if (!empty() && rawht() >= needheight) { + // not currently working on an unsatisfied NEed + r->enqueue(); + break; + } + // deal with overlapping NEeds + needheight = rawht() + max(needheight - rawht(), r->needht()); + enqueue(r); + } else if (r->forceflush() == NO) { + enqueue(r); + } else if (r->forceflush() == YES) { + currpage->vsince = 0; + if (!empty()) { + // ready or not, r must wait + r->enqueue(); + break; + } + enqueue(r); + break; + } else + ERROR "unexpected %s[%s] in prime(), line %d\n", + r->typename(), r->headstr(), r->lineno() FATAL; + } + return more(); // 0 if nothing was staged +} + +void page::cmdproc() +{ + if (stage->next()) + ERROR "more than a single command on bsqueue\n" FATAL; + switch (stage->current()->cmdtype()) { + case FC: // freeze the current 2-column range and start a new one + adddef(stage->dequeue()); + twocol->compose(FINAL); + adddef(twocol); + twocol = new multicol(this); + break; + case BP: // force a page break + adddef(stage->dequeue()); + squeue.block(); + break; + case FL: // flush out all floatables that precede this range: + // no more stream input allowed until they're past + if (stage->serialno() > ufqueue.serialno() || + stage->serialno() > bfqueue.serialno()) { + range *r = stage->dequeue(); + r->enqueue(ANDBLOCK); + } else + adddef(stage->dequeue()); + break; + default: + stage->current()->dump(); + ERROR "unknown command\n" FATAL; + } +} + +void page::parmproc() +{ + if (stage->next()) + ERROR "more than a single parameter on bsqueue\n" FATAL; + switch (stage->current()->parmtype()) { + case NP: // page top margin + if (blank()) + pagetop = stage->current()->parm(); + pagesize = pagebot - pagetop; + break; + case FO: + if (blank()) + pagebot = stage->current()->parm(); + pagesize = pagebot - pagetop; + break; + case PL: + if (blank()) + physbot = stage->current()->parm(); + break; + case MF: + minfull = 0.01*stage->current()->parm(); + break; + case CT: + coltol = 0.01*stage->current()->parm(); + break; + case WARN: + wantwarn = stage->current()->parm(); + break; + case DBG: + dbg = stage->current()->parm(); + break; + default: + stage->current()->dump(); + ERROR "unknown parameter\n" FATAL; + } + adddef(stage->dequeue()); +} + +// Process the contents of the staging area; a relic that used to do more. +void mergestream::pend() +{ + if (dbg & 4) + printf("#entering mergestream::pend()\n"); + if (!more()) + return; + if (current()->iscmd()) + currpage->cmdproc(); + else if (current()->isparm()) + currpage->parmproc(); + else + currpage->tryout(); +} |