6 void sprange::reheight(int *cv, int *mv)
9 ERROR "slug %d: an imbedded SP, line %d\n",
10 first->serialno(), first->lineno() WARNING;
15 void sprange::rerawht(int *cv, int *mv)
21 void nestrange::restore()
23 subrange->restoreall();
26 void stream::freeall() // not a destructor; called explicitly
29 for (p = first; p; p = q) {
33 first = last = curr = 0;
38 for (stream s = *this; s.more(); s.advance())
44 for (stream s = *this; s.more(); s.advance())
48 int stream::restoreall()
50 for (stream s = *this; s.more(); s.advance())
51 s.current()->restore();
55 range *stream::append(range *r)
58 curr = first = last = new strblk;
60 last->next = new strblk;
69 void stream::split() // duplicate current() range
71 strblk *s2 = new strblk;
72 range *r2 = curr->rp->clone();
74 s2->next = curr->next;
78 curr->rp->killkids(); // children only in the 2nd one
86 for (h = 0; s.more(); s.advance())
87 h += s.current()->height();
95 for (h = 0; s.more(); s.advance())
96 h += s.current()->rawht();
100 int measure(stream *sp) // record high-water mark of stream
101 { // sets nested stream heights
104 for (maxv = curv = 0; s.more(); s.advance())
105 s.current()->reheight(&curv, &maxv);
109 int rawmeasure(stream *sp)
113 for (maxv = curv = 0; s.more(); s.advance())
114 s.current()->rerawht(&curv, &maxv);
118 void nestrange::rdump()
125 void nestrange::killkids()
127 subrange = new stream;
130 int nestrange::print(int curv, int col)
134 for (stream s = *subrange; s.more(); s.advance())
135 curv = s.current()->print(curv, col);
136 return ocurv + height();
139 #define macroclone(rangetype) range *rangetype::clone() {\
140 rangetype *t = new rangetype;\
150 #define macropickgoal(rangetype) void rangetype::pickgoal(int acv, double scale) {\
152 goalV = (int)(scale*goalV);\
153 goal2 = (int)(scale*goal2);\
155 if (abs(acv - goalV) > abs(acv-goal2))\
158 macropickgoal(ufrange)
159 macropickgoal(bfrange)
163 range *generator::next()
167 if ((r = child->next()) != 0)
176 child = new generator(r->children());
181 range *queue::enqueue(range *r)
184 printf("#entering queue::enqueue()\n");
185 check("queue::enqueue");
186 if (!last || last->rp->serialno() < r->serialno()) // common case
189 printf("#queue::enqueue() pushing back\n");
192 if (r->serialno() < first->rp->serialno()) {
193 newguy->next = first;
194 curr = first = newguy;
198 printf("#queue::enqueue() searching down queue\n");
200 next() && next()->serialno() < r->serialno();
203 newguy->next = curr->next;
205 curr = first; // restore important queue condition
209 range *queue::dequeue()
212 printf("#entering queue::dequeue()\n");
213 check("queue::dequeue");
215 range *retval = first->rp;
223 // ================================================================================
225 // functions that munge the troff output stored in slugs[]
227 // ================================================================================
229 static void doprefix(FILE *fp) // copy 1st "x" commands to output
233 while ((c = getc(fp)) != EOF) {
240 putchar(c = getc(fp));
244 // printf("x font 1 R\n"); // horrible kludge: ensure a font for first f1 command
247 #define DELTASLUGS 15000
249 static slug *slugs = 0;
250 static int nslugs = 0; // slugs has nslugs slots
251 static slug *slugp = 0; // next free slug in slugs
253 static void readslugs(FILE *fp)
255 if ((slugs = (slug *) malloc((nslugs = DELTASLUGS)*sizeof(slug))) == NULL)
256 ERROR "no room for %d-slug array\n", nslugs FATAL;
258 for (slugp = slugs; ; slugp++) {
259 if (slugp >= slugs+nslugs-2) {
260 int where = slugp - slugs;
261 if ((slugs = (slug *) realloc((char *) slugs, (nslugs += DELTASLUGS)*sizeof(slug))) == NULL)
262 ERROR "no room for %d slugs\n", nslugs FATAL;
263 ERROR "now slug array can hold %d slugs\n", nslugs WARNING;
264 slugp = slugs + where;
266 *slugp = getslug(fp);
267 if (slugp->type == EOF)
270 *++slugp = eofslug();
271 printf("# %d slugs\n", slugp-slugs);
274 static slug *findend(slug *sp)
277 for (p = sp; p->type == sp->type; p++) // skip runs
279 for ( ; p < slugp; p++)
291 ERROR "walked past EOF in findend looking for %d (%s), line %d\n",
292 sp->type, sp->typename(), sp->lineno() FATAL;
296 static int markp(int i, int n, int parm)
297 { // should VBOX i of n be marked to brevent breaking after it?
300 return i <= parm-2 || i >= n-parm;
303 static void markbreak(slug *p)
305 // Mark impermissible breakpoints in BS's.
306 // The parm field of a VBOX is >0 if we shouldn't break after it.
307 int parm = 0; // how many lines must stay on page
308 int goahead = 1; // true until we see the next BS
309 int nowmark = 0; // true when we should be marking
311 while (p->type == BS)
312 parm = p++->parm; // latest BS parm applies
316 case VBOX: // count VBOXes so second pass knows
317 if (p->dv > 0) // knows how far to end of BS
320 case US: // mark around EQ/EN, etc.
324 case UF: // but not around floats, PTs, and BTs
330 case SP: // naked SP: probable macro botch
331 nowmark = 1; // mark around it anyhow
333 case BS: // beginning of next paragraph
334 case END: // probable macro botch
336 goahead = 0; // stop work after marking
343 int i = 0; // VBOX counter for second pass
348 op->parm = markp(i, n, parm);
351 case US: // caused second pass to begin
358 case UF: // skip on this pass too
370 ERROR "markbreak failed : i %d n %d\n",
378 static void fixslugs() // adjust bases and dv's, set parameters, etc.
381 for (p = slugs; p < slugp; p++) {
382 if (p->type == VBOX) {
387 ERROR "%s slug (type %d) has base = %d, line %d\n",
388 p->typename(), p->type, p->base, p->lineno() WARNING;
390 if ((p->type == SP) || (p->type == NE))
396 prevV->base = max(prevV->base, p->dv);
399 ERROR "%s slug (type %d) has dv = %d, line %d\n",
400 p->typename(), p->type, p->dv, p->lineno() WARNING;
404 int firstNP = 0, firstFO = 0, firstPL = 0;
405 for (p = slugs; p < slugp; p++) {
407 // adjust the dv in a sequence of VBOXes
408 // by subtracting from each the base of the preceding VBOX
411 p->dv -= prevV->base;
415 p->dv = max(p->dv, 0);
421 // record only first "declarations" of Page Top and bottom (FO);
441 // things that begin groups; not US, which should nest properly
444 while ((p+1)->type == p->type) {
445 // join adjacent identical
446 (p+1)->parm2 = p->parm; // parm is latest
448 p->neutralize(); // so it's not seen later
466 ERROR "Unknown slug type %d in fixslugs, line %d\n",
467 p->type, p->lineno() WARNING;
471 int pagesize = pagebot - pagetop;
473 ERROR "Page dimensions not declared\n" FATAL;
475 physbot = pagebot + pagetop;
476 printf("# page top %d bot %d size %d physbot %d\n",
477 pagetop, pagebot, pagesize, physbot);
478 for (p = slugs; p < slugp; p++) {
480 // normalize float parameters
484 p->parm = max(min(p->parm-pagetop, pagesize), 0);
486 p->parm2 = max(min(p->parm2-pagetop, pagesize), 0);
488 // normalize need parameters
490 p->dv = max( min(p->dv, pagesize), 0);
492 // mark permissible breaks
504 for (slug *p = slugs; p < slugp; p++)
513 ERROR "%s slug %d seen %d times\n",
514 p->typename(), p->serialno(),
521 stream ptlist, btlist;
523 static slug *makeranges(slug *p, stream *s, int level)
527 for ( ; p < slugp; p++)
530 s->append(new vboxrange(p));
533 s->append(new sprange(p));
536 s->append(new bsrange(p));
539 s->append(new usrange(p, t = new stream));
540 p = makeranges(p+1, t, level+1);
543 s->append(new bfrange(p, t = new stream));
544 p = makeranges(p+1, t, level+1);
547 s->append(new ufrange(p, t = new stream));
548 p = makeranges(p+1, t, level+1);
551 ptlist.append(new ptrange(p, t = new stream));
552 p = makeranges(p+1, t, level+1);
555 btlist.append(new btrange(p, t = new stream));
556 p = makeranges(p+1, t, level+1);
559 s->append(new endrange(p));
562 s->append(new tmrange(p));
565 s->append(new coordrange(p));
569 ERROR "Nested NE commands are ignored, line %d\n",
573 s->append(new nerange(p));
576 s->append(new mcrange(p));
580 ERROR "Nested command ignored, line %d\n",
582 s->append(new cmdrange(p));
586 ERROR "Nested parameter ignored, line %d\n",
588 s->append(new parmrange(p));
591 lastrange = new eofrange(p);
597 static queue text; // unexamined input ranges; the real data
599 void startup(FILE *fp)
601 doprefix(fp); // peel off 'x' commands
602 readslugs(fp); // read everything into slugs[]
603 fixslugs(); // measure parameters and clean up
604 makeranges(slugs, &text, 0); // add range superstructure
605 measure(&text); // heights of nested things
607 while (text.more()) {
608 range *r = text.dequeue();