range.h (10274B)
1 const int NOGOAL = -1; 2 3 class stream; 4 5 enum primeflush { NO, YES, EXPECTED, UNEXPECTED }; // mergestream::prime() 6 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 }; 66 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 }; 87 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 }; 104 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 }; 111 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 }; 119 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 }; 127 128 class mcrange : public range { 129 public: 130 mcrange(slug *p) : range(p) { } 131 int forceflush() { return YES; } 132 }; 133 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 }; 141 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 }; 150 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 }; 157 158 class endrange : public range { 159 public: 160 endrange(slug *p) : range(p) { } 161 int forceflush() { return UNEXPECTED; } 162 }; 163 164 class eofrange : public range { 165 public: 166 eofrange(slug *p) : range(p) { } 167 int forceflush() { return UNEXPECTED; } 168 }; 169 170 extern eofrange *lastrange; // the EOF block (trailer, etc.) goes here 171 172 int measure(stream *); 173 int rawmeasure(stream *); 174 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 }; 209 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 }; 217 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 }; 234 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 }; 252 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 }; 260 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 }; 267 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 }; 297 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 }; 308 309 extern stream ptlist, btlist; // page titles 310 311 #undef INFINITY 312 #define INFINITY 1000001 313 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 }; 333 334 // functions in range.c 335 void checkout(); 336 void startup(FILE *);