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