tok: wrap equations in .eqnbeg and .eqnend strings
[neateqn.git] / box.c
blob03b723a56f47549303298ce54a05bce68f8c3415
1 #include <stdarg.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "eqn.h"
7 struct box *box_alloc(int szreg, int pre, int style)
9 struct box *box = malloc(sizeof(*box));
10 memset(box, 0, sizeof(*box));
11 sbuf_init(&box->raw);
12 box->szreg = szreg;
13 box->atoms = 0;
14 box->style = style;
15 if (pre)
16 box->tcur = pre;
17 return box;
20 void box_free(struct box *box)
22 if (box->reg)
23 sregrm(box->reg);
24 if (box->szown)
25 nregrm(box->szreg);
26 sbuf_done(&box->raw);
27 free(box);
30 static void box_put(struct box *box, char *s)
32 sbuf_append(&box->raw, s);
33 if (box->reg)
34 printf(".as %s \"%s\n", sregname(box->reg), s);
37 void box_putf(struct box *box, char *s, ...)
39 char buf[LNLEN];
40 va_list ap;
41 va_start(ap, s);
42 vsprintf(buf, s, ap);
43 va_end(ap);
44 box_put(box, buf);
47 char *box_buf(struct box *box)
49 return sbuf_buf(&box->raw);
52 /* change box's point size; return the number register storing it */
53 int box_size(struct box *box, char *val)
55 int szreg = box->szreg;
56 if (!val || !*val)
57 return szreg;
58 if (!box->szown) {
59 box->szown = 1;
60 box->szreg = nregmk();
62 if (val[0] == '-' || val[0] == '+')
63 printf(".nr %s %s%s\n", nregname(box->szreg), nreg(szreg), val);
64 else
65 printf(".nr %s %s\n", nregname(box->szreg), val);
66 return box->szreg;
69 void box_move(struct box *box, int dy, int dx)
71 if (dy)
72 box_putf(box, "\\v'%du*%sp/100u'", dy, nreg(box->szreg));
73 if (dx)
74 box_putf(box, "\\h'%du*%sp/100u'", dx, nreg(box->szreg));
77 /* T_ORD, T_BIGOP, T_BINOP, T_RELOP, T_LEFT, T_RIGHT, T_PUNC, T_INNER */
78 static int spacing[][8] = {
79 {0, 1, 2, 3, 0, 0, 0, 1},
80 {1, 1, 0, 3, 0, 0, 0, 1},
81 {2, 2, 0, 0, 2, 0, 0, 2},
82 {3, 3, 0, 0, 3, 0, 0, 3},
83 {0, 0, 0, 0, 0, 0, 0, 0},
84 {0, 1, 2, 3, 0, 0, 0, 1},
85 {1, 1, 0, 1, 1, 1, 1, 1},
86 {1, 1, 2, 3, 1, 0, 1, 1},
89 /* return the amount of automatic spacing before adding the given token */
90 static int eqn_gaps(struct box *box, int cur)
92 int s = 0;
93 int a1 = T_ATOM(box->tcur); /* previous atom */
94 int a2 = T_ATOM(cur); /* current atom */
95 if (!TS_SZ(box->style) && a1 && a2)
96 s = spacing[T_ATOMIDX(a1)][T_ATOMIDX(a2)];
97 if (s == 3)
98 return S_S3;
99 if (s == 2)
100 return S_S2;
101 return s ? S_S1 : 0;
104 /* the extra cost of line break between atoms a1 and a2 */
105 static int def_cost(int a1, int a2)
107 if (a1 == T_RELOP)
108 return 100;
109 if (a1 == T_BINOP)
110 return 200;
111 if (a1 == T_PUNC)
112 return 1000;
113 return 10000;
116 /* call just before inserting a non-italic character */
117 static void box_italiccorrection(struct box *box)
119 if (box->atoms && (box->tcur & T_ITALIC))
120 box_put(box, "\\/");
121 box->tcur &= ~T_ITALIC;
124 static int box_fixatom(int cur, int pre)
126 if (cur == T_BINOP && (!pre || pre == T_RELOP || pre == T_BIGOP ||
127 pre == T_LEFT || pre == T_PUNC))
128 return T_ORD;
129 if (cur == T_RELOP && (!pre || pre == T_LEFT))
130 return T_ORD;
131 return cur;
134 /* call before inserting a token with box_put() and box_putf() */
135 static void box_beforeput(struct box *box, int type, int breakable)
137 int autogaps; /* automatically inserted space before this token */
138 if (box->atoms) {
139 autogaps = eqn_gaps(box, T_ATOM(type));
140 if (!(type & T_ITALIC))
141 box_italiccorrection(box);
142 if (autogaps && type != T_GAP && box->tcur != T_GAP) {
143 box_italiccorrection(box);
144 if (breakable) { /* enlarge a space to match autogaps */
145 box_putf(box, "\\s[\\En(.s*%du*%sp/100u/\\w' 'u]\\j'%d' \\s0",
146 autogaps, nreg(box->szreg),
147 def_cost(T_ATOM(box->tcur), T_ATOM(type)));
148 } else {
149 box_putf(box, "\\h'%du*%sp/100u'",
150 autogaps, nreg(box->szreg));
154 if (box->tomark) {
155 printf(".nr %s 0\\w'%s'\n", box->tomark, box_toreg(box));
156 box->tomark = NULL;
160 /* call after inserting a token with box_put() and box_putf() */
161 static void box_afterput(struct box *box, int type)
163 box->atoms++;
164 box->tcur = T_FONT(type) | box_fixatom(T_TOK(type), T_TOK(box->tcur));
165 if (!box->tbeg)
166 box->tbeg = box->tcur;
169 /* insert s with the given type */
170 void box_puttext(struct box *box, int type, char *s, ...)
172 char buf[LNLEN];
173 va_list ap;
174 va_start(ap, s);
175 vsprintf(buf, s, ap);
176 va_end(ap);
177 box_beforeput(box, type, 0);
178 if (!(box->tcur & T_ITALIC) && (type & T_ITALIC))
179 box_put(box, "\\,");
180 box_put(box, buf);
181 box_afterput(box, type);
184 /* append sub to box */
185 void box_merge(struct box *box, struct box *sub, int breakable)
187 if (box_empty(sub))
188 return;
189 box_beforeput(box, sub->tbeg, breakable);
190 box_toreg(box);
191 box_put(box, box_toreg(sub));
192 if (!box->tbeg)
193 box->tbeg = sub->tbeg;
194 /* fix atom type only if merging a single atom */
195 if (sub->atoms == 1) {
196 box_afterput(box, sub->tcur);
197 } else {
198 box->tcur = sub->tcur;
199 box->atoms += sub->atoms;
203 /* put the maximum of number registers a and b into register dst */
204 static void roff_max(int dst, int a, int b)
206 printf(".ie %s>=%s .nr %s 0+%s\n",
207 nreg(a), nreg(b), nregname(dst), nreg(a));
208 printf(".el .nr %s 0+%s\n", nregname(dst), nreg(b));
211 /* return the width, height and depth of a string */
212 static void tok_dim(char *s, int wd, int ht, int dp)
214 printf(".nr %s 0\\w'%s'\n", nregname(wd), s);
215 if (ht)
216 printf(".nr %s 0-\\n[bbury]\n", nregname(ht));
217 if (dp)
218 printf(".nr %s 0\\n[bblly]\n", nregname(dp));
221 static int box_suprise(struct box *box)
223 if (TS_0(box->style))
224 return e_sup3;
225 return box->style == TS_D ? e_sup1 : e_sup2;
228 void box_sub(struct box *box, struct box *sub, struct box *sup)
230 int box_wd = nregmk();
231 int box_wdnoic = nregmk();
232 int box_dp = nregmk();
233 int box_ht = nregmk();
234 int sub_wd = nregmk();
235 int sup_wd = nregmk();
236 int all_wd = nregmk();
237 int sup_dp = nregmk();
238 int sub_ht = nregmk();
239 int sup_rise = nregmk();
240 int sub_fall = nregmk();
241 int tmp_18e = nregmk();
242 int sub_cor = nregmk();
243 if (sub)
244 box_italiccorrection(sub);
245 if (sup)
246 box_italiccorrection(sup);
247 if (sub)
248 tok_dim(box_toreg(box), box_wdnoic, 0, 0);
249 box_italiccorrection(box);
250 printf(".ps %s\n", nreg(box->szreg));
251 tok_dim(box_toreg(box), box_wd, box_ht, box_dp);
252 box_putf(box, "\\h'5m/100u'");
253 if (sup) {
254 tok_dim(box_toreg(sup), sup_wd, 0, sup_dp);
255 /* 18a */
256 printf(".nr %s 0%su-(%dm/100u)\n",
257 nregname(sup_rise), nreg(box_ht), e_supdrop);
258 /* 18c */
259 printf(".if %s<(%dm/100u) .nr %s (%dm/100u)\n",
260 nreg(sup_rise), box_suprise(box),
261 nregname(sup_rise), box_suprise(box));
262 printf(".if %s<(%s+(%dm/100u/4)) .nr %s 0%s+(%dm/100u/4)\n",
263 nreg(sup_rise), nreg(sup_dp), e_xheight,
264 nregname(sup_rise), nreg(sup_dp), e_xheight);
266 if (sub) {
267 tok_dim(box_toreg(sub), sub_wd, sub_ht, 0);
268 /* 18a */
269 printf(".nr %s 0%su+(%dm/100u)\n",
270 nregname(sub_fall), nreg(box_dp), e_subdrop);
272 if (sub && !sup) {
273 /* 18b */
274 printf(".if %s<(%dm/100u) .nr %s (%dm/100u)\n",
275 nreg(sub_fall), e_sub1,
276 nregname(sub_fall), e_sub1);
277 printf(".if %s<(%s-(%dm/100u*4/5)) .nr %s 0%s-(%dm/100u*4/5)\n",
278 nreg(sub_fall), nreg(sub_ht), e_xheight,
279 nregname(sub_fall), nreg(sub_ht), e_xheight);
281 if (sub && sup) {
282 /* 18d */
283 printf(".if %s<(%dm/100u) .nr %s (%dm/100u)\n",
284 nreg(sub_fall), e_sub2,
285 nregname(sub_fall), e_sub2);
286 /* 18e */
287 printf(".if (%s-%s)-(%s-%s)<(%dm/100u*4) \\{\\\n",
288 nreg(sup_rise), nreg(sup_dp),
289 nreg(sub_ht), nreg(sub_fall), e_rulethickness);
290 printf(".nr %s (%dm/100u*4)+%s-(%s-%s)\n",
291 nregname(sub_fall), e_rulethickness,
292 nreg(sub_ht), nreg(sup_rise), nreg(sup_dp));
293 printf(".nr %s (%dm/100u*4/5)-(%s-%s)\n",
294 nregname(tmp_18e), e_xheight,
295 nreg(sup_rise), nreg(sup_dp));
296 printf(".if %s>0 .nr %s +%s\n",
297 nreg(tmp_18e), nregname(sup_rise), nreg(tmp_18e));
298 printf(".if %s>0 .nr %s -%s \\}\n",
299 nreg(tmp_18e), nregname(sub_fall), nreg(tmp_18e));
301 /* writing the superscript */
302 if (sup) {
303 box_putf(box, "\\v'-%su'%s\\v'%su'",
304 nreg(sup_rise), box_toreg(sup), nreg(sup_rise));
305 if (sub)
306 box_putf(box, "\\h'-%su'", nreg(sup_wd));
308 /* writing the subscript */
309 if (sub) {
310 /* subscript correction */
311 printf(".nr %s (%s+%s)*(%s-%s)/%s\n", nregname(sub_cor),
312 nreg(box_ht), nreg(sub_fall),
313 nreg(box_wd), nreg(box_wdnoic), nreg(box_ht));
314 printf(".nr %s -%s\n", nregname(sub_wd), nreg(sub_cor));
315 box_putf(box, "\\h'-%su'", nreg(sub_cor));
316 box_putf(box, "\\v'%su'%s\\v'-%su'",
317 nreg(sub_fall), box_toreg(sub), nreg(sub_fall));
318 if (sup) {
319 box_putf(box, "\\h'-%su'", nreg(sub_wd));
320 roff_max(all_wd, sub_wd, sup_wd);
321 box_putf(box, "\\h'+%su'", nreg(all_wd));
324 box_putf(box, "\\h'%dm/100u'", e_scriptspace);
325 nregrm(box_wd);
326 nregrm(box_wdnoic);
327 nregrm(box_dp);
328 nregrm(box_ht);
329 nregrm(sub_wd);
330 nregrm(sup_wd);
331 nregrm(all_wd);
332 nregrm(sup_dp);
333 nregrm(sub_ht);
334 nregrm(sup_rise);
335 nregrm(sub_fall);
336 nregrm(tmp_18e);
337 nregrm(sub_cor);
340 void box_from(struct box *box, struct box *lim, struct box *llim, struct box *ulim)
342 int lim_wd = nregmk(); /* box's width */
343 int lim_ht = nregmk(); /* box's height */
344 int lim_dp = nregmk(); /* box's depth */
345 int llim_wd = nregmk(); /* llim's width */
346 int ulim_wd = nregmk(); /* ulim's width */
347 int ulim_dp = nregmk(); /* ulim's depth */
348 int llim_ht = nregmk(); /* llim's height */
349 int ulim_rise = nregmk(); /* the position of ulim */
350 int llim_fall = nregmk(); /* the position of llim */
351 int all_wd = nregmk(); /* the width of all */
352 box_italiccorrection(lim);
353 box_beforeput(box, T_BIGOP, 0);
354 tok_dim(box_toreg(lim), lim_wd, lim_ht, lim_dp);
355 printf(".ps %s\n", nreg(box->szreg));
356 if (ulim)
357 tok_dim(box_toreg(ulim), ulim_wd, 0, ulim_dp);
358 if (llim)
359 tok_dim(box_toreg(llim), llim_wd, llim_ht, 0);
360 if (ulim && llim)
361 roff_max(all_wd, llim_wd, ulim_wd);
362 else
363 printf(".nr %s %s\n", nregname(all_wd),
364 ulim ? nreg(ulim_wd) : nreg(llim_wd));
365 printf(".if %s>%s .nr %s 0%s\n",
366 nreg(lim_wd), nreg(all_wd),
367 nregname(all_wd), nreg(lim_wd));
368 box_putf(box, "\\h'%su-%su/2u'", nreg(all_wd), nreg(lim_wd));
369 box_merge(box, lim, 0);
370 box_putf(box, "\\h'-%su/2u'", nreg(lim_wd));
371 if (ulim) {
372 /* 13a */
373 printf(".nr %s (%dm/100u)-%s\n",
374 nregname(ulim_rise), e_bigopspacing3, nreg(ulim_dp));
375 printf(".if %s<(%dm/100u) .nr %s (%dm/100u)\n",
376 nreg(ulim_rise), e_bigopspacing1,
377 nregname(ulim_rise), e_bigopspacing1);
378 printf(".nr %s +%s+%s\n",
379 nregname(ulim_rise), nreg(lim_ht), nreg(ulim_dp));
380 box_putf(box, "\\h'-%su/2u'\\v'-%su'%s\\v'%su'\\h'-%su/2u'",
381 nreg(ulim_wd), nreg(ulim_rise), box_toreg(ulim),
382 nreg(ulim_rise), nreg(ulim_wd));
384 if (llim) {
385 /* 13a */
386 printf(".nr %s (%dm/100u)-%s\n",
387 nregname(llim_fall), e_bigopspacing4, nreg(llim_ht));
388 printf(".if %s<(%dm/100u) .nr %s (%dm/100u)\n",
389 nreg(llim_fall), e_bigopspacing2,
390 nregname(llim_fall), e_bigopspacing2);
391 printf(".nr %s +%s+%s\n",
392 nregname(llim_fall), nreg(lim_dp), nreg(llim_ht));
393 box_putf(box, "\\h'-%su/2u'\\v'%su'%s\\v'-%su'\\h'-%su/2u'",
394 nreg(llim_wd), nreg(llim_fall), box_toreg(llim),
395 nreg(llim_fall), nreg(llim_wd));
397 box_putf(box, "\\h'%su/2u'", nreg(all_wd));
398 box_afterput(box, T_BIGOP);
399 nregrm(lim_wd);
400 nregrm(lim_ht);
401 nregrm(lim_dp);
402 nregrm(llim_wd);
403 nregrm(ulim_wd);
404 nregrm(ulim_dp);
405 nregrm(llim_ht);
406 nregrm(ulim_rise);
407 nregrm(llim_fall);
408 nregrm(all_wd);
411 /* return the width of s; len is the height plus depth */
412 static void tok_len(char *s, int wd, int len, int ht, int dp)
414 printf(".nr %s 0\\w'%s'\n", nregname(wd), s);
415 if (len)
416 printf(".nr %s 0\\n[bblly]-\\n[bbury]-2\n", nregname(len));
417 if (dp)
418 printf(".nr %s 0\\n[bblly]-1\n", nregname(dp));
419 if (ht)
420 printf(".nr %s 0-\\n[bbury]-1\n", nregname(ht));
423 /* len[0]: width, len[1]: vertical length, len[2]: height, len[3]: depth */
424 static void blen_mk(char *s, int len[4])
426 int i;
427 for (i = 0; i < 4; i++)
428 len[i] = nregmk();
429 tok_len(s, len[0], len[1], len[2], len[3]);
432 /* free the registers allocated with blen_mk() */
433 static void blen_rm(int len[4])
435 int i;
436 for (i = 0; i < 4; i++)
437 nregrm(len[i]);
440 /* build a fraction; the correct font should be set up beforehand */
441 void box_over(struct box *box, struct box *num, struct box *den)
443 int num_wd = nregmk();
444 int num_dp = nregmk();
445 int den_wd = nregmk();
446 int den_ht = nregmk();
447 int all_wd = nregmk();
448 int num_rise = nregmk();
449 int den_fall = nregmk();
450 int bar_wd = nregmk();
451 int bar_dp = nregmk();
452 int bar_ht = nregmk();
453 int bar_fall = nregmk();
454 int tmp_15d = nregmk();
455 int bargap = (TS_DX(box->style) ? 7 : 3) * e_rulethickness / 2;
456 box_beforeput(box, T_INNER, 0);
457 box_italiccorrection(num);
458 box_italiccorrection(den);
459 tok_dim(box_toreg(num), num_wd, 0, num_dp);
460 tok_dim(box_toreg(den), den_wd, den_ht, 0);
461 roff_max(all_wd, num_wd, den_wd);
462 printf(".ps %s\n", nreg(box->szreg));
463 tok_len("\\(ru", bar_wd, 0, bar_ht, bar_dp);
464 /* 15b */
465 printf(".nr %s 0%dm/100u\n",
466 nregname(num_rise), TS_DX(box->style) ? e_num1 : e_num2);
467 printf(".nr %s 0%dm/100u\n",
468 nregname(den_fall), TS_DX(box->style) ? e_denom1 : e_denom2);
469 /* 15d */
470 printf(".nr %s (%s-%s)-((%dm/100u)+(%dm/100u/2))\n",
471 nregname(tmp_15d), nreg(num_rise), nreg(num_dp),
472 e_axisheight, e_rulethickness);
473 printf(".if %s<(%dm/100u) .nr %s +(%dm/100u)-%s\n",
474 nreg(tmp_15d), bargap, nregname(num_rise),
475 bargap, nreg(tmp_15d));
476 printf(".nr %s ((%dm/100u)-(%dm/100u/2))-(%s-%s)\n",
477 nregname(tmp_15d), e_axisheight, e_rulethickness,
478 nreg(den_ht), nreg(den_fall));
479 printf(".if %s<(%dm/100u) .nr %s +(%dm/100u)-%s\n",
480 nreg(tmp_15d), bargap, nregname(den_fall),
481 bargap, nreg(tmp_15d));
482 /* calculating the vertical position of the bar */
483 printf(".nr %s 0-%s+%s/2-(%dm/100u)\n",
484 nregname(bar_fall), nreg(bar_dp),
485 nreg(bar_ht), e_axisheight);
486 /* making the bar longer */
487 printf(".nr %s +2*(%dm/100u)\n",
488 nregname(all_wd), e_overhang);
489 /* null delimiter space */
490 box_putf(box, "\\h'%sp*%du/100u'",nreg(box->szreg), e_nulldelim);
491 /* drawing the bar */
492 box_putf(box, "\\v'%su'\\f[\\n(.f]\\s[%s]\\l'%su'\\v'-%su'\\h'-%su/2u'",
493 nreg(bar_fall), nreg(box->szreg), nreg(all_wd),
494 nreg(bar_fall), nreg(all_wd));
495 /* output the numerator */
496 box_putf(box, "\\h'-%su/2u'", nreg(num_wd));
497 box_putf(box, "\\v'-%su'%s\\v'%su'",
498 nreg(num_rise), box_toreg(num), nreg(num_rise));
499 box_putf(box, "\\h'-%su/2u'", nreg(num_wd));
500 /* output the denominator */
501 box_putf(box, "\\h'-%su/2u'", nreg(den_wd));
502 box_putf(box, "\\v'%su'%s\\v'-%su'",
503 nreg(den_fall), box_toreg(den), nreg(den_fall));
504 box_putf(box, "\\h'(-%su+%su)/2u'", nreg(den_wd), nreg(all_wd));
505 box_putf(box, "\\h'%sp*%du/100u'",nreg(box->szreg), e_nulldelim);
506 box_afterput(box, T_INNER);
507 box_toreg(box);
508 nregrm(num_wd);
509 nregrm(num_dp);
510 nregrm(den_wd);
511 nregrm(den_ht);
512 nregrm(all_wd);
513 nregrm(num_rise);
514 nregrm(den_fall);
515 nregrm(bar_wd);
516 nregrm(bar_dp);
517 nregrm(bar_ht);
518 nregrm(bar_fall);
519 nregrm(tmp_15d);
522 /* choose the smallest bracket among br[], large enough for \n(ht+\n(dp */
523 static void box_bracketsel(int dst, int ht, int dp, char **br, int any, int both)
525 int i;
526 for (i = 0; br[i]; i++) {
527 printf(".if '%s'' ", sreg(dst));
528 printf(".if \\w'%s' ", br[i]); /* is this bracket available? */
529 if (both) { /* check both the height and the depth */
530 printf(".if (%s-(%dm/100)*2)<=(-\\n[bbury]+\\n[bblly]+(%dm/100*2)) ",
531 nreg(ht), e_rulethickness, e_axisheight);
532 printf(".if (%s*2)<=(-\\n[bbury]+\\n[bblly]-(%dm/100*2)) ",
533 nreg(dp), e_axisheight);
534 } else {
535 printf(".if (%s+%s)<=(-\\n[bbury]+\\n[bblly]) ", nreg(ht), nreg(dp));
537 printf(".ds %s \"%s\n", sregname(dst), br[i]);
539 if (any) /* choose the largest bracket, if any is 1 */
540 while (--i >= 0)
541 printf(".if '%s'' .if \\w'%s' .ds %s \"%s\n",
542 sreg(dst), br[i], sregname(dst), br[i]);
545 /* build a bracket using the provided pieces */
546 static void box_bracketmk(int dst, int len,
547 char *top, char *mid, char *bot, char *cen)
549 int toplen[4];
550 int midlen[4];
551 int botlen[4];
552 int cenlen[4];
553 int mid_cnt = nregmk(); /* number of mid glyphs to insert */
554 int mid_cur = nregmk(); /* the number of mid glyphs inserted */
555 int cen_pos = nregmk();
556 int buildmacro = sregmk();
557 blen_mk(top, toplen);
558 blen_mk(mid, midlen);
559 blen_mk(bot, botlen);
560 if (cen)
561 blen_mk(cen, cenlen);
562 /* the number of mid tokens necessary to cover sub */
563 if (!cen) {
564 printf(".nr %s %s*2-%s-%s*11/10/%s\n",
565 nregname(mid_cnt), nreg(len),
566 nreg(toplen[1]), nreg(botlen[1]), nreg(midlen[1]));
567 printf(".if %s<0 .nr %s 0\n", nreg(mid_cnt), nregname(mid_cnt));
568 } else { /* for brackets with a center like { */
569 printf(".nr %s %s-(%s+%s+%s/2)*11/10/%s\n",
570 nregname(cen_pos), nreg(len), nreg(cenlen[1]),
571 nreg(toplen[1]), nreg(botlen[1]), nreg(midlen[1]));
572 printf(".if %s<0 .nr %s 0\n", nreg(cen_pos), nregname(cen_pos));
573 printf(".nr %s 0%s*2\n", nregname(mid_cnt), nreg(cen_pos));
575 /* the macro to create the bracket; escaping backslashes */
576 printf(".de %s\n", sregname(buildmacro));
577 if (cen) /* inserting cen */
578 printf(".if \\%s=\\%s .as %s \"\\v'-\\%su'%s\\h'-\\%su'\\v'-\\%su'\n",
579 nreg(mid_cur), nreg(cen_pos), sregname(dst),
580 nreg(cenlen[3]), cen, nreg(cenlen[0]), nreg(cenlen[2]));
581 printf(".if \\%s<\\%s .as %s \"\\v'-\\%su'%s\\h'-\\%su'\\v'-\\%su'\n",
582 nreg(mid_cur), nreg(mid_cnt),
583 sregname(dst), nreg(midlen[3]),
584 mid, nreg(midlen[0]), nreg(midlen[2]));
585 printf(".if \\\\n+%s<\\%s .%s\n",
586 escarg(nregname(mid_cur)), nreg(mid_cnt), sregname(buildmacro));
587 printf("..\n");
588 /* constructing the bracket */
589 printf(".ds %s \"\\v'-%su'%s\\h'-%su'\\v'-%su'\n",
590 sregname(dst), nreg(botlen[3]),
591 bot, nreg(botlen[0]), nreg(botlen[2]));
592 printf(".nr %s 0 1\n", nregname(mid_cur));
593 printf(".%s\n", sregname(buildmacro));
594 printf(".as %s \"\\v'-%su'%s\\h'-%su'\\v'-%su'\n",
595 sregname(dst), nreg(toplen[3]), top,
596 nreg(toplen[0]), nreg(toplen[2]));
597 /* moving back vertically */
598 printf(".as %s \"\\v'%su*%su+%su+%su+%su'\n",
599 sregname(dst), nreg(mid_cnt), nreg(midlen[1]), nreg(botlen[1]),
600 nreg(toplen[1]), cen ? nreg(cenlen[1]) : "0");
601 /* moving right */
602 printf(".as %s \"\\h'%su'\n",
603 sregname(dst), cen ? nreg(cenlen[0]) : nreg(midlen[0]));
604 blen_rm(toplen);
605 blen_rm(midlen);
606 blen_rm(botlen);
607 if (cen)
608 blen_rm(cenlen);
609 nregrm(mid_cnt);
610 nregrm(mid_cur);
611 nregrm(cen_pos);
612 sregrm(buildmacro);
615 static void box_bracket(struct box *box, char *brac, int ht, int dp)
617 char *sizes[NSIZES] = {NULL};
618 char *top = NULL, *mid = NULL, *bot = NULL, *cen = NULL;
619 int dst = sregmk();
620 int len = nregmk();
621 int fall = nregmk();
622 int parlen[4];
623 roff_max(len, ht, dp);
624 def_sizes(brac, sizes);
625 printf(".ds %s \"\n", sregname(dst));
626 def_pieces(brac, &top, &mid, &bot, &cen);
627 box_bracketsel(dst, ht, dp, sizes, !mid, 1);
628 if (mid) {
629 printf(".if '%s'' \\{\\\n", sreg(dst));
630 box_bracketmk(dst, len, top, mid, bot, cen);
631 printf(". \\}\n");
633 /* calculating the total vertical length of the bracket */
634 blen_mk(sreg(dst), parlen);
635 /* calculating the amount the bracket should be moved downwards */
636 printf(".nr %s 0-%s+%s/2-(%sp*%du/100u)\n", nregname(fall),
637 nreg(parlen[3]), nreg(parlen[2]), nreg(box->szreg), e_axisheight);
638 /* printing the output */
639 box_putf(box, "\\f[\\n(.f]\\s[\\n(.s]\\v'%su'%s\\v'-%su'",
640 nreg(fall), sreg(dst), nreg(fall));
641 box_toreg(box);
642 blen_rm(parlen);
643 sregrm(dst);
644 nregrm(len);
645 nregrm(fall);
648 static char *bracsign(char *brac, int left)
650 if (brac[0] == 'c' && !strncmp("ceiling", brac, strlen(brac)))
651 return left ? "\\(lc" : "\\(rc";
652 if (brac[0] == 'f' && !strncmp("floor", brac, strlen(brac)))
653 return left ? "\\(lf" : "\\(rf";
654 if (brac[0] == '<' && brac[1] == '\0')
655 return "\\(la";
656 if (brac[0] == '>' && brac[1] == '\0')
657 return "\\(ra";
658 return brac;
661 /* build large brackets; the correct font should be set up beforehand */
662 void box_wrap(struct box *box, struct box *sub, char *left, char *right)
664 int sublen[4];
665 blen_mk(box_toreg(sub), sublen);
666 printf(".ps %s\n", nreg(box->szreg));
667 if (left) {
668 box_beforeput(box, T_LEFT, 0);
669 box_bracket(box, bracsign(left, 1), sublen[2], sublen[3]);
670 box_afterput(box, T_LEFT);
672 box_merge(box, sub, 0);
673 if (right) {
674 box_beforeput(box, T_RIGHT, 0);
675 box_bracket(box, bracsign(right, 0), sublen[2], sublen[3]);
676 box_afterput(box, T_RIGHT);
678 blen_rm(sublen);
681 /* construct a radical with height at least len and width wd in dst register */
682 static void sqrt_rad(int dst, int len, int wd)
684 char *sizes[NSIZES] = {NULL};
685 int srlen[4];
686 int rnlen[4];
687 int sr_sz = nregmk();
688 int wd_diff = nregmk(); /* if wd is shorter than \(rn */
689 int sr_rx = nregmk(); /* the right-most horizontal position of \(sr */
690 int rn_dx = nregmk(); /* horizontal displacement necessary for \(rn */
691 int len2 = nregmk();
692 int rad = sregmk();
693 char *top = NULL, *mid = NULL, *bot = NULL, *cen;
694 printf(".nr %s 0%s/2*11/10\n", nregname(len2), nreg(len));
695 printf(".ds %s \"\n", sregname(rad));
696 /* selecting a radical of the appropriate size */
697 def_pieces("\\(sr", &top, &mid, &bot, &cen);
698 def_sizes("\\(sr", sizes);
699 box_bracketsel(rad, len2, len2, sizes, 0, 0);
700 /* constructing the bracket if needed */
701 if (mid) {
702 printf(".if \\w'%s' ", mid);
703 printf(".if '%s'' \\{\\\n", sreg(rad));
704 box_bracketmk(rad, len2, top, mid, bot, NULL);
705 printf(". \\}\n");
707 /* enlarging \(sr if no suitable glyph was found */
708 printf(".if '%s'' \\{\\\n", sreg(rad));
709 blen_mk("\\(sr", srlen);
710 printf(".ie %s<(%s+%s) .nr %s 0\\n(.s\n",
711 nreg(len), nreg(srlen[2]), nreg(srlen[3]), nregname(sr_sz));
712 printf(".el .nr %s 0%s*\\n(.s/(%s+%s-(%dm/100u))+1\n",
713 nregname(sr_sz), nreg(len),
714 nreg(srlen[2]), nreg(srlen[3]), e_rulethickness);
715 printf(".ps %s\n", nreg(sr_sz));
716 printf(".ds %s \"\\(sr\n", sregname(rad));
717 blen_rm(srlen);
718 printf(". \\}\n");
719 /* adding the handle */
720 blen_mk(sreg(rad), srlen);
721 printf(".nr %s \\n[bburx]\n", nregname(sr_rx));
722 blen_mk("\\(rn", rnlen);
723 printf(".nr %s 0%s-\\n[bbllx]-(%dm/100u)\n",
724 nregname(rn_dx), nreg(sr_rx), e_rulethickness);
725 printf(".nr %s 0\n", nregname(wd_diff));
726 printf(".if %s<%s .nr %s 0%s-%s\n",
727 nreg(wd), nreg(rnlen[0]),
728 nregname(wd_diff), nreg(rnlen[0]), nreg(wd));
729 /* output the radical; align the top of the radical to the baseline */
730 printf(".ds %s \"\\s[\\n(.s]\\f[\\n(.f]"
731 "\\v'%su'\\h'%su'\\l'%su+%su\\(rn'\\h'-%su'\\v'-%su'"
732 "\\h'-%su-%su'\\v'%su'%s\\v'-%su'\\h'%su+%su'\n",
733 nregname(dst),
734 nreg(rnlen[2]), nreg(rn_dx), nreg(wd), nreg(wd_diff),
735 nreg(rn_dx), nreg(rnlen[2]), nreg(wd), nreg(wd_diff),
736 nreg(srlen[2]), sreg(rad), nreg(srlen[2]), nreg(wd), nreg(wd_diff));
737 blen_rm(srlen);
738 blen_rm(rnlen);
739 nregrm(sr_sz);
740 nregrm(wd_diff);
741 nregrm(sr_rx);
742 nregrm(rn_dx);
743 sregrm(rad);
746 void box_sqrt(struct box *box, struct box *sub)
748 int sublen[4];
749 int radlen[4];
750 int rad = sregmk();
751 int rad_rise = nregmk();
752 int min_ht = nregmk();
753 box_italiccorrection(sub);
754 box_beforeput(box, T_ORD, 0);
755 blen_mk(box_toreg(sub), sublen);
756 printf(".ps %s\n", nreg(box->szreg));
757 /* 11 */
758 printf(".nr %s 0%s+%s+(2*%dm/100u)+(%dm/100u/4)\n",
759 nregname(min_ht), nreg(sublen[2]), nreg(sublen[3]),
760 e_rulethickness,
761 TS_DX(box->style) ? e_xheight : e_rulethickness);
762 sqrt_rad(rad, min_ht, sublen[0]);
763 blen_mk(sreg(rad), radlen);
764 printf(".nr %s 0(%dm/100u)+(%dm/100u/4)\n",
765 nregname(rad_rise), e_rulethickness,
766 TS_DX(box->style) ? e_xheight : e_rulethickness);
767 printf(".if %s>(%s+%s+%s) .nr %s (%s+%s-%s-%s)/2\n",
768 nreg(radlen[3]), nreg(sublen[2]), nreg(sublen[3]),
769 nreg(rad_rise), nregname(rad_rise),
770 nreg(rad_rise), nreg(radlen[3]), nreg(sublen[2]),
771 nreg(sublen[3]));
772 printf(".nr %s +%s\n", nregname(rad_rise), nreg(sublen[2]));
773 /* output the radical */
774 box_putf(box, "\\v'-%su'%s\\v'%su'\\h'-%su'%s",
775 nreg(rad_rise), sreg(rad), nreg(rad_rise),
776 nreg(sublen[0]), box_toreg(sub));
777 box_afterput(box, T_ORD);
778 box_toreg(box);
779 blen_rm(sublen);
780 blen_rm(radlen);
781 sregrm(rad);
782 nregrm(rad_rise);
783 nregrm(min_ht);
786 void box_bar(struct box *box)
788 int box_wd = nregmk();
789 int box_ht = nregmk();
790 int bar_wd = nregmk();
791 int bar_dp = nregmk();
792 int bar_rise = nregmk();
793 box_italiccorrection(box);
794 printf(".ps %s\n", nreg(box->szreg));
795 tok_len("\\(ru", bar_wd, 0, 0, bar_dp);
796 tok_dim(box_toreg(box), box_wd, box_ht, 0);
797 printf(".if %su<(%dm/100u) .nr %s 0%dm/100u\n",
798 nreg(box_ht), e_xheight, nregname(box_ht), e_xheight);
799 printf(".nr %s 0%su+%su+(3*%dm/100u)\n",
800 nregname(bar_rise), nreg(box_ht),
801 nreg(bar_dp), e_rulethickness);
802 box_putf(box, "\\v'-%su'\\s%s\\f[\\n(.f]\\l'-%su\\(ru'\\v'%su'",
803 nreg(bar_rise), escarg(nreg(box->szreg)),
804 nreg(box_wd), nreg(bar_rise));
805 nregrm(box_wd);
806 nregrm(box_ht);
807 nregrm(bar_wd);
808 nregrm(bar_dp);
809 nregrm(bar_rise);
812 void box_accent(struct box *box, char *c)
814 int box_wd = nregmk();
815 int box_ht = nregmk();
816 int ac_rise = nregmk();
817 int ac_wd = nregmk();
818 int ac_dp = nregmk();
819 box_italiccorrection(box);
820 printf(".ps %s\n", nreg(box->szreg));
821 tok_len(c, ac_wd, 0, 0, ac_dp);
822 tok_dim(box_toreg(box), box_wd, box_ht, 0);
823 printf(".if %su<(%dm/100u) .nr %s 0%dm/100u\n",
824 nreg(box_ht), e_xheight, nregname(box_ht), e_xheight);
825 printf(".nr %s 0%su+%su+(%sp*10u/100u)\n",
826 nregname(ac_rise), nreg(box_ht),
827 nreg(ac_dp), nreg(box->szreg));
828 box_putf(box, "\\v'-%su'\\h'-%su-%su/2u'\\s%s\\f[\\n(.f]%s\\h'%su-%su/2u'\\v'%su'",
829 nreg(ac_rise), nreg(box_wd), nreg(ac_wd),
830 escarg(nreg(box->szreg)), c, nreg(box_wd),
831 nreg(ac_wd), nreg(ac_rise));
832 nregrm(box_wd);
833 nregrm(box_ht);
834 nregrm(ac_rise);
835 nregrm(ac_wd);
836 nregrm(ac_dp);
839 void box_under(struct box *box)
841 int box_wd = nregmk();
842 int box_dp = nregmk();
843 int bar_wd = nregmk();
844 int bar_ht = nregmk();
845 int bar_fall = nregmk();
846 box_italiccorrection(box);
847 printf(".ps %s\n", nreg(box->szreg));
848 tok_len("\\(ul", bar_wd, 0, bar_ht, 0);
849 tok_dim(box_toreg(box), box_wd, 0, box_dp);
850 printf(".if %s<0 .nr %s 0\n", nreg(box_dp), nregname(box_dp));
851 printf(".nr %s 0%su+%su+(3*%dm/100u)\n",
852 nregname(bar_fall), nreg(box_dp),
853 nreg(bar_ht), e_rulethickness);
854 box_putf(box, "\\v'%su'\\s%s\\f[\\n(.f]\\l'-%su\\(ul'\\v'-%su'",
855 nreg(bar_fall), escarg(nreg(box->szreg)),
856 nreg(box_wd), nreg(bar_fall));
857 nregrm(box_wd);
858 nregrm(box_dp);
859 nregrm(bar_wd);
860 nregrm(bar_ht);
861 nregrm(bar_fall);
864 char *box_toreg(struct box *box)
866 if (!box->reg) {
867 box->reg = sregmk();
868 printf(".ds %s \"%s\n", sregname(box->reg), box_buf(box));
870 return sreg(box->reg);
873 int box_empty(struct box *box)
875 return !strlen(box_buf(box));
878 void box_vcenter(struct box *box, struct box *sub)
880 int wd = nregmk();
881 int ht = nregmk();
882 int dp = nregmk();
883 int fall = nregmk();
884 box_beforeput(box, sub->tbeg, 0);
885 tok_dim(box_toreg(sub), wd, ht, dp);
886 printf(".nr %s 0-%s+%s/2-(%sp*%du/100u)\n", nregname(fall),
887 nreg(dp), nreg(ht), nreg(box->szreg), e_axisheight);
888 box_putf(box, "\\v'%su'%s\\v'-%su'",
889 nreg(fall), box_toreg(sub), nreg(fall));
890 box_toreg(box);
891 box_afterput(box, sub->tcur);
892 nregrm(wd);
893 nregrm(ht);
894 nregrm(dp);
895 nregrm(fall);
898 /* include line-space requests */
899 void box_vertspace(struct box *box)
901 int box_wd = nregmk();
902 int htroom = nregmk();
903 int dproom = nregmk();
904 box_italiccorrection(box);
905 /* amount of room available before and after this line */
906 printf(".nr %s 0+\\n(.vu-%sp+(%sp*%du/100u)\n",
907 nregname(htroom), nreg(box->szreg),
908 nreg(box->szreg), e_bodyheight);
909 printf(".nr %s 0+\\n(.vu-%sp+(%sp*%du/100u)\n",
910 nregname(dproom), nreg(box->szreg),
911 nreg(box->szreg), e_bodydepth);
912 /* appending \x requests */
913 tok_dim(box_toreg(box), box_wd, 0, 0);
914 printf(".if -\\n[bbury]>%s .as %s \"\\x'\\n[bbury]u+%su'\n",
915 nreg(htroom), sregname(box->reg), nreg(htroom));
916 printf(".if \\n[bblly]>%s .as %s \"\\x'\\n[bblly]u-%su'\n",
917 nreg(dproom), sregname(box->reg), nreg(dproom));
918 nregrm(box_wd);
919 nregrm(htroom);
920 nregrm(dproom);
923 /* put the current width to the given number register */
924 void box_markpos(struct box *box, char *reg)
926 box->tomark = reg;
929 /* initialize the length of a pile or column of a matrix */
930 static void box_colinit(struct box **pile, int n,
931 int plen[][4], int wd, int ht)
933 int i;
934 for (i = 0; i < n; i++)
935 if (pile[i])
936 box_italiccorrection(pile[i]);
937 for (i = 0; i < n; i++)
938 blen_mk(pile[i] ? box_toreg(pile[i]) : "", plen[i]);
939 printf(".nr %s 0%s\n", nregname(wd), nreg(plen[0][0]));
940 printf(".nr %s 0%s\n", nregname(ht), nreg(plen[0][2]));
941 /* finding the maximum width */
942 for (i = 1; i < n; i++) {
943 printf(".if %s>%s .nr %s 0+%s\n",
944 nreg(plen[i][0]), nreg(wd),
945 nregname(wd), nreg(plen[i][0]));
947 /* finding the maximum height (vertical length) */
948 for (i = 1; i < n; i++) {
949 printf(".if %s+%s>%s .nr %s 0+%s+%s\n",
950 nreg(plen[i - 1][3]), nreg(plen[i][2]), nreg(ht),
951 nregname(ht), nreg(plen[i - 1][3]), nreg(plen[i][2]));
953 /* maximum height and the depth of the last row */
954 printf(".if %s>%s .nr %s 0+%s\n",
955 nreg(plen[n - 1][3]), nreg(ht),
956 nregname(ht), nreg(plen[n - 1][3]));
959 /* append the give pile to box */
960 static void box_colput(struct box **pile, int n, struct box *box,
961 int adj, int plen[][4], int wd, int ht)
963 int i;
964 box_putf(box, "\\v'-%du*%su/2u'", n - 1, nreg(ht));
965 /* adding the entries */
966 for (i = 0; i < n; i++) {
967 if (adj == 'c')
968 box_putf(box, "\\h'%su-%su/2u'",
969 nreg(wd), nreg(plen[i][0]));
970 if (adj == 'r')
971 box_putf(box, "\\h'%su-%su'",
972 nreg(wd), nreg(plen[i][0]));
973 box_putf(box, "\\v'%su'%s", i ? nreg(ht) : "0",
974 pile[i] ? box_toreg(pile[i]) : "");
975 if (adj == 'l')
976 box_putf(box, "\\h'-%su'", nreg(plen[i][0]));
977 if (adj == 'c')
978 box_putf(box, "\\h'-%su+(%su-%su/2u)'",
979 nreg(wd), nreg(wd), nreg(plen[i][0]));
980 if (adj == 'r')
981 box_putf(box, "\\h'-%su'", nreg(wd));
983 box_putf(box, "\\v'-%du*%su/2u'\\h'%su'", n - 1, nreg(ht), nreg(wd));
986 /* free the registers allocated for this pile */
987 static void box_coldone(struct box **pile, int n, int plen[][4])
989 int i;
990 for (i = 0; i < n; i++)
991 blen_rm(plen[i]);
994 /* calculate the number of entries in the given pile */
995 static int box_colnrows(struct box *cols[])
997 int n = 0;
998 while (n < NPILES && cols[n])
999 n++;
1000 return n;
1003 void box_pile(struct box *box, struct box **pile, int adj, int rowspace)
1005 int plen[NPILES][4];
1006 int max_wd = nregmk();
1007 int max_ht = nregmk();
1008 int n = box_colnrows(pile);
1009 box_beforeput(box, T_INNER, 0);
1010 box_colinit(pile, n, plen, max_wd, max_ht);
1011 /* inserting spaces between entries */
1012 printf(".if %s<(%sp*%du/100u) .nr %s (%sp*%du/100u)\n",
1013 nreg(max_ht), nreg(box->szreg), e_baselinesep,
1014 nregname(max_ht), nreg(box->szreg), e_baselinesep);
1015 if (rowspace)
1016 printf(".nr %s +(%sp*%du/100u)\n",
1017 nregname(max_ht), nreg(box->szreg), rowspace);
1018 /* adding the entries */
1019 box_colput(pile, n, box, adj, plen, max_wd, max_ht);
1020 box_coldone(pile, n, plen);
1021 box_afterput(box, T_INNER);
1022 box_toreg(box);
1023 nregrm(max_wd);
1024 nregrm(max_ht);
1027 void box_matrix(struct box *box, int ncols, struct box *cols[][NPILES],
1028 int *adj, int colspace, int rowspace)
1030 int plen[NPILES][NPILES][4];
1031 int wd[NPILES];
1032 int ht[NPILES];
1033 int max_ht = nregmk();
1034 int max_wd = nregmk();
1035 int nrows = 0;
1036 int i;
1037 box_beforeput(box, T_INNER, 0);
1038 for (i = 0; i < ncols; i++)
1039 if (box_colnrows(cols[i]) > nrows)
1040 nrows = box_colnrows(cols[i]);
1041 for (i = 0; i < ncols; i++)
1042 wd[i] = nregmk();
1043 for (i = 0; i < ncols; i++)
1044 ht[i] = nregmk();
1045 /* initializing the columns */
1046 for (i = 0; i < ncols; i++)
1047 box_colinit(cols[i], nrows, plen[i], wd[i], ht[i]);
1048 /* finding the maximum width and height */
1049 printf(".nr %s 0%s\n", nregname(max_wd), nreg(wd[0]));
1050 printf(".nr %s 0%s\n", nregname(max_ht), nreg(ht[0]));
1051 for (i = 1; i < ncols; i++) {
1052 printf(".if %s>%s .nr %s 0+%s\n",
1053 nreg(wd[i]), nreg(max_wd),
1054 nregname(max_wd), nreg(wd[i]));
1056 for (i = 1; i < ncols; i++) {
1057 printf(".if %s>%s .nr %s 0+%s\n",
1058 nreg(ht[i]), nreg(max_ht),
1059 nregname(max_ht), nreg(ht[i]));
1061 /* inserting spaces between rows */
1062 printf(".if %s<(%sp*%du/100u) .nr %s (%sp*%du/100u)\n",
1063 nreg(max_ht), nreg(box->szreg), e_baselinesep,
1064 nregname(max_ht), nreg(box->szreg), e_baselinesep);
1065 if (rowspace)
1066 printf(".nr %s +(%sp*%du/100u)\n",
1067 nregname(max_ht), nreg(box->szreg), rowspace);
1068 /* printing the columns */
1069 for (i = 0; i < ncols; i++) {
1070 if (i) /* space between columns */
1071 box_putf(box, "\\h'%sp*%du/100u'",
1072 nreg(box->szreg), e_columnsep + colspace);
1073 box_colput(cols[i], nrows, box, adj[i],
1074 plen[i], max_wd, max_ht);
1076 box_afterput(box, T_INNER);
1077 box_toreg(box);
1078 for (i = 0; i < ncols; i++)
1079 box_coldone(cols[i], nrows, plen[i]);
1080 for (i = 0; i < ncols; i++)
1081 nregrm(ht[i]);
1082 for (i = 0; i < ncols; i++)
1083 nregrm(wd[i]);
1084 nregrm(max_wd);
1085 nregrm(max_ht);