plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

queue.cc (5717B)


      1 #include	"misc.h"
      2 #include	"slug.h"
      3 #include	"range.h"
      4 #include	"page.h"
      5 
      6 queue	squeue;
      7 queue	bfqueue;
      8 queue	ufqueue;
      9 
     10 // We use the stream function current() to access a queue's head.
     11 // Thus, queue member curr should always point to its first range.
     12 void queue::check(char *whence)
     13 {
     14 	if (dbg & 8) {
     15 		char *p;
     16 		if (this == &squeue)
     17 			p = "squeue";
     18 		else if (this == &bfqueue)
     19 			p = "bfqueue";
     20 		else if (this == &ufqueue)
     21 			p = "ufqueue";
     22 		else
     23 			p = "weird queue";
     24 		printf("#checking %s\n", p);
     25 	}
     26 	if (first != curr)
     27 		ERROR "check(%s): first != curr, line %d\n", whence, curr->rp->lineno() FATAL;
     28 }
     29 
     30 // When ranges are told to enqueue themselves, they are being rejected from the
     31 // stage back onto their original queues.
     32 // They reset any parameters that may have been altered by staging or trial
     33 // composition.
     34 
     35 void	range::enqueue(int block)
     36 {
     37 	squeue.enqueue(this);
     38 	if (block)
     39 		squeue.block();
     40 }
     41 
     42 void	ufrange::enqueue(int block)
     43 {
     44 	restore();			// both goal positions
     45 	ufqueue.enqueue(this);
     46 	if (block)
     47 		ufqueue.block();
     48 }
     49 
     50 void	bfrange::enqueue(int block)
     51 {
     52 	restore();			// both goal positions
     53 	bfqueue.enqueue(this);
     54 	if (block)
     55 		bfqueue.block();
     56 }
     57 
     58 int anymore()
     59 {
     60 	return !(squeue.empty() && ufqueue.empty() && bfqueue.empty());
     61 }
     62 
     63 void mergestream::unblock()
     64 {
     65 	squeue.unblock();
     66 	bfqueue.unblock();
     67 	ufqueue.unblock();
     68 }
     69 
     70 // Fill the staging area with a minimal chunk of input ranges.
     71 int mergestream::prime()
     72 {
     73 	if (dbg & 4)
     74 		printf("#entering mergestream::prime()\n");
     75 	if (!empty())
     76 		return 1;
     77 	int brkok = 1;			// is it OK to break after the last
     78 					// VBOX that was added to the stage?
     79 	int needheight = -1;		// minimum acceptable height of the
     80 					// chunk being constructed on stage
     81 	// If the range at the head of any queue is breaking,
     82 	// deal with it first.
     83 	if (squeue.more() && squeue.current()->breaking())
     84 		enqueue(squeue.dequeue());
     85 	else if (bfqueue.more() && (bfqueue.current()->breaking() ||
     86 		(bfqueue.serialno() < squeue.serialno())))
     87 		enqueue(bfqueue.dequeue());
     88 	else if (ufqueue.more() && (ufqueue.current()->breaking() ||
     89 		(ufqueue.serialno() < squeue.serialno())))
     90 		enqueue(ufqueue.dequeue());
     91 	else while (squeue.more()) {
     92 		// Fill the stage with enough ranges to be a valid chunk.
     93 		range *r = squeue.dequeue();
     94 		if (r->isvbox()) {	// VBOX
     95 			if (dbg & 16)
     96 				printf("#VBOX: !empty: %d; brkok: %d; vsince: %d\n",
     97 					!empty(), brkok, currpage->vsince);
     98 			if (!empty()	// there's something there
     99 				&& brkok
    100 					// it's OK to break here
    101 				&& currpage->vsince >= 2
    102 					// enough stream has gone onto this page
    103 				&& rawht() >= needheight
    104 					// current need has been satisfied
    105 				) {
    106 					// the stage already contains enough
    107 					// ranges, so this one can wait
    108 				r->enqueue();
    109 				break;
    110 			} else {
    111 				if (r->rawht() > 0) {
    112 					++currpage->vsince;
    113 					brkok = r->brkafter();
    114 				}
    115 				enqueue(r);
    116 			}
    117 		} else if (r->isnested() || r->issp()) {	// US, SP
    118 			if (!empty() && rawht() >= needheight) {
    119 					// enough already, wait
    120 				r->enqueue();
    121 				break;
    122 			}
    123 			currpage->vsince = 0;
    124 			enqueue(r);
    125 			if (height() >= needheight)
    126 				break;
    127 		} else if (r->isneed()) {	// NE
    128 			if (!empty() && rawht() >= needheight) {
    129 					// not currently working on an unsatisfied NEed 
    130 				r->enqueue();
    131 				break;
    132 			}
    133 					// deal with overlapping NEeds
    134 			needheight = rawht() + max(needheight - rawht(), r->needht());
    135 			enqueue(r);
    136 		} else if (r->forceflush() == NO) {
    137 			enqueue(r);
    138 		} else if (r->forceflush() == YES) {
    139 			currpage->vsince = 0;
    140 			if (!empty()) {
    141 					// ready or not, r must wait
    142 				r->enqueue();
    143 				break;
    144 			}
    145 			enqueue(r);
    146 			break;
    147 		} else
    148 			ERROR "unexpected  %s[%s] in prime(), line %d\n",
    149 				r->typename(), r->headstr(), r->lineno() FATAL;
    150 	}
    151 	return more();			// 0 if nothing was staged
    152 }
    153 
    154 void page::cmdproc()
    155 {
    156 	if (stage->next())
    157 		ERROR "more than a single command on bsqueue\n" FATAL;
    158 	switch (stage->current()->cmdtype()) {
    159 	case FC:	// freeze the current 2-column range and start a new one
    160 		adddef(stage->dequeue());
    161 		twocol->compose(FINAL);
    162 		adddef(twocol);
    163 		twocol = new multicol(this);
    164 		break;
    165 	case BP:	// force a page break
    166 		adddef(stage->dequeue());
    167 		squeue.block();
    168 		break;
    169 	case FL:	// flush out all floatables that precede this range:
    170 			// no more stream input allowed until they're past
    171 		if (stage->serialno() > ufqueue.serialno() ||
    172 			stage->serialno() > bfqueue.serialno()) {
    173 			range *r = stage->dequeue();
    174 			r->enqueue(ANDBLOCK);
    175 		} else
    176 			adddef(stage->dequeue());
    177 		break;
    178 	default:
    179 		stage->current()->dump();
    180 		ERROR "unknown command\n" FATAL;
    181 	}
    182 }
    183 
    184 void page::parmproc()
    185 {
    186 	if (stage->next())
    187 		ERROR "more than a single parameter on bsqueue\n" FATAL;
    188 	switch (stage->current()->parmtype()) {
    189 	case NP:	// page top margin
    190 		if (blank())
    191 			pagetop = stage->current()->parm();
    192 		pagesize = pagebot - pagetop;
    193 		break;
    194 	case FO:
    195 		if (blank())
    196 			pagebot = stage->current()->parm();
    197 		pagesize = pagebot - pagetop;
    198 		break;
    199 	case PL:
    200 		if (blank())
    201 			physbot = stage->current()->parm();
    202 		break;
    203 	case MF:
    204 		minfull = 0.01*stage->current()->parm();
    205 		break;
    206 	case CT:
    207 		coltol = 0.01*stage->current()->parm();
    208 		break;
    209 	case WARN:
    210 		wantwarn = stage->current()->parm();
    211 		break;
    212 	case DBG:
    213 		dbg = stage->current()->parm();
    214 		break;
    215 	default:
    216 		stage->current()->dump();
    217 		ERROR "unknown parameter\n" FATAL;
    218 	}
    219 	adddef(stage->dequeue());
    220 }
    221 
    222 // Process the contents of the staging area; a relic that used to do more.
    223 void mergestream::pend()
    224 {
    225 	if (dbg & 4)
    226 		printf("#entering mergestream::pend()\n");
    227 	if (!more())
    228 		return;
    229 	if (current()->iscmd())
    230 		currpage->cmdproc();
    231 	else if (current()->isparm())
    232 		currpage->parmproc();
    233 	else
    234 		currpage->tryout();
    235 }