Blob


1 const int NOGOAL = -1;
3 class stream;
5 enum primeflush { NO, YES, EXPECTED, UNEXPECTED }; // mergestream::prime()
7 // Ranges do two things. They interpose a layer between slugs and the rest
8 // of the program; this is important because of the grossness of the slug
9 // data structure (made necessary by its origins in troff output). Ranges also
10 // group together other ranges into meaningful chunks like unbreakable stream
11 // objects, floatable objects, and page headers and footers.
12 // Member function height() returns a range's height as of the latest composition.
13 // Member function rawht() returns the range's original height in the input.
14 class range {
15 protected:
16 slug *first; // earliest slug in range
17 int accumV; // accumulated V to this point
18 public:
19 range() { first = 0; accumV = 0; }
20 range(slug *p) { first = p; accumV = 0; }
21 char *headstr() {
22 return first ? first->headstr() : (char*)""; }
23 char *typename() { return first->typename(); }
24 int serialno() { return first->serialno(); }
25 int lineno() { return first->lineno(); }
26 virtual void dump() { first->dump(); }
27 virtual void rdump() { dump(); }
28 virtual int print(int cv, int col) {
29 first->slugout(col); return cv; }
30 virtual int floatable() { return 0; }
31 virtual int brkafter() { return 1; }
32 virtual int isnested() { return 0; }
33 virtual int issp() { return 0; }
34 virtual int isvbox() { return 0; }
35 virtual int isneed() { return 0; }
36 virtual int iscmd() { return 0; }
37 virtual int cmdtype() { return -1; }
38 virtual int isparm() { return 0; }
39 virtual int parmtype() { return -1; }
40 virtual int parm() { return -1; }
41 virtual int breakable() { return 0; }
42 virtual int forceflush() { return UNEXPECTED; }
43 virtual int pn() { return 0; }
44 virtual stream *children() { return 0; } // see page::peeloff()
45 virtual void killkids() { }
46 virtual void enqueue(int = 0);
47 virtual int height() { return 0; }
48 virtual int rawht() { return 0; }
49 virtual int needht() { return 0; }
50 virtual void reheight(int *, int *) { }
51 virtual void rerawht(int *, int *) { }
52 virtual void setheight(int) { }
53 virtual void restore() { } // goals of floatables
54 virtual int goal() { return NOGOAL; }
55 int accum() { return accumV; }
56 void setaccum(int n) { accumV = n; }
57 virtual void setgoal(int) { }
58 virtual void pickgoal(int, double) { }
59 virtual int numcol() { return first->numcol(); }
60 virtual int issentinel() { return 0; }
61 virtual range *clone() { return 0; }
62 virtual int breaking() { return 0; }
63 virtual void setbreaking() { }
64 };
66 class vboxrange : public range {
67 int dv; // inherited from slug
68 int base; // inherited from slug
69 int brk; // 0 => ok to break after, 1 => no break
70 public:
71 vboxrange(slug *p) : range(p) { dv = p->dv; base = p->base; brk = p->parm; }
72 void dump() {
73 printf("#### VBOX brk? %d dv %d ht %d\n", brk, dv, dv+base); }
74 int print(int cv, int col) {
75 printf("V%d\n", cv += dv); first->slugout(col); return cv+base; }
76 int brkafter() { return !brk; }
77 int isvbox() { return 1; }
78 int forceflush() { return NO; }
79 int height() { return dv + base; }
80 int rawht() { return first->dv + first->base; }
81 void reheight(int *cv, int *mv) {
82 *cv += dv+base; *mv = max(*mv, *cv); }
83 void rerawht(int *cv, int *mv) {
84 *cv += rawht(); *mv = max(*mv, *cv); }
85 };
87 class sprange : public range {
88 int dv;
89 public:
90 sprange(slug *p) : range(p) { dv = first->dv; }
91 void dump() {
92 printf("#### SP dv %d (originally %d)\n", dv, first->dv); }
93 int print(int cv, int col) {
94 first->slugout(col); return cv + dv; }
95 int issp() { return 1; }
96 int forceflush() { return YES; }
97 int height() { return dv; }
98 int rawht() { return first->dv; }
99 void reheight(int *, int *);
100 void rerawht(int *, int *);
101 void setheight(int n) { dv = n; }
102 };
104 class tmrange : public range {
105 public:
106 tmrange(slug *p) : range(p) { }
107 int forceflush() { return NO; }
108 int print(int cv, int col) { first->slugout(col); return cv; }
109 };
111 class coordrange : public range {
112 public:
113 coordrange(slug *p) : range(p) { }
114 int forceflush() { return NO; }
115 int print(int cv, int col)
116 { first->slugout(col); printf(" Y %d\n", cv); return cv; }
117 };
119 class nerange : public range {
120 public:
121 nerange(slug *p) : range(p) { }
122 int isneed() { return 1; }
123 int forceflush() { return YES; }
124 int needht() { return first->dv; }
125 };
127 class mcrange : public range {
128 public:
129 mcrange(slug *p) : range(p) { }
130 int forceflush() { return YES; }
131 };
133 class cmdrange : public range {
134 public:
135 cmdrange(slug *p) : range(p) { }
136 int iscmd() { return 1; }
137 int forceflush() { return YES; }
138 int cmdtype() { return first->parm; }
139 };
141 class parmrange : public range {
142 public:
143 parmrange(slug *p) : range(p) { }
144 int isparm() { return 1; }
145 int forceflush() { return YES; }
146 int parmtype() { return first->parm; }
147 int parm() { return first->parm2; }
148 };
150 class bsrange : public range {
151 public:
152 bsrange(slug *p) : range(p) { }
153 int forceflush() { return NO; }
154 int print(int cv, int col) { first->slugout(col); return cv; }
155 };
157 class endrange : public range {
158 public:
159 endrange(slug *p) : range(p) { }
160 int forceflush() { return UNEXPECTED; }
161 };
163 class eofrange : public range {
164 public:
165 eofrange(slug *p) : range(p) { }
166 int forceflush() { return UNEXPECTED; }
167 };
169 extern eofrange *lastrange; // the EOF block (trailer, etc.) goes here
171 int measure(stream *);
172 int rawmeasure(stream *);
174 // A nestrange packages together a sequence of ranges, its subrange.
175 // Other parts of the program reach in and alter the dimensions of
176 // some of these ranges, so when the height of a range is requested
177 // it is computed completely afresh.
178 // (Note: the alternative, of keeping around many copies of ranges
179 // with different dimensions, was abandoned because of the difficulty
180 // of ensuring that exactly one copy of each original range would be
181 // output.)
182 class nestrange : public range {
183 protected:
184 stream *subrange;
185 int isbreaking;
186 int rawdv;
187 public:
188 nestrange() : range() { subrange = 0; isbreaking = 0; rawdv = -1; }
189 nestrange(slug *p, stream *s) : range(p)
190 { subrange = s; isbreaking = 0; rawdv = -1; }
191 void rdump();
192 virtual void restore();
193 stream *children() { return subrange; }
194 void killkids();
195 int height() { return measure(subrange); }
196 int rawht() { if (rawdv < 0 || isbreaking) rawdv = rawmeasure(subrange);
197 return rawdv; }
198 void reheight(int *cv, int *mv) {
199 *mv += measure(subrange); *cv = max(*mv, *cv); }
200 void rerawht(int *cv, int *mv) {
201 *mv += rawht(); *cv = max(*mv, *cv); }
202 int isnested() { return 1; }
203 int forceflush() { return EXPECTED; }
204 int print(int cv, int col);
205 int breaking() { return isbreaking; }
206 void setbreaking() { isbreaking++; }
207 };
209 class usrange : public nestrange {
210 public:
211 usrange() { }
212 usrange(slug *p, stream *s) : nestrange(p, s) {}
213 void dump() { printf("#### US dv %d\n", height()); }
214 range *clone();
215 };
217 class ufrange : public nestrange {
218 int goalV, goal2;
219 public:
220 ufrange() { }
221 ufrange(slug *p, stream *s) : nestrange(p, s) {
222 goalV = p->parm; goal2 = p->parm2; }
223 void dump() { printf("#### UF dv %d goal %d goal2 %d\n",
224 height(), goalV, goal2); }
225 int floatable() { return 1; }
226 void enqueue(int = 0);
227 range *clone();
228 int goal() { return goalV; }
229 void setgoal(int n) { goalV = goal2 = n; }
230 void pickgoal(int acv, double scale);
231 void restore() { goalV = first->parm; goal2 = first->ht; }
232 };
234 class bfrange : public nestrange {
235 int goalV, goal2;
236 public:
237 bfrange() { }
238 bfrange(slug *p, stream *s) : nestrange(p, s) {
239 goalV = p->parm; goal2 = p->parm2; }
240 void dump() { printf("#### BF dv %d goal %d goal2 %d\n",
241 height(), goalV, goal2); }
242 int floatable() { return 1; }
243 void enqueue(int = 0);
244 range *clone();
245 int goal() { return goalV; }
246 void setgoal(int n) { goalV = goal2 = n; }
247 void pickgoal(int acv, double scale);
248 void restore() { goalV = first->parm; goal2 = first->parm2; }
249 int breakable() { return 1; } // can be broken
250 };
252 class ptrange : public nestrange {
253 int pgno;
254 public:
255 int pn() { return pgno; }
256 ptrange(slug *p, stream *s) : nestrange(p, s) { pgno = p->parm; }
257 void dump() { printf("#### PT pgno %d dv %d\n", pgno, height()); }
258 };
260 class btrange : public nestrange {
261 int pgno;
262 public:
263 btrange(slug *p, stream *s) : nestrange(p, s) { pgno = p->parm; }
264 void dump() { printf("#### BT pgno %d dv %d\n", pgno, height()); }
265 };
267 // A stream is a sequence of ranges; we use this data structure a lot
268 // to traverse various sequences that crop up in page-making.
269 class stream {
270 protected:
271 public:
272 struct strblk { // ranges are linked by these blocks
273 strblk *next;
274 range *rp;
275 };
276 strblk *first;
277 strblk *last;
278 strblk *curr;
279 public:
280 stream() { curr = last = first = 0; }
281 stream(range *r) { curr = last = first = new strblk;
282 last->rp = r; last->next = 0; }
283 void freeall(); // note: not a destructor
284 void dump(); // top level
285 void rdump(); // recursive
286 int restoreall();
287 range *current() { return curr->rp; }
288 range *next() { return curr && curr->next ? curr->next->rp : 0; }
289 void advance() { curr = curr->next; }
290 range *append(range *r);
291 void split();
292 int more() { return curr && curr->rp; }
293 int height();
294 int rawht();
295 };
297 // A generator iterates through all the ranges of a stream
298 // (not just the root ranges of nestranges).
299 class generator {
300 stream s;
301 generator *child;
302 public:
303 generator() { child = 0; }
304 generator(stream *sp) { s = *sp; child = 0; }
305 range *next();
306 };
308 extern stream ptlist, btlist; // page titles
310 #define INFINITY 1000001
312 // A queue is a distinguished kind of stream.
313 // It keeps its contents in order by the serial numbers of the ranges.
314 // A queue can be blocked from dequeuing something to indicate
315 // that it's not worth considering the queue again on a given page.
316 class queue : public stream {
317 strblk *newguy;
318 protected:
319 int blocked;
320 void check(char *);
321 public:
322 queue() : blocked(0) { }
323 range *enqueue(range *r);
324 range *dequeue();
325 void block() { blocked = 1; }
326 void unblock() { blocked = 0; }
327 int more() { return !blocked && stream::more(); }
328 int empty() { return !stream::more(); }
329 int serialno() { return empty() ? INFINITY : current()->serialno(); }
330 };
332 // functions in range.c
333 void checkout();
334 void startup(FILE *);