Blob


1 #include "misc.h"
2 #include "slug.h"
3 #include "range.h"
4 #include "page.h"
6 queue squeue;
7 queue bfqueue;
8 queue ufqueue;
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 }
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.
35 void range::enqueue(int block)
36 {
37 squeue.enqueue(this);
38 if (block)
39 squeue.block();
40 }
42 void ufrange::enqueue(int block)
43 {
44 restore(); // both goal positions
45 ufqueue.enqueue(this);
46 if (block)
47 ufqueue.block();
48 }
50 void bfrange::enqueue(int block)
51 {
52 restore(); // both goal positions
53 bfqueue.enqueue(this);
54 if (block)
55 bfqueue.block();
56 }
58 int anymore()
59 {
60 return !(squeue.empty() && ufqueue.empty() && bfqueue.empty());
61 }
63 void mergestream::unblock()
64 {
65 squeue.unblock();
66 bfqueue.unblock();
67 ufqueue.unblock();
68 }
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();
115 enqueue(r);
117 } else if (r->isnested() || r->issp()) { // US, SP
118 if (!empty() && rawht() >= needheight) {
119 // enough already, wait
120 r->enqueue();
121 break;
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;
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;
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;
151 return more(); // 0 if nothing was staged
154 void page::cmdproc()
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;
184 void page::parmproc()
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;
219 adddef(stage->dequeue());
222 // Process the contents of the staging area; a relic that used to do more.
223 void mergestream::pend()
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();