def: int should be defined as \(is
[neateqn.git] / box.c
blobb9922d57970c360c6a7aece01a678746549e17bf
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 /* call just before inserting a non-italic character */
105 static void box_italiccorrection(struct box *box)
107 if (box->atoms && (box->tcur & T_ITALIC))
108 box_put(box, "\\/");
109 box->tcur &= ~T_ITALIC;
112 static int box_fixatom(int cur, int pre)
114 if (cur == T_BINOP && (!pre || pre == T_RELOP || pre == T_BIGOP ||
115 pre == T_LEFT || pre == T_PUNC))
116 return T_ORD;
117 if (cur == T_RELOP && (!pre || pre == T_LEFT))
118 return T_ORD;
119 return cur;
122 /* call before inserting a token with box_put() and box_putf() */
123 static void box_beforeput(struct box *box, int type)
125 int autogaps;
126 if (box->atoms) {
127 autogaps = eqn_gaps(box, T_ATOM(type));
128 if (!(type & T_ITALIC))
129 box_italiccorrection(box);
130 if (autogaps && type != T_GAP && box->tcur != T_GAP) {
131 box_italiccorrection(box);
132 box_putf(box, "\\h'%du*%sp/100u'",
133 autogaps, nreg(box->szreg));
136 if (box->tomark) {
137 printf(".nr %s 0\\w'%s'\n", box->tomark, box_toreg(box));
138 box->tomark = NULL;
142 /* call after inserting a token with box_put() and box_putf() */
143 static void box_afterput(struct box *box, int type)
145 box->atoms++;
146 box->tcur = T_FONT(type) | box_fixatom(T_TOK(type), T_TOK(box->tcur));
147 if (!box->tbeg)
148 box->tbeg = box->tcur;
151 /* insert s with the given type */
152 void box_puttext(struct box *box, int type, char *s, ...)
154 char buf[LNLEN];
155 va_list ap;
156 va_start(ap, s);
157 vsprintf(buf, s, ap);
158 va_end(ap);
159 box_beforeput(box, type);
160 if (!(box->tcur & T_ITALIC) && (type & T_ITALIC))
161 box_put(box, "\\,");
162 box_put(box, buf);
163 box_afterput(box, type);
166 /* append sub to box */
167 void box_merge(struct box *box, struct box *sub)
169 if (box_empty(sub))
170 return;
171 box_beforeput(box, sub->tbeg);
172 box_toreg(box);
173 box_put(box, box_toreg(sub));
174 if (!box->tbeg)
175 box->tbeg = sub->tbeg;
176 /* fix atom type only if merging a single atom */
177 if (sub->atoms == 1) {
178 box_afterput(box, sub->tcur);
179 } else {
180 box->tcur = sub->tcur;
181 box->atoms += sub->atoms;
185 /* put the maximum of number registers a and b into register dst */
186 static void roff_max(int dst, int a, int b)
188 printf(".ie %s>=%s .nr %s 0+%s\n",
189 nreg(a), nreg(b), nregname(dst), nreg(a));
190 printf(".el .nr %s 0+%s\n", nregname(dst), nreg(b));
193 /* return the width, height and depth of a string */
194 static void tok_dim(char *s, int wd, int ht, int dp)
196 printf(".nr %s 0\\w'%s'\n", nregname(wd), s);
197 if (ht)
198 printf(".nr %s 0-\\n[bbury]\n", nregname(ht));
199 if (dp)
200 printf(".nr %s 0\\n[bblly]\n", nregname(dp));
203 static int box_suprise(struct box *box)
205 if (TS_0(box->style))
206 return e_sup3;
207 return box->style == TS_D ? e_sup1 : e_sup2;
210 void box_sub(struct box *box, struct box *sub, struct box *sup)
212 int box_wd = nregmk();
213 int box_wdnoic = nregmk();
214 int box_dp = nregmk();
215 int box_ht = nregmk();
216 int sub_wd = nregmk();
217 int sup_wd = nregmk();
218 int all_wd = nregmk();
219 int sup_dp = nregmk();
220 int sub_ht = nregmk();
221 int sup_rise = nregmk();
222 int sub_fall = nregmk();
223 int tmp_18e = nregmk();
224 int sub_cor = nregmk();
225 if (sub)
226 box_italiccorrection(sub);
227 if (sup)
228 box_italiccorrection(sup);
229 if (sub)
230 tok_dim(box_toreg(box), box_wdnoic, 0, 0);
231 box_italiccorrection(box);
232 printf(".ps %s\n", nreg(box->szreg));
233 tok_dim(box_toreg(box), box_wd, box_ht, box_dp);
234 box_putf(box, "\\h'5m/100u'");
235 if (sup) {
236 tok_dim(box_toreg(sup), sup_wd, 0, sup_dp);
237 /* 18a */
238 printf(".nr %s 0%su-(%dm/100u)\n",
239 nregname(sup_rise), nreg(box_ht), e_supdrop);
240 /* 18c */
241 printf(".if %s<(%dm/100u) .nr %s (%dm/100u)\n",
242 nreg(sup_rise), box_suprise(box),
243 nregname(sup_rise), box_suprise(box));
244 printf(".if %s<(%s+(%dm/100u/4)) .nr %s 0%s+(%dm/100u/4)\n",
245 nreg(sup_rise), nreg(sup_dp), e_xheight,
246 nregname(sup_rise), nreg(sup_dp), e_xheight);
248 if (sub) {
249 tok_dim(box_toreg(sub), sub_wd, sub_ht, 0);
250 /* 18a */
251 printf(".nr %s 0%su+(%dm/100u)\n",
252 nregname(sub_fall), nreg(box_dp), e_subdrop);
254 if (sub && !sup) {
255 /* 18b */
256 printf(".if %s<(%dm/100u) .nr %s (%dm/100u)\n",
257 nreg(sub_fall), e_sub1,
258 nregname(sub_fall), e_sub1);
259 printf(".if %s<(%s-(%dm/100u*4/5)) .nr %s 0%s-(%dm/100u*4/5)\n",
260 nreg(sub_fall), nreg(sub_ht), e_xheight,
261 nregname(sub_fall), nreg(sub_ht), e_xheight);
263 if (sub && sup) {
264 /* 18d */
265 printf(".if %s<(%dm/100u) .nr %s (%dm/100u)\n",
266 nreg(sub_fall), e_sub2,
267 nregname(sub_fall), e_sub2);
268 /* 18e */
269 printf(".if (%s-%s)-(%s-%s)<(%dm/100u*4) \\{\\\n",
270 nreg(sup_rise), nreg(sup_dp),
271 nreg(sub_ht), nreg(sub_fall), e_rulethickness);
272 printf(".nr %s (%dm/100u*4)+%s-(%s-%s)\n",
273 nregname(sub_fall), e_rulethickness,
274 nreg(sub_ht), nreg(sup_rise), nreg(sup_dp));
275 printf(".nr %s (%dm/100u*4/5)-(%s-%s)\n",
276 nregname(tmp_18e), e_xheight,
277 nreg(sup_rise), nreg(sup_dp));
278 printf(".if %s>0 .nr %s +%s\n",
279 nreg(tmp_18e), nregname(sup_rise), nreg(tmp_18e));
280 printf(".if %s>0 .nr %s -%s \\}\n",
281 nreg(tmp_18e), nregname(sub_fall), nreg(tmp_18e));
283 /* writing the superscript */
284 if (sup) {
285 box_putf(box, "\\v'-%su'%s\\v'%su'",
286 nreg(sup_rise), box_toreg(sup), nreg(sup_rise));
287 if (sub)
288 box_putf(box, "\\h'-%su'", nreg(sup_wd));
290 /* writing the subscript */
291 if (sub) {
292 /* subscript correction */
293 printf(".nr %s (%s+%s)*(%s-%s)/%s\n", nregname(sub_cor),
294 nreg(box_ht), nreg(sub_fall),
295 nreg(box_wd), nreg(box_wdnoic), nreg(box_ht));
296 printf(".nr %s -%s\n", nregname(sub_wd), nreg(sub_cor));
297 box_putf(box, "\\h'-%su'", nreg(sub_cor));
298 box_putf(box, "\\v'%su'%s\\v'-%su'",
299 nreg(sub_fall), box_toreg(sub), nreg(sub_fall));
300 if (sup) {
301 box_putf(box, "\\h'-%su'", nreg(sub_wd));
302 roff_max(all_wd, sub_wd, sup_wd);
303 box_putf(box, "\\h'+%su'", nreg(all_wd));
306 box_putf(box, "\\h'%dm/100u'", e_scriptspace);
307 nregrm(box_wd);
308 nregrm(box_wdnoic);
309 nregrm(box_dp);
310 nregrm(box_ht);
311 nregrm(sub_wd);
312 nregrm(sup_wd);
313 nregrm(all_wd);
314 nregrm(sup_dp);
315 nregrm(sub_ht);
316 nregrm(sup_rise);
317 nregrm(sub_fall);
318 nregrm(tmp_18e);
319 nregrm(sub_cor);
322 void box_from(struct box *box, struct box *lim, struct box *llim, struct box *ulim)
324 int lim_wd = nregmk(); /* box's width */
325 int lim_ht = nregmk(); /* box's height */
326 int lim_dp = nregmk(); /* box's depth */
327 int llim_wd = nregmk(); /* llim's width */
328 int ulim_wd = nregmk(); /* ulim's width */
329 int ulim_dp = nregmk(); /* ulim's depth */
330 int llim_ht = nregmk(); /* llim's height */
331 int ulim_rise = nregmk(); /* the position of ulim */
332 int llim_fall = nregmk(); /* the position of llim */
333 int all_wd = nregmk(); /* the width of all */
334 box_italiccorrection(lim);
335 box_beforeput(box, T_BIGOP);
336 tok_dim(box_toreg(lim), lim_wd, lim_ht, lim_dp);
337 printf(".ps %s\n", nreg(box->szreg));
338 if (ulim)
339 tok_dim(box_toreg(ulim), ulim_wd, 0, ulim_dp);
340 if (llim)
341 tok_dim(box_toreg(llim), llim_wd, llim_ht, 0);
342 if (ulim && llim)
343 roff_max(all_wd, llim_wd, ulim_wd);
344 else
345 printf(".nr %s %s\n", nregname(all_wd),
346 ulim ? nreg(ulim_wd) : nreg(llim_wd));
347 printf(".if %s>%s .nr %s 0%s\n",
348 nreg(lim_wd), nreg(all_wd),
349 nregname(all_wd), nreg(lim_wd));
350 box_putf(box, "\\h'%su-%su/2u'", nreg(all_wd), nreg(lim_wd));
351 box_merge(box, lim);
352 box_putf(box, "\\h'-%su/2u'", nreg(lim_wd));
353 if (ulim) {
354 /* 13a */
355 printf(".nr %s (%dm/100u)-%s\n",
356 nregname(ulim_rise), e_bigopspacing3, nreg(ulim_dp));
357 printf(".if %s<(%dm/100u) .nr %s (%dm/100u)\n",
358 nreg(ulim_rise), e_bigopspacing1,
359 nregname(ulim_rise), e_bigopspacing1);
360 printf(".nr %s +%s+%s\n",
361 nregname(ulim_rise), nreg(lim_ht), nreg(ulim_dp));
362 box_putf(box, "\\h'-%su/2u'\\v'-%su'%s\\v'%su'\\h'-%su/2u'",
363 nreg(ulim_wd), nreg(ulim_rise), box_toreg(ulim),
364 nreg(ulim_rise), nreg(ulim_wd));
366 if (llim) {
367 /* 13a */
368 printf(".nr %s (%dm/100u)-%s\n",
369 nregname(llim_fall), e_bigopspacing4, nreg(llim_ht));
370 printf(".if %s<(%dm/100u) .nr %s (%dm/100u)\n",
371 nreg(llim_fall), e_bigopspacing2,
372 nregname(llim_fall), e_bigopspacing2);
373 printf(".nr %s +%s+%s\n",
374 nregname(llim_fall), nreg(lim_dp), nreg(llim_ht));
375 box_putf(box, "\\h'-%su/2u'\\v'%su'%s\\v'-%su'\\h'-%su/2u'",
376 nreg(llim_wd), nreg(llim_fall), box_toreg(llim),
377 nreg(llim_fall), nreg(llim_wd));
379 box_putf(box, "\\h'%su/2u'", nreg(all_wd));
380 box_afterput(box, T_BIGOP);
381 nregrm(lim_wd);
382 nregrm(lim_ht);
383 nregrm(lim_dp);
384 nregrm(llim_wd);
385 nregrm(ulim_wd);
386 nregrm(ulim_dp);
387 nregrm(llim_ht);
388 nregrm(ulim_rise);
389 nregrm(llim_fall);
390 nregrm(all_wd);
393 /* return the width of s; len is the height plus depth */
394 static void tok_len(char *s, int wd, int len, int ht, int dp)
396 printf(".nr %s 0\\w'%s'\n", nregname(wd), s);
397 if (len)
398 printf(".nr %s 0\\n[bblly]-\\n[bbury]-2\n", nregname(len));
399 if (dp)
400 printf(".nr %s 0\\n[bblly]-1\n", nregname(dp));
401 if (ht)
402 printf(".nr %s 0-\\n[bbury]-1\n", nregname(ht));
405 /* len[0]: width, len[1]: vertical length, len[2]: height, len[3]: depth */
406 static void blen_mk(char *s, int len[4])
408 int i;
409 for (i = 0; i < 4; i++)
410 len[i] = nregmk();
411 tok_len(s, len[0], len[1], len[2], len[3]);
414 /* free the registers allocated with blen_mk() */
415 static void blen_rm(int len[4])
417 int i;
418 for (i = 0; i < 4; i++)
419 nregrm(len[i]);
422 /* build a fraction; the correct font should be set up beforehand */
423 void box_over(struct box *box, struct box *num, struct box *den)
425 int num_wd = nregmk();
426 int num_dp = nregmk();
427 int den_wd = nregmk();
428 int den_ht = nregmk();
429 int all_wd = nregmk();
430 int num_rise = nregmk();
431 int den_fall = nregmk();
432 int bar_wd = nregmk();
433 int bar_dp = nregmk();
434 int bar_ht = nregmk();
435 int bar_fall = nregmk();
436 int tmp_15d = nregmk();
437 int bargap = (TS_DX(box->style) ? 7 : 3) * e_rulethickness / 2;
438 box_beforeput(box, T_INNER);
439 box_italiccorrection(num);
440 box_italiccorrection(den);
441 tok_dim(box_toreg(num), num_wd, 0, num_dp);
442 tok_dim(box_toreg(den), den_wd, den_ht, 0);
443 roff_max(all_wd, num_wd, den_wd);
444 printf(".ps %s\n", nreg(box->szreg));
445 tok_len("\\(ru", bar_wd, 0, bar_ht, bar_dp);
446 /* 15b */
447 printf(".nr %s 0%dm/100u\n",
448 nregname(num_rise), TS_DX(box->style) ? e_num1 : e_num2);
449 printf(".nr %s 0%dm/100u\n",
450 nregname(den_fall), TS_DX(box->style) ? e_denom1 : e_denom2);
451 /* 15d */
452 printf(".nr %s (%s-%s)-((%dm/100u)+(%dm/100u/2))\n",
453 nregname(tmp_15d), nreg(num_rise), nreg(num_dp),
454 e_axisheight, e_rulethickness);
455 printf(".if %s<(%dm/100u) .nr %s +(%dm/100u)-%s\n",
456 nreg(tmp_15d), bargap, nregname(num_rise),
457 bargap, nreg(tmp_15d));
458 printf(".nr %s ((%dm/100u)-(%dm/100u/2))-(%s-%s)\n",
459 nregname(tmp_15d), e_axisheight, e_rulethickness,
460 nreg(den_ht), nreg(den_fall));
461 printf(".if %s<(%dm/100u) .nr %s +(%dm/100u)-%s\n",
462 nreg(tmp_15d), bargap, nregname(den_fall),
463 bargap, nreg(tmp_15d));
464 /* calculating the vertical position of the bar */
465 printf(".nr %s 0-%s+%s/2-(%dm/100u)\n",
466 nregname(bar_fall), nreg(bar_dp),
467 nreg(bar_ht), e_axisheight);
468 /* making the bar longer */
469 printf(".nr %s +2*(%dm/100u)\n",
470 nregname(all_wd), e_overhang);
471 /* null delimiter space */
472 box_putf(box, "\\h'%sp*%du/100u'",nreg(box->szreg), e_nulldelim);
473 /* drawing the bar */
474 box_putf(box, "\\v'%su'\\f[\\n(.f]\\s[%s]\\l'%su'\\v'-%su'\\h'-%su/2u'",
475 nreg(bar_fall), nreg(box->szreg), nreg(all_wd),
476 nreg(bar_fall), nreg(all_wd));
477 /* output the numerator */
478 box_putf(box, "\\h'-%su/2u'", nreg(num_wd));
479 box_putf(box, "\\v'-%su'%s\\v'%su'",
480 nreg(num_rise), box_toreg(num), nreg(num_rise));
481 box_putf(box, "\\h'-%su/2u'", nreg(num_wd));
482 /* output the denominator */
483 box_putf(box, "\\h'-%su/2u'", nreg(den_wd));
484 box_putf(box, "\\v'%su'%s\\v'-%su'",
485 nreg(den_fall), box_toreg(den), nreg(den_fall));
486 box_putf(box, "\\h'(-%su+%su)/2u'", nreg(den_wd), nreg(all_wd));
487 box_putf(box, "\\h'%sp*%du/100u'",nreg(box->szreg), e_nulldelim);
488 box_afterput(box, T_INNER);
489 box_toreg(box);
490 nregrm(num_wd);
491 nregrm(num_dp);
492 nregrm(den_wd);
493 nregrm(den_ht);
494 nregrm(all_wd);
495 nregrm(num_rise);
496 nregrm(den_fall);
497 nregrm(bar_wd);
498 nregrm(bar_dp);
499 nregrm(bar_ht);
500 nregrm(bar_fall);
501 nregrm(tmp_15d);
504 /* choose the smallest bracket among br[], large enough for \n(ht+\n(dp */
505 static void box_bracketsel(int dst, int ht, int dp, char **br, int any, int both)
507 int i;
508 for (i = 0; br[i]; i++) {
509 printf(".if '%s'' ", sreg(dst));
510 printf(".if \\w'%s' ", br[i]); /* is this bracket available? */
511 if (both) { /* check both the height and the depth */
512 printf(".if (%s-(%dm/100)*2)<=(-\\n[bbury]+\\n[bblly]+(%dm/100*2)) ",
513 nreg(ht), e_rulethickness, e_axisheight);
514 printf(".if (%s*2)<=(-\\n[bbury]+\\n[bblly]-(%dm/100*2)) ",
515 nreg(dp), e_axisheight);
516 } else {
517 printf(".if (%s+%s)<=(-\\n[bbury]+\\n[bblly]) ", nreg(ht), nreg(dp));
519 printf(".ds %s \"%s\n", sregname(dst), br[i]);
521 if (any) /* choose the largest bracket, if any is 1 */
522 while (--i >= 0)
523 printf(".if '%s'' .if \\w'%s' .ds %s \"%s\n",
524 sreg(dst), br[i], sregname(dst), br[i]);
527 /* build a bracket using the provided pieces */
528 static void box_bracketmk(int dst, int len,
529 char *top, char *mid, char *bot, char *cen)
531 int toplen[4];
532 int midlen[4];
533 int botlen[4];
534 int cenlen[4];
535 int mid_cnt = nregmk(); /* number of mid glyphs to insert */
536 int mid_cur = nregmk(); /* the number of mid glyphs inserted */
537 int cen_pos = nregmk();
538 int buildmacro = sregmk();
539 blen_mk(top, toplen);
540 blen_mk(mid, midlen);
541 blen_mk(bot, botlen);
542 if (cen)
543 blen_mk(cen, cenlen);
544 /* the number of mid tokens necessary to cover sub */
545 if (!cen) {
546 printf(".nr %s %s*2-%s-%s*11/10/%s\n",
547 nregname(mid_cnt), nreg(len),
548 nreg(toplen[1]), nreg(botlen[1]), nreg(midlen[1]));
549 printf(".if %s<0 .nr %s 0\n", nreg(mid_cnt), nregname(mid_cnt));
550 } else { /* for brackets with a center like { */
551 printf(".nr %s %s-(%s+%s+%s/2)*11/10/%s\n",
552 nregname(cen_pos), nreg(len), nreg(cenlen[1]),
553 nreg(toplen[1]), nreg(botlen[1]), nreg(midlen[1]));
554 printf(".if %s<0 .nr %s 0\n", nreg(cen_pos), nregname(cen_pos));
555 printf(".nr %s 0%s*2\n", nregname(mid_cnt), nreg(cen_pos));
557 /* the macro to create the bracket; escaping backslashes */
558 printf(".de %s\n", sregname(buildmacro));
559 if (cen) /* inserting cen */
560 printf(".if \\%s=\\%s .as %s \"\\v'-\\%su'%s\\h'-\\%su'\\v'-\\%su'\n",
561 nreg(mid_cur), nreg(cen_pos), sregname(dst),
562 nreg(cenlen[3]), cen, nreg(cenlen[0]), nreg(cenlen[2]));
563 printf(".if \\%s<\\%s .as %s \"\\v'-\\%su'%s\\h'-\\%su'\\v'-\\%su'\n",
564 nreg(mid_cur), nreg(mid_cnt),
565 sregname(dst), nreg(midlen[3]),
566 mid, nreg(midlen[0]), nreg(midlen[2]));
567 printf(".if \\\\n+%s<\\%s .%s\n",
568 escarg(nregname(mid_cur)), nreg(mid_cnt), sregname(buildmacro));
569 printf("..\n");
570 /* constructing the bracket */
571 printf(".ds %s \"\\v'-%su'%s\\h'-%su'\\v'-%su'\n",
572 sregname(dst), nreg(botlen[3]),
573 bot, nreg(botlen[0]), nreg(botlen[2]));
574 printf(".nr %s 0 1\n", nregname(mid_cur));
575 printf(".%s\n", sregname(buildmacro));
576 printf(".as %s \"\\v'-%su'%s\\h'-%su'\\v'-%su'\n",
577 sregname(dst), nreg(toplen[3]), top,
578 nreg(toplen[0]), nreg(toplen[2]));
579 /* moving back vertically */
580 printf(".as %s \"\\v'%su*%su+%su+%su+%su'\n",
581 sregname(dst), nreg(mid_cnt), nreg(midlen[1]), nreg(botlen[1]),
582 nreg(toplen[1]), cen ? nreg(cenlen[1]) : "0");
583 /* moving right */
584 printf(".as %s \"\\h'%su'\n",
585 sregname(dst), cen ? nreg(cenlen[0]) : nreg(midlen[0]));
586 blen_rm(toplen);
587 blen_rm(midlen);
588 blen_rm(botlen);
589 if (cen)
590 blen_rm(cenlen);
591 nregrm(mid_cnt);
592 nregrm(mid_cur);
593 nregrm(cen_pos);
594 sregrm(buildmacro);
597 static void box_bracket(struct box *box, char *brac, int ht, int dp)
599 char *sizes[NSIZES] = {NULL};
600 char *top = NULL, *mid = NULL, *bot = NULL, *cen = NULL;
601 int dst = sregmk();
602 int len = nregmk();
603 int fall = nregmk();
604 int parlen[4];
605 roff_max(len, ht, dp);
606 def_sizes(brac, sizes);
607 printf(".ds %s \"\n", sregname(dst));
608 def_pieces(brac, &top, &mid, &bot, &cen);
609 box_bracketsel(dst, ht, dp, sizes, !mid, 1);
610 if (mid) {
611 printf(".if '%s'' \\{\\\n", sreg(dst));
612 box_bracketmk(dst, len, top, mid, bot, cen);
613 printf(". \\}\n");
615 /* calculating the total vertical length of the bracket */
616 blen_mk(sreg(dst), parlen);
617 /* calculating the amount the bracket should be moved downwards */
618 printf(".nr %s 0-%s+%s/2-(%sp*%du/100u)\n", nregname(fall),
619 nreg(parlen[3]), nreg(parlen[2]), nreg(box->szreg), e_axisheight);
620 /* printing the output */
621 box_putf(box, "\\f[\\n(.f]\\s[\\n(.s]\\v'%su'%s\\v'-%su'",
622 nreg(fall), sreg(dst), nreg(fall));
623 box_toreg(box);
624 blen_rm(parlen);
625 sregrm(dst);
626 nregrm(len);
627 nregrm(fall);
630 static char *bracsign(char *brac, int left)
632 if (brac[0] == 'c' && !strncmp("ceiling", brac, strlen(brac)))
633 return left ? "\\(lc" : "\\(rc";
634 if (brac[0] == 'f' && !strncmp("floor", brac, strlen(brac)))
635 return left ? "\\(lf" : "\\(rf";
636 if (brac[0] == '<' && brac[1] == '\0')
637 return "\\(la";
638 if (brac[0] == '>' && brac[1] == '\0')
639 return "\\(ra";
640 return brac;
643 /* build large brackets; the correct font should be set up beforehand */
644 void box_wrap(struct box *box, struct box *sub, char *left, char *right)
646 int sublen[4];
647 blen_mk(box_toreg(sub), sublen);
648 printf(".ps %s\n", nreg(box->szreg));
649 if (left) {
650 box_beforeput(box, T_LEFT);
651 box_bracket(box, bracsign(left, 1), sublen[2], sublen[3]);
652 box_afterput(box, T_LEFT);
654 box_merge(box, sub);
655 if (right) {
656 box_beforeput(box, T_RIGHT);
657 box_bracket(box, bracsign(right, 0), sublen[2], sublen[3]);
658 box_afterput(box, T_RIGHT);
660 blen_rm(sublen);
663 /* construct a radical with height at least len and width wd in dst register */
664 static void sqrt_rad(int dst, int len, int wd)
666 char *sizes[NSIZES] = {NULL};
667 int srlen[4];
668 int rnlen[4];
669 int sr_sz = nregmk();
670 int wd_diff = nregmk(); /* if wd is shorter than \(rn */
671 int sr_rx = nregmk(); /* the right-most horizontal position of \(sr */
672 int rn_dx = nregmk(); /* horizontal displacement necessary for \(rn */
673 int len2 = nregmk();
674 int rad = sregmk();
675 char *top = NULL, *mid = NULL, *bot = NULL, *cen;
676 printf(".nr %s 0%s/2*11/10\n", nregname(len2), nreg(len));
677 printf(".ds %s \"\n", sregname(rad));
678 /* selecting a radical of the appropriate size */
679 def_pieces("\\(sr", &top, &mid, &bot, &cen);
680 def_sizes("\\(sr", sizes);
681 box_bracketsel(rad, len2, len2, sizes, 0, 0);
682 /* constructing the bracket if needed */
683 if (mid) {
684 printf(".if \\w'%s' ", mid);
685 printf(".if '%s'' \\{\\\n", sreg(rad));
686 box_bracketmk(rad, len2, top, mid, bot, NULL);
687 printf(". \\}\n");
689 /* enlarging \(sr if no suitable glyph was found */
690 printf(".if '%s'' \\{\\\n", sreg(rad));
691 blen_mk("\\(sr", srlen);
692 printf(".ie %s<(%s+%s) .nr %s 0\\n(.s\n",
693 nreg(len), nreg(srlen[2]), nreg(srlen[3]), nregname(sr_sz));
694 printf(".el .nr %s 0%s*\\n(.s/(%s+%s-(%dm/100u))+1\n",
695 nregname(sr_sz), nreg(len),
696 nreg(srlen[2]), nreg(srlen[3]), e_rulethickness);
697 printf(".ps %s\n", nreg(sr_sz));
698 printf(".ds %s \"\\(sr\n", sregname(rad));
699 blen_rm(srlen);
700 printf(". \\}\n");
701 /* adding the handle */
702 blen_mk(sreg(rad), srlen);
703 printf(".nr %s \\n[bburx]\n", nregname(sr_rx));
704 blen_mk("\\(rn", rnlen);
705 printf(".nr %s 0%s-\\n[bbllx]-(%dm/100u)\n",
706 nregname(rn_dx), nreg(sr_rx), e_rulethickness);
707 printf(".nr %s 0\n", nregname(wd_diff));
708 printf(".if %s<%s .nr %s 0%s-%s\n",
709 nreg(wd), nreg(rnlen[0]),
710 nregname(wd_diff), nreg(rnlen[0]), nreg(wd));
711 /* output the radical; align the top of the radical to the baseline */
712 printf(".ds %s \"\\s[\\n(.s]\\f[\\n(.f]"
713 "\\v'%su'\\h'%su'\\l'%su+%su\\(rn'\\h'-%su'\\v'-%su'"
714 "\\h'-%su-%su'\\v'%su'%s\\v'-%su'\\h'%su+%su'\n",
715 nregname(dst),
716 nreg(rnlen[2]), nreg(rn_dx), nreg(wd), nreg(wd_diff),
717 nreg(rn_dx), nreg(rnlen[2]), nreg(wd), nreg(wd_diff),
718 nreg(srlen[2]), sreg(rad), nreg(srlen[2]), nreg(wd), nreg(wd_diff));
719 blen_rm(srlen);
720 blen_rm(rnlen);
721 nregrm(sr_sz);
722 nregrm(wd_diff);
723 nregrm(sr_rx);
724 nregrm(rn_dx);
725 sregrm(rad);
728 void box_sqrt(struct box *box, struct box *sub)
730 int sublen[4];
731 int radlen[4];
732 int rad = sregmk();
733 int rad_rise = nregmk();
734 int min_ht = nregmk();
735 box_italiccorrection(sub);
736 box_beforeput(box, T_ORD);
737 blen_mk(box_toreg(sub), sublen);
738 printf(".ps %s\n", nreg(box->szreg));
739 /* 11 */
740 printf(".nr %s 0%s+%s+(2*%dm/100u)+(%dm/100u/4)\n",
741 nregname(min_ht), nreg(sublen[2]), nreg(sublen[3]),
742 e_rulethickness,
743 TS_DX(box->style) ? e_xheight : e_rulethickness);
744 sqrt_rad(rad, min_ht, sublen[0]);
745 blen_mk(sreg(rad), radlen);
746 printf(".nr %s 0(%dm/100u)+(%dm/100u/4)\n",
747 nregname(rad_rise), e_rulethickness,
748 TS_DX(box->style) ? e_xheight : e_rulethickness);
749 printf(".if %s>(%s+%s+%s) .nr %s (%s+%s-%s-%s)/2\n",
750 nreg(radlen[3]), nreg(sublen[2]), nreg(sublen[3]),
751 nreg(rad_rise), nregname(rad_rise),
752 nreg(rad_rise), nreg(radlen[3]), nreg(sublen[2]),
753 nreg(sublen[3]));
754 printf(".nr %s +%s\n", nregname(rad_rise), nreg(sublen[2]));
755 /* output the radical */
756 box_putf(box, "\\v'-%su'%s\\v'%su'\\h'-%su'%s",
757 nreg(rad_rise), sreg(rad), nreg(rad_rise),
758 nreg(sublen[0]), box_toreg(sub));
759 box_afterput(box, T_ORD);
760 box_toreg(box);
761 blen_rm(sublen);
762 blen_rm(radlen);
763 sregrm(rad);
764 nregrm(rad_rise);
765 nregrm(min_ht);
768 void box_bar(struct box *box)
770 int box_wd = nregmk();
771 int box_ht = nregmk();
772 int bar_wd = nregmk();
773 int bar_dp = nregmk();
774 int bar_rise = nregmk();
775 box_italiccorrection(box);
776 printf(".ps %s\n", nreg(box->szreg));
777 tok_len("\\(ru", bar_wd, 0, 0, bar_dp);
778 tok_dim(box_toreg(box), box_wd, box_ht, 0);
779 printf(".if %su<(%dm/100u) .nr %s 0%dm/100u\n",
780 nreg(box_ht), e_xheight, nregname(box_ht), e_xheight);
781 printf(".nr %s 0%su+%su+(3*%dm/100u)\n",
782 nregname(bar_rise), nreg(box_ht),
783 nreg(bar_dp), e_rulethickness);
784 box_putf(box, "\\v'-%su'\\s%s\\f[\\n(.f]\\l'-%su\\(ru'\\v'%su'",
785 nreg(bar_rise), escarg(nreg(box->szreg)),
786 nreg(box_wd), nreg(bar_rise));
787 nregrm(box_wd);
788 nregrm(box_ht);
789 nregrm(bar_wd);
790 nregrm(bar_dp);
791 nregrm(bar_rise);
794 void box_accent(struct box *box, char *c)
796 int box_wd = nregmk();
797 int box_ht = nregmk();
798 int ac_rise = nregmk();
799 int ac_wd = nregmk();
800 int ac_dp = nregmk();
801 box_italiccorrection(box);
802 printf(".ps %s\n", nreg(box->szreg));
803 tok_len(c, ac_wd, 0, 0, ac_dp);
804 tok_dim(box_toreg(box), box_wd, box_ht, 0);
805 printf(".if %su<(%dm/100u) .nr %s 0%dm/100u\n",
806 nreg(box_ht), e_xheight, nregname(box_ht), e_xheight);
807 printf(".nr %s 0%su+%su+(%sp*10u/100u)\n",
808 nregname(ac_rise), nreg(box_ht),
809 nreg(ac_dp), nreg(box->szreg));
810 box_putf(box, "\\v'-%su'\\h'-%su-%su/2u'\\s%s\\f[\\n(.f]%s\\h'%su-%su/2u'\\v'%su'",
811 nreg(ac_rise), nreg(box_wd), nreg(ac_wd),
812 escarg(nreg(box->szreg)), c, nreg(box_wd),
813 nreg(ac_wd), nreg(ac_rise));
814 nregrm(box_wd);
815 nregrm(box_ht);
816 nregrm(ac_rise);
817 nregrm(ac_wd);
818 nregrm(ac_dp);
821 void box_under(struct box *box)
823 int box_wd = nregmk();
824 int box_dp = nregmk();
825 int bar_wd = nregmk();
826 int bar_ht = nregmk();
827 int bar_fall = nregmk();
828 box_italiccorrection(box);
829 printf(".ps %s\n", nreg(box->szreg));
830 tok_len("\\(ul", bar_wd, 0, bar_ht, 0);
831 tok_dim(box_toreg(box), box_wd, 0, box_dp);
832 printf(".if %s<0 .nr %s 0\n", nreg(box_dp), nregname(box_dp));
833 printf(".nr %s 0%su+%su+(3*%dm/100u)\n",
834 nregname(bar_fall), nreg(box_dp),
835 nreg(bar_ht), e_rulethickness);
836 box_putf(box, "\\v'%su'\\s%s\\f[\\n(.f]\\l'-%su\\(ul'\\v'-%su'",
837 nreg(bar_fall), escarg(nreg(box->szreg)),
838 nreg(box_wd), nreg(bar_fall));
839 nregrm(box_wd);
840 nregrm(box_dp);
841 nregrm(bar_wd);
842 nregrm(bar_ht);
843 nregrm(bar_fall);
846 char *box_toreg(struct box *box)
848 if (!box->reg) {
849 box->reg = sregmk();
850 printf(".ds %s \"%s\n", sregname(box->reg), box_buf(box));
852 return sreg(box->reg);
855 int box_empty(struct box *box)
857 return !strlen(box_buf(box));
860 void box_vcenter(struct box *box, struct box *sub)
862 int wd = nregmk();
863 int ht = nregmk();
864 int dp = nregmk();
865 int fall = nregmk();
866 box_beforeput(box, sub->tbeg);
867 tok_dim(box_toreg(sub), wd, ht, dp);
868 printf(".nr %s 0-%s+%s/2-(%sp*%du/100u)\n", nregname(fall),
869 nreg(dp), nreg(ht), nreg(box->szreg), e_axisheight);
870 box_putf(box, "\\v'%su'%s\\v'-%su'",
871 nreg(fall), box_toreg(sub), nreg(fall));
872 box_toreg(box);
873 box_afterput(box, sub->tcur);
874 nregrm(wd);
875 nregrm(ht);
876 nregrm(dp);
877 nregrm(fall);
880 /* include line-space requests */
881 void box_vertspace(struct box *box)
883 int box_wd = nregmk();
884 int htroom = nregmk();
885 int dproom = nregmk();
886 box_italiccorrection(box);
887 /* amount of room available before and after this line */
888 printf(".nr %s 0+\\n(.vu-%sp+(%sp*%du/100u)\n",
889 nregname(htroom), nreg(box->szreg),
890 nreg(box->szreg), e_bodyheight);
891 printf(".nr %s 0+\\n(.vu-%sp+(%sp*%du/100u)\n",
892 nregname(dproom), nreg(box->szreg),
893 nreg(box->szreg), e_bodydepth);
894 /* appending \x requests */
895 tok_dim(box_toreg(box), box_wd, 0, 0);
896 printf(".if -\\n[bbury]>%s .as %s \"\\x'\\n[bbury]u+%su'\n",
897 nreg(htroom), sregname(box->reg), nreg(htroom));
898 printf(".if \\n[bblly]>%s .as %s \"\\x'\\n[bblly]u-%su'\n",
899 nreg(dproom), sregname(box->reg), nreg(dproom));
900 nregrm(box_wd);
901 nregrm(htroom);
902 nregrm(dproom);
905 /* put the current width to the given number register */
906 void box_markpos(struct box *box, char *reg)
908 box->tomark = reg;
911 /* initialize the length of a pile or column of a matrix */
912 static void box_colinit(struct box **pile, int n,
913 int plen[][4], int wd, int ht)
915 int i;
916 for (i = 0; i < n; i++)
917 if (pile[i])
918 box_italiccorrection(pile[i]);
919 for (i = 0; i < n; i++)
920 blen_mk(pile[i] ? box_toreg(pile[i]) : "", plen[i]);
921 printf(".nr %s 0%s\n", nregname(wd), nreg(plen[0][0]));
922 printf(".nr %s 0%s\n", nregname(ht), nreg(plen[0][2]));
923 /* finding the maximum width */
924 for (i = 1; i < n; i++) {
925 printf(".if %s>%s .nr %s 0+%s\n",
926 nreg(plen[i][0]), nreg(wd),
927 nregname(wd), nreg(plen[i][0]));
929 /* finding the maximum height (vertical length) */
930 for (i = 1; i < n; i++) {
931 printf(".if %s+%s>%s .nr %s 0+%s+%s\n",
932 nreg(plen[i - 1][3]), nreg(plen[i][2]), nreg(ht),
933 nregname(ht), nreg(plen[i - 1][3]), nreg(plen[i][2]));
935 /* maximum height and the depth of the last row */
936 printf(".if %s>%s .nr %s 0+%s\n",
937 nreg(plen[n - 1][3]), nreg(ht),
938 nregname(ht), nreg(plen[n - 1][3]));
941 /* append the give pile to box */
942 static void box_colput(struct box **pile, int n, struct box *box,
943 int adj, int plen[][4], int wd, int ht)
945 int i;
946 box_putf(box, "\\v'-%du*%su/2u'", n - 1, nreg(ht));
947 /* adding the entries */
948 for (i = 0; i < n; i++) {
949 if (adj == 'c')
950 box_putf(box, "\\h'%su-%su/2u'",
951 nreg(wd), nreg(plen[i][0]));
952 if (adj == 'r')
953 box_putf(box, "\\h'%su-%su'",
954 nreg(wd), nreg(plen[i][0]));
955 box_putf(box, "\\v'%su'%s", i ? nreg(ht) : "0",
956 pile[i] ? box_toreg(pile[i]) : "");
957 if (adj == 'l')
958 box_putf(box, "\\h'-%su'", nreg(plen[i][0]));
959 if (adj == 'c')
960 box_putf(box, "\\h'-%su+(%su-%su/2u)'",
961 nreg(wd), nreg(wd), nreg(plen[i][0]));
962 if (adj == 'r')
963 box_putf(box, "\\h'-%su'", nreg(wd));
965 box_putf(box, "\\v'-%du*%su/2u'\\h'%su'", n - 1, nreg(ht), nreg(wd));
968 /* free the registers allocated for this pile */
969 static void box_coldone(struct box **pile, int n, int plen[][4])
971 int i;
972 for (i = 0; i < n; i++)
973 blen_rm(plen[i]);
976 /* calculate the number of entries in the given pile */
977 static int box_colnrows(struct box *cols[])
979 int n = 0;
980 while (n < NPILES && cols[n])
981 n++;
982 return n;
985 void box_pile(struct box *box, struct box **pile, int adj, int rowspace)
987 int plen[NPILES][4];
988 int max_wd = nregmk();
989 int max_ht = nregmk();
990 int n = box_colnrows(pile);
991 box_beforeput(box, T_INNER);
992 box_colinit(pile, n, plen, max_wd, max_ht);
993 /* inserting spaces between entries */
994 printf(".if %s<(%sp*%du/100u) .nr %s (%sp*%du/100u)\n",
995 nreg(max_ht), nreg(box->szreg), e_baselinesep,
996 nregname(max_ht), nreg(box->szreg), e_baselinesep);
997 if (rowspace)
998 printf(".nr %s +(%sp*%du/100u)\n",
999 nregname(max_ht), nreg(box->szreg), rowspace);
1000 /* adding the entries */
1001 box_colput(pile, n, box, adj, plen, max_wd, max_ht);
1002 box_coldone(pile, n, plen);
1003 box_afterput(box, T_INNER);
1004 box_toreg(box);
1005 nregrm(max_wd);
1006 nregrm(max_ht);
1009 void box_matrix(struct box *box, int ncols, struct box *cols[][NPILES],
1010 int *adj, int colspace, int rowspace)
1012 int plen[NPILES][NPILES][4];
1013 int wd[NPILES];
1014 int ht[NPILES];
1015 int max_ht = nregmk();
1016 int max_wd = nregmk();
1017 int nrows = 0;
1018 int i;
1019 box_beforeput(box, T_INNER);
1020 for (i = 0; i < ncols; i++)
1021 if (box_colnrows(cols[i]) > nrows)
1022 nrows = box_colnrows(cols[i]);
1023 for (i = 0; i < ncols; i++)
1024 wd[i] = nregmk();
1025 for (i = 0; i < ncols; i++)
1026 ht[i] = nregmk();
1027 /* initializing the columns */
1028 for (i = 0; i < ncols; i++)
1029 box_colinit(cols[i], nrows, plen[i], wd[i], ht[i]);
1030 /* finding the maximum width and height */
1031 printf(".nr %s 0%s\n", nregname(max_wd), nreg(wd[0]));
1032 printf(".nr %s 0%s\n", nregname(max_ht), nreg(ht[0]));
1033 for (i = 1; i < ncols; i++) {
1034 printf(".if %s>%s .nr %s 0+%s\n",
1035 nreg(wd[i]), nreg(max_wd),
1036 nregname(max_wd), nreg(wd[i]));
1038 for (i = 1; i < ncols; i++) {
1039 printf(".if %s>%s .nr %s 0+%s\n",
1040 nreg(ht[i]), nreg(max_ht),
1041 nregname(max_ht), nreg(ht[i]));
1043 /* inserting spaces between rows */
1044 printf(".if %s<(%sp*%du/100u) .nr %s (%sp*%du/100u)\n",
1045 nreg(max_ht), nreg(box->szreg), e_baselinesep,
1046 nregname(max_ht), nreg(box->szreg), e_baselinesep);
1047 if (rowspace)
1048 printf(".nr %s +(%sp*%du/100u)\n",
1049 nregname(max_ht), nreg(box->szreg), rowspace);
1050 /* printing the columns */
1051 for (i = 0; i < ncols; i++) {
1052 if (i) /* space between columns */
1053 box_putf(box, "\\h'%sp*%du/100u'",
1054 nreg(box->szreg), e_columnsep + colspace);
1055 box_colput(cols[i], nrows, box, adj[i],
1056 plen[i], max_wd, max_ht);
1058 box_afterput(box, T_INNER);
1059 box_toreg(box);
1060 for (i = 0; i < ncols; i++)
1061 box_coldone(cols[i], nrows, plen[i]);
1062 for (i = 0; i < ncols; i++)
1063 nregrm(ht[i]);
1064 for (i = 0; i < ncols; i++)
1065 nregrm(wd[i]);
1066 nregrm(max_wd);
1067 nregrm(max_ht);