aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/mpm/range.h
diff options
context:
space:
mode:
authorwkj <devnull@localhost>2004-05-16 07:56:41 +0000
committerwkj <devnull@localhost>2004-05-16 07:56:41 +0000
commit5f1cf8e6fb130fd48d6f016d13baf5408b3181f8 (patch)
tree7f77f458df8c8b34db139fb4551df602ab6286be /src/cmd/mpm/range.h
parentc5561c23cf394806cbf6d70a96f2dc0253f93745 (diff)
downloadplan9port-5f1cf8e6fb130fd48d6f016d13baf5408b3181f8.tar.gz
plan9port-5f1cf8e6fb130fd48d6f016d13baf5408b3181f8.tar.bz2
plan9port-5f1cf8e6fb130fd48d6f016d13baf5408b3181f8.zip
Checkpoint: pull in mpm; merge pic from Taj's version of the world
Diffstat (limited to 'src/cmd/mpm/range.h')
-rw-r--r--src/cmd/mpm/range.h334
1 files changed, 334 insertions, 0 deletions
diff --git a/src/cmd/mpm/range.h b/src/cmd/mpm/range.h
new file mode 100644
index 00000000..401035a5
--- /dev/null
+++ b/src/cmd/mpm/range.h
@@ -0,0 +1,334 @@
+const int NOGOAL = -1;
+
+class stream;
+
+enum primeflush { NO, YES, EXPECTED, UNEXPECTED }; // mergestream::prime()
+
+// Ranges do two things. They interpose a layer between slugs and the rest
+// of the program; this is important because of the grossness of the slug
+// data structure (made necessary by its origins in troff output). Ranges also
+// group together other ranges into meaningful chunks like unbreakable stream
+// objects, floatable objects, and page headers and footers.
+// Member function height() returns a range's height as of the latest composition.
+// Member function rawht() returns the range's original height in the input.
+class range {
+ protected:
+ slug *first; // earliest slug in range
+ int accumV; // accumulated V to this point
+ public:
+ range() { first = 0; accumV = 0; }
+ range(slug *p) { first = p; accumV = 0; }
+ char *headstr() {
+ return first ? first->headstr() : (char*)""; }
+ char *typename() { return first->typename(); }
+ int serialno() { return first->serialno(); }
+ int lineno() { return first->lineno(); }
+ virtual void dump() { first->dump(); }
+ virtual void rdump() { dump(); }
+ virtual int print(int cv, int col) {
+ first->slugout(col); return cv; }
+ virtual int floatable() { return 0; }
+ virtual int brkafter() { return 1; }
+ virtual int isnested() { return 0; }
+ virtual int issp() { return 0; }
+ virtual int isvbox() { return 0; }
+ virtual int isneed() { return 0; }
+ virtual int iscmd() { return 0; }
+ virtual int cmdtype() { return -1; }
+ virtual int isparm() { return 0; }
+ virtual int parmtype() { return -1; }
+ virtual int parm() { return -1; }
+ virtual int breakable() { return 0; }
+ virtual int forceflush() { return UNEXPECTED; }
+ virtual int pn() { return 0; }
+ virtual stream *children() { return 0; } // see page::peeloff()
+ virtual void killkids() { }
+ virtual void enqueue(int = 0);
+ virtual int height() { return 0; }
+ virtual int rawht() { return 0; }
+ virtual int needht() { return 0; }
+ virtual void reheight(int *, int *) { }
+ virtual void rerawht(int *, int *) { }
+ virtual void setheight(int) { }
+ virtual void restore() { } // goals of floatables
+ virtual int goal() { return NOGOAL; }
+ int accum() { return accumV; }
+ void setaccum(int n) { accumV = n; }
+ virtual void setgoal(int) { }
+ virtual void pickgoal(int, double) { }
+ virtual int numcol() { return first->numcol(); }
+ virtual int issentinel() { return 0; }
+ virtual range *clone() { return 0; }
+ virtual int breaking() { return 0; }
+ virtual void setbreaking() { }
+};
+
+class vboxrange : public range {
+ int dv; // inherited from slug
+ int base; // inherited from slug
+ int brk; // 0 => ok to break after, 1 => no break
+ public:
+ vboxrange(slug *p) : range(p) { dv = p->dv; base = p->base; brk = p->parm; }
+ void dump() {
+ printf("#### VBOX brk? %d dv %d ht %d\n", brk, dv, dv+base); }
+ int print(int cv, int col) {
+ printf("V%d\n", cv += dv); first->slugout(col); return cv+base; }
+ int brkafter() { return !brk; }
+ int isvbox() { return 1; }
+ int forceflush() { return NO; }
+ int height() { return dv + base; }
+ int rawht() { return first->dv + first->base; }
+ void reheight(int *cv, int *mv) {
+ *cv += dv+base; *mv = max(*mv, *cv); }
+ void rerawht(int *cv, int *mv) {
+ *cv += rawht(); *mv = max(*mv, *cv); }
+};
+
+class sprange : public range {
+ int dv;
+ public:
+ sprange(slug *p) : range(p) { dv = first->dv; }
+ void dump() {
+ printf("#### SP dv %d (originally %d)\n", dv, first->dv); }
+ int print(int cv, int col) {
+ first->slugout(col); return cv + dv; }
+ int issp() { return 1; }
+ int forceflush() { return YES; }
+ int height() { return dv; }
+ int rawht() { return first->dv; }
+ void reheight(int *, int *);
+ void rerawht(int *, int *);
+ void setheight(int n) { dv = n; }
+};
+
+class tmrange : public range {
+ public:
+ tmrange(slug *p) : range(p) { }
+ int forceflush() { return NO; }
+ int print(int cv, int col) { first->slugout(col); return cv; }
+};
+
+class coordrange : public range {
+ public:
+ coordrange(slug *p) : range(p) { }
+ int forceflush() { return NO; }
+ int print(int cv, int col)
+ { first->slugout(col); printf(" Y %d\n", cv); return cv; }
+};
+
+class nerange : public range {
+ public:
+ nerange(slug *p) : range(p) { }
+ int isneed() { return 1; }
+ int forceflush() { return YES; }
+ int needht() { return first->dv; }
+};
+
+class mcrange : public range {
+ public:
+ mcrange(slug *p) : range(p) { }
+ int forceflush() { return YES; }
+};
+
+class cmdrange : public range {
+ public:
+ cmdrange(slug *p) : range(p) { }
+ int iscmd() { return 1; }
+ int forceflush() { return YES; }
+ int cmdtype() { return first->parm; }
+};
+
+class parmrange : public range {
+ public:
+ parmrange(slug *p) : range(p) { }
+ int isparm() { return 1; }
+ int forceflush() { return YES; }
+ int parmtype() { return first->parm; }
+ int parm() { return first->parm2; }
+};
+
+class bsrange : public range {
+ public:
+ bsrange(slug *p) : range(p) { }
+ int forceflush() { return NO; }
+ int print(int cv, int col) { first->slugout(col); return cv; }
+};
+
+class endrange : public range {
+ public:
+ endrange(slug *p) : range(p) { }
+ int forceflush() { return UNEXPECTED; }
+};
+
+class eofrange : public range {
+ public:
+ eofrange(slug *p) : range(p) { }
+ int forceflush() { return UNEXPECTED; }
+};
+
+extern eofrange *lastrange; // the EOF block (trailer, etc.) goes here
+
+int measure(stream *);
+int rawmeasure(stream *);
+
+// A nestrange packages together a sequence of ranges, its subrange.
+// Other parts of the program reach in and alter the dimensions of
+// some of these ranges, so when the height of a range is requested
+// it is computed completely afresh.
+// (Note: the alternative, of keeping around many copies of ranges
+// with different dimensions, was abandoned because of the difficulty
+// of ensuring that exactly one copy of each original range would be
+// output.)
+class nestrange : public range {
+ protected:
+ stream *subrange;
+ int isbreaking;
+ int rawdv;
+ public:
+ nestrange() : range() { subrange = 0; isbreaking = 0; rawdv = -1; }
+ nestrange(slug *p, stream *s) : range(p)
+ { subrange = s; isbreaking = 0; rawdv = -1; }
+ void rdump();
+ virtual void restore();
+ stream *children() { return subrange; }
+ void killkids();
+ int height() { return measure(subrange); }
+ int rawht() { if (rawdv < 0 || isbreaking) rawdv = rawmeasure(subrange);
+ return rawdv; }
+ void reheight(int *cv, int *mv) {
+ *mv += measure(subrange); *cv = max(*mv, *cv); }
+ void rerawht(int *cv, int *mv) {
+ *mv += rawht(); *cv = max(*mv, *cv); }
+ int isnested() { return 1; }
+ int forceflush() { return EXPECTED; }
+ int print(int cv, int col);
+ int breaking() { return isbreaking; }
+ void setbreaking() { isbreaking++; }
+};
+
+class usrange : public nestrange {
+ public:
+ usrange() { }
+ usrange(slug *p, stream *s) : nestrange(p, s) {}
+ void dump() { printf("#### US dv %d\n", height()); }
+ range *clone();
+};
+
+class ufrange : public nestrange {
+ int goalV, goal2;
+ public:
+ ufrange() { }
+ ufrange(slug *p, stream *s) : nestrange(p, s) {
+ goalV = p->parm; goal2 = p->parm2; }
+ void dump() { printf("#### UF dv %d goal %d goal2 %d\n",
+ height(), goalV, goal2); }
+ int floatable() { return 1; }
+ void enqueue(int = 0);
+ range *clone();
+ int goal() { return goalV; }
+ void setgoal(int n) { goalV = goal2 = n; }
+ void pickgoal(int acv, double scale);
+ void restore() { goalV = first->parm; goal2 = first->ht; }
+};
+
+class bfrange : public nestrange {
+ int goalV, goal2;
+ public:
+ bfrange() { }
+ bfrange(slug *p, stream *s) : nestrange(p, s) {
+ goalV = p->parm; goal2 = p->parm2; }
+ void dump() { printf("#### BF dv %d goal %d goal2 %d\n",
+ height(), goalV, goal2); }
+ int floatable() { return 1; }
+ void enqueue(int = 0);
+ range *clone();
+ int goal() { return goalV; }
+ void setgoal(int n) { goalV = goal2 = n; }
+ void pickgoal(int acv, double scale);
+ void restore() { goalV = first->parm; goal2 = first->parm2; }
+ int breakable() { return 1; } // can be broken
+};
+
+class ptrange : public nestrange {
+ int pgno;
+ public:
+ int pn() { return pgno; }
+ ptrange(slug *p, stream *s) : nestrange(p, s) { pgno = p->parm; }
+ void dump() { printf("#### PT pgno %d dv %d\n", pgno, height()); }
+};
+
+class btrange : public nestrange {
+ int pgno;
+ public:
+ btrange(slug *p, stream *s) : nestrange(p, s) { pgno = p->parm; }
+ void dump() { printf("#### BT pgno %d dv %d\n", pgno, height()); }
+};
+
+// A stream is a sequence of ranges; we use this data structure a lot
+// to traverse various sequences that crop up in page-making.
+class stream {
+ protected:
+public:
+ struct strblk { // ranges are linked by these blocks
+ strblk *next;
+ range *rp;
+ };
+ strblk *first;
+ strblk *last;
+ strblk *curr;
+ public:
+ stream() { curr = last = first = 0; }
+ stream(range *r) { curr = last = first = new strblk;
+ last->rp = r; last->next = 0; }
+ void freeall(); // note: not a destructor
+ void dump(); // top level
+ void rdump(); // recursive
+ int restoreall();
+ range *current() { return curr->rp; }
+ range *next() { return curr && curr->next ? curr->next->rp : 0; }
+ void advance() { curr = curr->next; }
+ range *append(range *r);
+ void split();
+ int more() { return curr && curr->rp; }
+ int height();
+ int rawht();
+};
+
+// A generator iterates through all the ranges of a stream
+// (not just the root ranges of nestranges).
+class generator {
+ stream s;
+ generator *child;
+ public:
+ generator() { child = 0; }
+ generator(stream *sp) { s = *sp; child = 0; }
+ range *next();
+};
+
+extern stream ptlist, btlist; // page titles
+
+#define INFINITY 1000001
+
+// A queue is a distinguished kind of stream.
+// It keeps its contents in order by the serial numbers of the ranges.
+// A queue can be blocked from dequeuing something to indicate
+// that it's not worth considering the queue again on a given page.
+class queue : public stream {
+ strblk *newguy;
+ protected:
+ int blocked;
+ void check(char *);
+ public:
+ queue() : blocked(0) { }
+ range *enqueue(range *r);
+ range *dequeue();
+ void block() { blocked = 1; }
+ void unblock() { blocked = 0; }
+ int more() { return !blocked && stream::more(); }
+ int empty() { return !stream::more(); }
+ int serialno() { return empty() ? INFINITY : current()->serialno(); }
+};
+
+// functions in range.c
+void checkout();
+void startup(FILE *);