Makefile: compatibility with openbsd
[neateqn.git] / box.c
blob33b75063778edff47d28c3d47f76295d0bdec3ab
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 if (sub)
225 box_italiccorrection(sub);
226 if (sup)
227 box_italiccorrection(sup);
228 if (sub)
229 tok_dim(box_toreg(box), box_wdnoic, 0, 0);
230 box_italiccorrection(box);
231 printf(".ps %s\n", nreg(box->szreg));
232 tok_dim(box_toreg(box), box_wd, box_ht, box_dp);
233 box_putf(box, "\\h'5m/100u'");
234 if (sup) {
235 tok_dim(box_toreg(sup), sup_wd, 0, sup_dp);
236 /* 18a */
237 printf(".nr %s 0%su-(%dm/100u)\n",
238 nregname(sup_rise), nreg(box_ht), e_supdrop);
239 /* 18c */
240 printf(".if %s<(%dm/100u) .nr %s (%dm/100u)\n",
241 nreg(sup_rise), box_suprise(box),
242 nregname(sup_rise), box_suprise(box));
243 printf(".if %s<(%s+(%dm/100u/4)) .nr %s 0%s+(%dm/100u/4)\n",
244 nreg(sup_rise), nreg(sup_dp), e_xheight,
245 nregname(sup_rise), nreg(sup_dp), e_xheight);
247 if (sub) {
248 tok_dim(box_toreg(sub), sub_wd, sub_ht, 0);
249 /* 18a */
250 printf(".nr %s 0%su+(%dm/100u)\n",
251 nregname(sub_fall), nreg(box_dp), e_subdrop);
253 if (sub && !sup) {
254 /* 18b */
255 printf(".if %s<(%dm/100u) .nr %s (%dm/100u)\n",
256 nreg(sub_fall), e_sub1,
257 nregname(sub_fall), e_sub1);
258 printf(".if %s<(%s-(%dm/100u*4/5)) .nr %s 0%s-(%dm/100u*4/5)\n",
259 nreg(sub_fall), nreg(sub_ht), e_xheight,
260 nregname(sub_fall), nreg(sub_ht), e_xheight);
262 if (sub && sup) {
263 /* 18d */
264 printf(".if %s<(%dm/100u) .nr %s (%dm/100u)\n",
265 nreg(sub_fall), e_sub2,
266 nregname(sub_fall), e_sub2);
267 /* 18e */
268 printf(".if (%s-%s)-(%s-%s)<(%dm/100u*4) \\{\\\n",
269 nreg(sup_rise), nreg(sup_dp),
270 nreg(sub_ht), nreg(sub_fall), e_rulethickness);
271 printf(".nr %s (%dm/100u*4)+%s-(%s-%s)\n",
272 nregname(sub_fall), e_rulethickness,
273 nreg(sub_ht), nreg(sup_rise), nreg(sup_dp));
274 printf(".nr %s (%dm/100u*4/5)-(%s-%s)\n",
275 nregname(tmp_18e), e_xheight,
276 nreg(sup_rise), nreg(sup_dp));
277 printf(".if %s>0 .nr %s +%s\n",
278 nreg(tmp_18e), nregname(sup_rise), nreg(tmp_18e));
279 printf(".if %s>0 .nr %s -%s \\}\n",
280 nreg(tmp_18e), nregname(sub_fall), nreg(tmp_18e));
282 /* writing the superscript */
283 if (sup) {
284 box_putf(box, "\\v'-%su'%s\\v'%su'",
285 nreg(sup_rise), box_toreg(sup), nreg(sup_rise));
286 if (sub)
287 box_putf(box, "\\h'-%su'", nreg(sup_wd));
289 /* writing the subscript */
290 if (sub) {
291 /* subscript correction */
292 printf(".nr %s -(%s-%s)/2\n", nregname(sub_wd),
293 nreg(box_wd), nreg(box_wdnoic));
294 box_putf(box, "\\h'-(%su-%su)/2u'",
295 nreg(box_wd), nreg(box_wdnoic));
296 box_putf(box, "\\v'%su'%s\\v'-%su'",
297 nreg(sub_fall), box_toreg(sub), nreg(sub_fall));
298 if (sup) {
299 box_putf(box, "\\h'-%su'", nreg(sub_wd));
300 roff_max(all_wd, sub_wd, sup_wd);
301 box_putf(box, "\\h'+%su'", nreg(all_wd));
304 box_putf(box, "\\h'%dm/100u'", e_scriptspace);
305 nregrm(box_wd);
306 nregrm(box_wdnoic);
307 nregrm(box_dp);
308 nregrm(box_ht);
309 nregrm(sub_wd);
310 nregrm(sup_wd);
311 nregrm(all_wd);
312 nregrm(sup_dp);
313 nregrm(sub_ht);
314 nregrm(sup_rise);
315 nregrm(sub_fall);
316 nregrm(tmp_18e);
319 void box_from(struct box *box, struct box *lim, struct box *llim, struct box *ulim)
321 int lim_wd = nregmk(); /* box's width */
322 int lim_ht = nregmk(); /* box's height */
323 int lim_dp = nregmk(); /* box's depth */
324 int llim_wd = nregmk(); /* llim's width */
325 int ulim_wd = nregmk(); /* ulim's width */
326 int ulim_dp = nregmk(); /* ulim's depth */
327 int llim_ht = nregmk(); /* llim's height */
328 int ulim_rise = nregmk(); /* the position of ulim */
329 int llim_fall = nregmk(); /* the position of llim */
330 int all_wd = nregmk(); /* the width of all */
331 box_italiccorrection(lim);
332 box_beforeput(box, T_BIGOP);
333 tok_dim(box_toreg(lim), lim_wd, lim_ht, lim_dp);
334 printf(".ps %s\n", nreg(box->szreg));
335 if (ulim)
336 tok_dim(box_toreg(ulim), ulim_wd, 0, ulim_dp);
337 if (llim)
338 tok_dim(box_toreg(llim), llim_wd, llim_ht, 0);
339 if (ulim && llim)
340 roff_max(all_wd, llim_wd, ulim_wd);
341 else
342 printf(".nr %s %s\n", nregname(all_wd),
343 ulim ? nreg(ulim_wd) : nreg(llim_wd));
344 printf(".if %s>%s .nr %s 0%s\n",
345 nreg(lim_wd), nreg(all_wd),
346 nregname(all_wd), nreg(lim_wd));
347 box_putf(box, "\\h'%su-%su/2u'", nreg(all_wd), nreg(lim_wd));
348 box_merge(box, lim);
349 box_putf(box, "\\h'-%su/2u'", nreg(lim_wd));
350 if (ulim) {
351 /* 13a */
352 printf(".nr %s (%dm/100u)-%s\n",
353 nregname(ulim_rise), e_bigopspacing3, nreg(ulim_dp));
354 printf(".if %s<(%dm/100u) .nr %s (%dm/100u)\n",
355 nreg(ulim_rise), e_bigopspacing1,
356 nregname(ulim_rise), e_bigopspacing1);
357 printf(".nr %s +%s+%s\n",
358 nregname(ulim_rise), nreg(lim_ht), nreg(ulim_dp));
359 box_putf(box, "\\h'-%su/2u'\\v'-%su'%s\\v'%su'\\h'-%su/2u'",
360 nreg(ulim_wd), nreg(ulim_rise), box_toreg(ulim),
361 nreg(ulim_rise), nreg(ulim_wd));
363 if (llim) {
364 /* 13a */
365 printf(".nr %s (%dm/100u)-%s\n",
366 nregname(llim_fall), e_bigopspacing4, nreg(llim_ht));
367 printf(".if %s<(%dm/100u) .nr %s (%dm/100u)\n",
368 nreg(llim_fall), e_bigopspacing2,
369 nregname(llim_fall), e_bigopspacing2);
370 printf(".nr %s +%s+%s\n",
371 nregname(llim_fall), nreg(lim_dp), nreg(llim_ht));
372 box_putf(box, "\\h'-%su/2u'\\v'%su'%s\\v'-%su'\\h'-%su/2u'",
373 nreg(llim_wd), nreg(llim_fall), box_toreg(llim),
374 nreg(llim_fall), nreg(llim_wd));
376 box_putf(box, "\\h'%su/2u'", nreg(all_wd));
377 box_afterput(box, T_BIGOP);
378 nregrm(lim_wd);
379 nregrm(lim_ht);
380 nregrm(lim_dp);
381 nregrm(llim_wd);
382 nregrm(ulim_wd);
383 nregrm(ulim_dp);
384 nregrm(llim_ht);
385 nregrm(ulim_rise);
386 nregrm(llim_fall);
387 nregrm(all_wd);
390 /* return the width of s; len is the height plus depth */
391 static void tok_len(char *s, int wd, int len, int ht, int dp)
393 printf(".nr %s 0\\w'%s'\n", nregname(wd), s);
394 if (len)
395 printf(".nr %s 0\\n[bblly]-\\n[bbury]-2\n", nregname(len));
396 if (dp)
397 printf(".nr %s 0\\n[bblly]-1\n", nregname(dp));
398 if (ht)
399 printf(".nr %s 0-\\n[bbury]-1\n", nregname(ht));
402 /* len[0]: width, len[1]: vertical length, len[2]: height, len[3]: depth */
403 static void blen_mk(char *s, int len[4])
405 int i;
406 for (i = 0; i < 4; i++)
407 len[i] = nregmk();
408 tok_len(s, len[0], len[1], len[2], len[3]);
411 /* free the registers allocated with blen_mk() */
412 static void blen_rm(int len[4])
414 int i;
415 for (i = 0; i < 4; i++)
416 nregrm(len[i]);
419 /* build a fraction; the correct font should be set up beforehand */
420 void box_over(struct box *box, struct box *num, struct box *den)
422 int num_wd = nregmk();
423 int num_dp = nregmk();
424 int den_wd = nregmk();
425 int den_ht = nregmk();
426 int all_wd = nregmk();
427 int num_rise = nregmk();
428 int den_fall = nregmk();
429 int bar_wd = nregmk();
430 int bar_dp = nregmk();
431 int bar_ht = nregmk();
432 int bar_fall = nregmk();
433 int tmp_15d = nregmk();
434 int bargap = (TS_DX(box->style) ? 7 : 3) * e_rulethickness / 2;
435 box_beforeput(box, T_INNER);
436 box_italiccorrection(num);
437 box_italiccorrection(den);
438 tok_dim(box_toreg(num), num_wd, 0, num_dp);
439 tok_dim(box_toreg(den), den_wd, den_ht, 0);
440 roff_max(all_wd, num_wd, den_wd);
441 printf(".ps %s\n", nreg(box->szreg));
442 tok_len("\\(ru", bar_wd, 0, bar_ht, bar_dp);
443 /* 15b */
444 printf(".nr %s 0%dm/100u\n",
445 nregname(num_rise), TS_DX(box->style) ? e_num1 : e_num2);
446 printf(".nr %s 0%dm/100u\n",
447 nregname(den_fall), TS_DX(box->style) ? e_denom1 : e_denom2);
448 /* 15d */
449 printf(".nr %s (%s-%s)-((%dm/100u)+(%dm/100u/2))\n",
450 nregname(tmp_15d), nreg(num_rise), nreg(num_dp),
451 e_axisheight, e_rulethickness);
452 printf(".if %s<(%dm/100u) .nr %s +(%dm/100u)-%s\n",
453 nreg(tmp_15d), bargap, nregname(num_rise),
454 bargap, nreg(tmp_15d));
455 printf(".nr %s ((%dm/100u)-(%dm/100u/2))-(%s-%s)\n",
456 nregname(tmp_15d), e_axisheight, e_rulethickness,
457 nreg(den_ht), nreg(den_fall));
458 printf(".if %s<(%dm/100u) .nr %s +(%dm/100u)-%s\n",
459 nreg(tmp_15d), bargap, nregname(den_fall),
460 bargap, nreg(tmp_15d));
461 /* calculating the vertical position of the bar */
462 printf(".nr %s 0-%s+%s/2-(%dm/100u)\n",
463 nregname(bar_fall), nreg(bar_dp),
464 nreg(bar_ht), e_axisheight);
465 /* making the bar longer */
466 printf(".nr %s +2*(%dm/100u)\n",
467 nregname(all_wd), e_overhang);
468 /* null delimiter space */
469 box_putf(box, "\\h'%sp*%du/100u'",nreg(box->szreg), e_nulldelim);
470 /* drawing the bar */
471 box_putf(box, "\\v'%su'\\f[\\n(.f]\\s[%s]\\l'%su'\\v'-%su'\\h'-%su/2u'",
472 nreg(bar_fall), nreg(box->szreg), nreg(all_wd),
473 nreg(bar_fall), nreg(all_wd));
474 /* output the numerator */
475 box_putf(box, "\\h'-%su/2u'", nreg(num_wd));
476 box_putf(box, "\\v'-%su'%s\\v'%su'",
477 nreg(num_rise), box_toreg(num), nreg(num_rise));
478 box_putf(box, "\\h'-%su/2u'", nreg(num_wd));
479 /* output the denominator */
480 box_putf(box, "\\h'-%su/2u'", nreg(den_wd));
481 box_putf(box, "\\v'%su'%s\\v'-%su'",
482 nreg(den_fall), box_toreg(den), nreg(den_fall));
483 box_putf(box, "\\h'(-%su+%su)/2u'", nreg(den_wd), nreg(all_wd));
484 box_putf(box, "\\h'%sp*%du/100u'",nreg(box->szreg), e_nulldelim);
485 box_afterput(box, T_INNER);
486 box_toreg(box);
487 nregrm(num_wd);
488 nregrm(num_dp);
489 nregrm(den_wd);
490 nregrm(den_ht);
491 nregrm(all_wd);
492 nregrm(num_rise);
493 nregrm(den_fall);
494 nregrm(bar_wd);
495 nregrm(bar_dp);
496 nregrm(bar_ht);
497 nregrm(bar_fall);
498 nregrm(tmp_15d);
501 /* choose the smallest bracket among br[], large enough for \n(ht+\n(dp */
502 static void box_bracketsel(int dst, int ht, int dp, char **br, int any, int both)
504 int i;
505 for (i = 0; br[i]; i++) {
506 printf(".if '%s'' ", sreg(dst));
507 printf(".if \\w'%s' ", br[i]); /* is this bracket available? */
508 if (both) { /* check both the height and the depth */
509 printf(".if (%s-(%dm/100)*2)<=(-\\n[bbury]+\\n[bblly]+(%dm/100*2)) ",
510 nreg(ht), e_rulethickness, e_axisheight);
511 printf(".if (%s*2)<=(-\\n[bbury]+\\n[bblly]-(%dm/100*2)) ",
512 nreg(dp), e_axisheight);
513 } else {
514 printf(".if (%s+%s)<=(-\\n[bbury]+\\n[bblly]) ", nreg(ht), nreg(dp));
516 printf(".ds %s \"%s\n", sregname(dst), br[i]);
518 if (any) /* choose the largest bracket, if any is 1 */
519 while (--i >= 0)
520 printf(".if '%s'' .if \\w'%s' .ds %s \"%s\n",
521 sreg(dst), br[i], sregname(dst), br[i]);
524 /* build a bracket using the provided pieces */
525 static void box_bracketmk(int dst, int len,
526 char *top, char *mid, char *bot, char *cen)
528 int toplen[4];
529 int midlen[4];
530 int botlen[4];
531 int cenlen[4];
532 int mid_cnt = nregmk(); /* number of mid glyphs to insert */
533 int mid_cur = nregmk(); /* the number of mid glyphs inserted */
534 int cen_pos = nregmk();
535 int buildmacro = sregmk();
536 blen_mk(top, toplen);
537 blen_mk(mid, midlen);
538 blen_mk(bot, botlen);
539 if (cen)
540 blen_mk(cen, cenlen);
541 /* the number of mid tokens necessary to cover sub */
542 if (!cen) {
543 printf(".nr %s %s*2-%s-%s*11/10/%s\n",
544 nregname(mid_cnt), nreg(len),
545 nreg(toplen[1]), nreg(botlen[1]), nreg(midlen[1]));
546 printf(".if %s<0 .nr %s 0\n", nreg(mid_cnt), nregname(mid_cnt));
547 } else { /* for brackets with a center like { */
548 printf(".nr %s %s-(%s+%s+%s/2)*11/10/%s\n",
549 nregname(cen_pos), nreg(len), nreg(cenlen[1]),
550 nreg(toplen[1]), nreg(botlen[1]), nreg(midlen[1]));
551 printf(".if %s<0 .nr %s 0\n", nreg(cen_pos), nregname(cen_pos));
552 printf(".nr %s 0%s*2\n", nregname(mid_cnt), nreg(cen_pos));
554 /* the macro to create the bracket; escaping backslashes */
555 printf(".de %s\n", sregname(buildmacro));
556 if (cen) /* inserting cen */
557 printf(".if \\%s=\\%s .as %s \"\\v'-\\%su'%s\\h'-\\%su'\\v'-\\%su'\n",
558 nreg(mid_cur), nreg(cen_pos), sregname(dst),
559 nreg(cenlen[3]), cen, nreg(cenlen[0]), nreg(cenlen[2]));
560 printf(".if \\%s<\\%s .as %s \"\\v'-\\%su'%s\\h'-\\%su'\\v'-\\%su'\n",
561 nreg(mid_cur), nreg(mid_cnt),
562 sregname(dst), nreg(midlen[3]),
563 mid, nreg(midlen[0]), nreg(midlen[2]));
564 printf(".if \\\\n+%s<\\%s .%s\n",
565 escarg(nregname(mid_cur)), nreg(mid_cnt), sregname(buildmacro));
566 printf("..\n");
567 /* constructing the bracket */
568 printf(".ds %s \"\\v'-%su'%s\\h'-%su'\\v'-%su'\n",
569 sregname(dst), nreg(botlen[3]),
570 bot, nreg(botlen[0]), nreg(botlen[2]));
571 printf(".nr %s 0 1\n", nregname(mid_cur));
572 printf(".%s\n", sregname(buildmacro));
573 printf(".as %s \"\\v'-%su'%s\\h'-%su'\\v'-%su'\n",
574 sregname(dst), nreg(toplen[3]), top,
575 nreg(toplen[0]), nreg(toplen[2]));
576 /* moving back vertically */
577 printf(".as %s \"\\v'%su*%su+%su+%su+%su'\n",
578 sregname(dst), nreg(mid_cnt), nreg(midlen[1]), nreg(botlen[1]),
579 nreg(toplen[1]), cen ? nreg(cenlen[1]) : "0");
580 /* moving right */
581 printf(".as %s \"\\h'%su'\n",
582 sregname(dst), cen ? nreg(cenlen[0]) : nreg(midlen[0]));
583 blen_rm(toplen);
584 blen_rm(midlen);
585 blen_rm(botlen);
586 if (cen)
587 blen_rm(cenlen);
588 nregrm(mid_cnt);
589 nregrm(mid_cur);
590 nregrm(cen_pos);
591 sregrm(buildmacro);
594 static void box_bracket(struct box *box, char *brac, int ht, int dp)
596 char *sizes[8] = {NULL};
597 char *top = NULL, *mid = NULL, *bot = NULL, *cen = NULL;
598 int dst = sregmk();
599 int len = nregmk();
600 int fall = nregmk();
601 int parlen[4];
602 roff_max(len, ht, dp);
603 def_sizes(brac, sizes);
604 printf(".ds %s \"\n", sregname(dst));
605 def_pieces(brac, &top, &mid, &bot, &cen);
606 box_bracketsel(dst, ht, dp, sizes, !mid, 1);
607 if (mid) {
608 printf(".if '%s'' \\{\\\n", sreg(dst));
609 box_bracketmk(dst, len, top, mid, bot, cen);
610 printf(". \\}\n");
612 /* calculating the total vertical length of the bracket */
613 blen_mk(sreg(dst), parlen);
614 /* calculating the amount the bracket should be moved downwards */
615 printf(".nr %s 0-%s+%s/2-(%sp*%du/100u)\n", nregname(fall),
616 nreg(parlen[3]), nreg(parlen[2]), nreg(box->szreg), e_axisheight);
617 /* printing the output */
618 box_putf(box, "\\f[\\n(.f]\\s[\\n(.s]\\v'%su'%s\\v'-%su'",
619 nreg(fall), sreg(dst), nreg(fall));
620 box_toreg(box);
621 blen_rm(parlen);
622 sregrm(dst);
623 nregrm(len);
624 nregrm(fall);
627 static char *bracsign(char *brac, int left)
629 if (brac[0] == 'c' && !strncmp("ceiling", brac, strlen(brac)))
630 return left ? "\\(lc" : "\\(rc";
631 if (brac[0] == 'f' && !strncmp("floor", brac, strlen(brac)))
632 return left ? "\\(lf" : "\\(rf";
633 if (brac[0] == '<' && brac[1] == '\0')
634 return "\\(la";
635 if (brac[0] == '>' && brac[1] == '\0')
636 return "\\(ra";
637 return brac;
640 /* build large brackets; the correct font should be set up beforehand */
641 void box_wrap(struct box *box, struct box *sub, char *left, char *right)
643 int sublen[4];
644 blen_mk(box_toreg(sub), sublen);
645 printf(".ps %s\n", nreg(box->szreg));
646 if (left) {
647 box_beforeput(box, T_LEFT);
648 box_bracket(box, bracsign(left, 1), sublen[2], sublen[3]);
649 box_afterput(box, T_LEFT);
651 box_merge(box, sub);
652 if (right) {
653 box_beforeput(box, T_RIGHT);
654 box_bracket(box, bracsign(right, 0), sublen[2], sublen[3]);
655 box_afterput(box, T_RIGHT);
657 blen_rm(sublen);
660 /* construct a radical with height at least len and width wd in dst register */
661 static void sqrt_rad(int dst, int len, int wd)
663 int srlen[4];
664 int rnlen[4];
665 int sr_sz = nregmk();
666 int wd_diff = nregmk(); /* if wd is shorter than \(rn */
667 int sr_rx = nregmk(); /* the right-most horizontal position of \(sr */
668 int rn_dx = nregmk(); /* horizontal displacement necessary for \(rn */
669 int len2 = nregmk();
670 int rad = sregmk();
671 char *top = NULL, *mid = NULL, *bot = NULL;
672 char **sizes;
673 printf(".nr %s 0%s/2*11/10\n", nregname(len2), nreg(len));
674 printf(".ds %s \"\n", sregname(rad));
675 /* selecting a radical of the appropriate size */
676 sizes = def_sqrtpieces(&top, &mid, &bot);
677 box_bracketsel(rad, len2, len2, sizes, 0, 0);
678 /* constructing the bracket if needed */
679 if (mid) {
680 printf(".if \\w'%s' ", mid);
681 printf(".if '%s'' \\{\\\n", sreg(rad));
682 box_bracketmk(rad, len2, top, mid, bot, NULL);
683 printf(". \\}\n");
685 /* enlarging \(sr if no suitable glyph was found */
686 printf(".if '%s'' \\{\\\n", sreg(rad));
687 blen_mk("\\(sr", srlen);
688 printf(".ie %s<(%s+%s) .nr %s 0\\n(.s\n",
689 nreg(len), nreg(srlen[2]), nreg(srlen[3]), nregname(sr_sz));
690 printf(".el .nr %s 0%s*\\n(.s/(%s+%s-(%dm/100u))+1\n",
691 nregname(sr_sz), nreg(len),
692 nreg(srlen[2]), nreg(srlen[3]), e_rulethickness);
693 printf(".ps %s\n", nreg(sr_sz));
694 printf(".ds %s \"\\(sr\n", sregname(rad));
695 blen_rm(srlen);
696 printf(". \\}\n");
697 /* adding the handle */
698 blen_mk(sreg(rad), srlen);
699 printf(".nr %s \\n[bburx]\n", nregname(sr_rx));
700 blen_mk("\\(rn", rnlen);
701 printf(".nr %s 0%s-\\n[bbllx]-(%dm/100u)\n",
702 nregname(rn_dx), nreg(sr_rx), e_rulethickness);
703 printf(".nr %s 0\n", nregname(wd_diff));
704 printf(".if %s<%s .nr %s 0%s-%s\n",
705 nreg(wd), nreg(rnlen[0]),
706 nregname(wd_diff), nreg(rnlen[0]), nreg(wd));
707 /* output the radical; align the top of the radical to the baseline */
708 printf(".ds %s \"\\s[\\n(.s]\\f[\\n(.f]"
709 "\\v'%su'\\h'%su'\\l'%su+%su\\(rn'\\h'-%su'\\v'-%su'"
710 "\\h'-%su-%su'\\v'%su'%s\\v'-%su'\\h'%su+%su'\n",
711 nregname(dst),
712 nreg(rnlen[2]), nreg(rn_dx), nreg(wd), nreg(wd_diff),
713 nreg(rn_dx), nreg(rnlen[2]), nreg(wd), nreg(wd_diff),
714 nreg(srlen[2]), sreg(rad), nreg(srlen[2]), nreg(wd), nreg(wd_diff));
715 blen_rm(srlen);
716 blen_rm(rnlen);
717 nregrm(sr_sz);
718 nregrm(wd_diff);
719 nregrm(sr_rx);
720 nregrm(rn_dx);
721 sregrm(rad);
724 void box_sqrt(struct box *box, struct box *sub)
726 int sublen[4];
727 int radlen[4];
728 int rad = sregmk();
729 int rad_rise = nregmk();
730 int min_ht = nregmk();
731 box_italiccorrection(sub);
732 box_beforeput(box, T_ORD);
733 blen_mk(box_toreg(sub), sublen);
734 printf(".ps %s\n", nreg(box->szreg));
735 /* 11 */
736 printf(".nr %s 0%s+%s+(2*%dm/100u)+(%dm/100u/4)\n",
737 nregname(min_ht), nreg(sublen[2]), nreg(sublen[3]),
738 e_rulethickness,
739 TS_DX(box->style) ? e_xheight : e_rulethickness);
740 sqrt_rad(rad, min_ht, sublen[0]);
741 blen_mk(sreg(rad), radlen);
742 printf(".nr %s 0(%dm/100u)+(%dm/100u/4)\n",
743 nregname(rad_rise), e_rulethickness,
744 TS_DX(box->style) ? e_xheight : e_rulethickness);
745 printf(".if %s>(%s+%s+%s) .nr %s (%s+%s-%s-%s)/2\n",
746 nreg(radlen[3]), nreg(sublen[2]), nreg(sublen[3]),
747 nreg(rad_rise), nregname(rad_rise),
748 nreg(rad_rise), nreg(radlen[3]), nreg(sublen[2]),
749 nreg(sublen[3]));
750 printf(".nr %s +%s\n", nregname(rad_rise), nreg(sublen[2]));
751 /* output the radical */
752 box_putf(box, "\\v'-%su'%s\\v'%su'\\h'-%su'%s",
753 nreg(rad_rise), sreg(rad), nreg(rad_rise),
754 nreg(sublen[0]), box_toreg(sub));
755 box_afterput(box, T_ORD);
756 box_toreg(box);
757 blen_rm(sublen);
758 blen_rm(radlen);
759 sregrm(rad);
760 nregrm(rad_rise);
761 nregrm(min_ht);
764 void box_bar(struct box *box)
766 int box_wd = nregmk();
767 int box_ht = nregmk();
768 int bar_wd = nregmk();
769 int bar_dp = nregmk();
770 int bar_rise = nregmk();
771 box_italiccorrection(box);
772 printf(".ps %s\n", nreg(box->szreg));
773 tok_len("\\(ru", bar_wd, 0, 0, bar_dp);
774 tok_dim(box_toreg(box), box_wd, box_ht, 0);
775 printf(".if %su<(%dm/100u) .nr %s 0%dm/100u\n",
776 nreg(box_ht), e_xheight, nregname(box_ht), e_xheight);
777 printf(".nr %s 0%su+%su+(3*%dm/100u)\n",
778 nregname(bar_rise), nreg(box_ht),
779 nreg(bar_dp), e_rulethickness);
780 box_putf(box, "\\v'-%su'\\s%s\\f[\\n(.f]\\l'-%su\\(ru'\\v'%su'",
781 nreg(bar_rise), escarg(nreg(box->szreg)),
782 nreg(box_wd), nreg(bar_rise));
783 nregrm(box_wd);
784 nregrm(box_ht);
785 nregrm(bar_wd);
786 nregrm(bar_dp);
787 nregrm(bar_rise);
790 void box_accent(struct box *box, char *c)
792 int box_wd = nregmk();
793 int box_ht = nregmk();
794 int ac_rise = nregmk();
795 int ac_wd = nregmk();
796 int ac_dp = nregmk();
797 box_italiccorrection(box);
798 printf(".ps %s\n", nreg(box->szreg));
799 tok_len(c, ac_wd, 0, 0, ac_dp);
800 tok_dim(box_toreg(box), box_wd, box_ht, 0);
801 printf(".if %su<(%dm/100u) .nr %s 0%dm/100u\n",
802 nreg(box_ht), e_xheight, nregname(box_ht), e_xheight);
803 printf(".nr %s 0%su+%su+(%sp*10u/100u)\n",
804 nregname(ac_rise), nreg(box_ht),
805 nreg(ac_dp), nreg(box->szreg));
806 box_putf(box, "\\v'-%su'\\h'-%su-%su/2u'\\s%s\\f[\\n(.f]%s\\h'%su-%su/2u'\\v'%su'",
807 nreg(ac_rise), nreg(box_wd), nreg(ac_wd),
808 escarg(nreg(box->szreg)), c, nreg(box_wd),
809 nreg(ac_wd), nreg(ac_rise));
810 nregrm(box_wd);
811 nregrm(box_ht);
812 nregrm(ac_rise);
813 nregrm(ac_wd);
814 nregrm(ac_dp);
817 void box_under(struct box *box)
819 int box_wd = nregmk();
820 int box_dp = nregmk();
821 int bar_wd = nregmk();
822 int bar_ht = nregmk();
823 int bar_fall = nregmk();
824 box_italiccorrection(box);
825 printf(".ps %s\n", nreg(box->szreg));
826 tok_len("\\(ul", bar_wd, 0, bar_ht, 0);
827 tok_dim(box_toreg(box), box_wd, 0, box_dp);
828 printf(".if %s<0 .nr %s 0\n", nreg(box_dp), nregname(box_dp));
829 printf(".nr %s 0%su+%su+(3*%dm/100u)\n",
830 nregname(bar_fall), nreg(box_dp),
831 nreg(bar_ht), e_rulethickness);
832 box_putf(box, "\\v'%su'\\s%s\\f[\\n(.f]\\l'-%su\\(ul'\\v'-%su'",
833 nreg(bar_fall), escarg(nreg(box->szreg)),
834 nreg(box_wd), nreg(bar_fall));
835 nregrm(box_wd);
836 nregrm(box_dp);
837 nregrm(bar_wd);
838 nregrm(bar_ht);
839 nregrm(bar_fall);
842 char *box_toreg(struct box *box)
844 if (!box->reg) {
845 box->reg = sregmk();
846 printf(".ds %s \"%s\n", sregname(box->reg), box_buf(box));
848 return sreg(box->reg);
851 int box_empty(struct box *box)
853 return !strlen(box_buf(box));
856 void box_vcenter(struct box *box, struct box *sub)
858 int wd = nregmk();
859 int ht = nregmk();
860 int dp = nregmk();
861 int fall = nregmk();
862 box_beforeput(box, sub->tbeg);
863 tok_dim(box_toreg(sub), wd, ht, dp);
864 printf(".nr %s 0-%s+%s/2-(%sp*%du/100u)\n", nregname(fall),
865 nreg(dp), nreg(ht), nreg(box->szreg), e_axisheight);
866 box_putf(box, "\\v'%su'%s\\v'-%su'",
867 nreg(fall), box_toreg(sub), nreg(fall));
868 box_toreg(box);
869 box_afterput(box, sub->tcur);
870 nregrm(wd);
871 nregrm(ht);
872 nregrm(dp);
873 nregrm(fall);
876 /* include line-space requests */
877 void box_vertspace(struct box *box)
879 int box_wd = nregmk();
880 int htroom = nregmk();
881 int dproom = nregmk();
882 box_italiccorrection(box);
883 /* amount of room available before and after this line */
884 printf(".nr %s 0+\\n(.vu-%sp+(%sp*%du/100u)\n",
885 nregname(htroom), nreg(box->szreg),
886 nreg(box->szreg), e_bodyheight);
887 printf(".nr %s 0+\\n(.vu-%sp+(%sp*%du/100u)\n",
888 nregname(dproom), nreg(box->szreg),
889 nreg(box->szreg), e_bodydepth);
890 /* appending \x requests */
891 tok_dim(box_toreg(box), box_wd, 0, 0);
892 printf(".if -\\n[bbury]>%s .as %s \"\\x'\\n[bbury]u+%su'\n",
893 nreg(htroom), sregname(box->reg), nreg(htroom));
894 printf(".if \\n[bblly]>%s .as %s \"\\x'\\n[bblly]u-%su'\n",
895 nreg(dproom), sregname(box->reg), nreg(dproom));
896 nregrm(box_wd);
897 nregrm(htroom);
898 nregrm(dproom);
901 /* put the current width to the given number register */
902 void box_markpos(struct box *box, char *reg)
904 box->tomark = reg;
907 /* initialize the length of a pile or column of a matrix */
908 static void box_colinit(struct box **pile, int n,
909 int plen[][4], int wd, int ht)
911 int i;
912 for (i = 0; i < n; i++)
913 if (pile[i])
914 box_italiccorrection(pile[i]);
915 for (i = 0; i < n; i++)
916 blen_mk(pile[i] ? box_toreg(pile[i]) : "", plen[i]);
917 printf(".nr %s 0%s\n", nregname(wd), nreg(plen[0][0]));
918 printf(".nr %s 0%s\n", nregname(ht), nreg(plen[0][2]));
919 /* finding the maximum width */
920 for (i = 1; i < n; i++) {
921 printf(".if %s>%s .nr %s 0+%s\n",
922 nreg(plen[i][0]), nreg(wd),
923 nregname(wd), nreg(plen[i][0]));
925 /* finding the maximum height (vertical length) */
926 for (i = 1; i < n; i++) {
927 printf(".if %s+%s>%s .nr %s 0+%s+%s\n",
928 nreg(plen[i - 1][3]), nreg(plen[i][2]), nreg(ht),
929 nregname(ht), nreg(plen[i - 1][3]), nreg(plen[i][2]));
931 /* maximum height and the depth of the last row */
932 printf(".if %s>%s .nr %s 0+%s\n",
933 nreg(plen[n - 1][3]), nreg(ht),
934 nregname(ht), nreg(plen[n - 1][3]));
937 /* append the give pile to box */
938 static void box_colput(struct box **pile, int n, struct box *box,
939 int adj, int plen[][4], int wd, int ht)
941 int i;
942 box_putf(box, "\\v'-%du*%su/2u'", n - 1, nreg(ht));
943 /* adding the entries */
944 for (i = 0; i < n; i++) {
945 if (adj == 'c')
946 box_putf(box, "\\h'%su-%su/2u'",
947 nreg(wd), nreg(plen[i][0]));
948 if (adj == 'r')
949 box_putf(box, "\\h'%su-%su'",
950 nreg(wd), nreg(plen[i][0]));
951 box_putf(box, "\\v'%su'%s", i ? nreg(ht) : "0",
952 pile[i] ? box_toreg(pile[i]) : "");
953 if (adj == 'l')
954 box_putf(box, "\\h'-%su'", nreg(plen[i][0]));
955 if (adj == 'c')
956 box_putf(box, "\\h'-%su+(%su-%su/2u)'",
957 nreg(wd), nreg(wd), nreg(plen[i][0]));
958 if (adj == 'r')
959 box_putf(box, "\\h'-%su'", nreg(wd));
961 box_putf(box, "\\v'-%du*%su/2u'\\h'%su'", n - 1, nreg(ht), nreg(wd));
964 /* free the registers allocated for this pile */
965 static void box_coldone(struct box **pile, int n, int plen[][4])
967 int i;
968 for (i = 0; i < n; i++)
969 blen_rm(plen[i]);
972 /* calculate the number of entries in the given pile */
973 static int box_colnrows(struct box *cols[])
975 int n = 0;
976 while (n < NPILES && cols[n])
977 n++;
978 return n;
981 void box_pile(struct box *box, struct box **pile, int adj, int rowspace)
983 int plen[NPILES][4];
984 int max_wd = nregmk();
985 int max_ht = nregmk();
986 int n = box_colnrows(pile);
987 box_beforeput(box, T_INNER);
988 box_colinit(pile, n, plen, max_wd, max_ht);
989 /* inserting spaces between entries */
990 printf(".if %s<(%sp*%du/100u) .nr %s (%sp*%du/100u)\n",
991 nreg(max_ht), nreg(box->szreg), e_baselinesep,
992 nregname(max_ht), nreg(box->szreg), e_baselinesep);
993 if (rowspace)
994 printf(".nr %s +(%sp*%du/100u)\n",
995 nregname(max_ht), nreg(box->szreg), rowspace);
996 /* adding the entries */
997 box_colput(pile, n, box, adj, plen, max_wd, max_ht);
998 box_coldone(pile, n, plen);
999 box_afterput(box, T_INNER);
1000 box_toreg(box);
1001 nregrm(max_wd);
1002 nregrm(max_ht);
1005 void box_matrix(struct box *box, int ncols, struct box *cols[][NPILES],
1006 int *adj, int colspace, int rowspace)
1008 int plen[NPILES][NPILES][4];
1009 int wd[NPILES];
1010 int ht[NPILES];
1011 int max_ht = nregmk();
1012 int max_wd = nregmk();
1013 int nrows = 0;
1014 int i;
1015 box_beforeput(box, T_INNER);
1016 for (i = 0; i < ncols; i++)
1017 if (box_colnrows(cols[i]) > nrows)
1018 nrows = box_colnrows(cols[i]);
1019 for (i = 0; i < ncols; i++)
1020 wd[i] = nregmk();
1021 for (i = 0; i < ncols; i++)
1022 ht[i] = nregmk();
1023 /* initializing the columns */
1024 for (i = 0; i < ncols; i++)
1025 box_colinit(cols[i], nrows, plen[i], wd[i], ht[i]);
1026 /* finding the maximum width and height */
1027 printf(".nr %s 0%s\n", nregname(max_wd), nreg(wd[0]));
1028 printf(".nr %s 0%s\n", nregname(max_ht), nreg(ht[0]));
1029 for (i = 1; i < ncols; i++) {
1030 printf(".if %s>%s .nr %s 0+%s\n",
1031 nreg(wd[i]), nreg(max_wd),
1032 nregname(max_wd), nreg(wd[i]));
1034 for (i = 1; i < ncols; i++) {
1035 printf(".if %s>%s .nr %s 0+%s\n",
1036 nreg(ht[i]), nreg(max_ht),
1037 nregname(max_ht), nreg(ht[i]));
1039 /* inserting spaces between rows */
1040 printf(".if %s<(%sp*%du/100u) .nr %s (%sp*%du/100u)\n",
1041 nreg(max_ht), nreg(box->szreg), e_baselinesep,
1042 nregname(max_ht), nreg(box->szreg), e_baselinesep);
1043 if (rowspace)
1044 printf(".nr %s +(%sp*%du/100u)\n",
1045 nregname(max_ht), nreg(box->szreg), rowspace);
1046 /* printing the columns */
1047 for (i = 0; i < ncols; i++) {
1048 if (i) /* space between columns */
1049 box_putf(box, "\\h'%sp*%du/100u'",
1050 nreg(box->szreg), e_columnsep + colspace);
1051 box_colput(cols[i], nrows, box, adj[i],
1052 plen[i], max_wd, max_ht);
1054 box_afterput(box, T_INNER);
1055 box_toreg(box);
1056 for (i = 0; i < ncols; i++)
1057 box_coldone(cols[i], nrows, plen[i]);
1058 for (i = 0; i < ncols; i++)
1059 nregrm(ht[i]);
1060 for (i = 0; i < ncols; i++)
1061 nregrm(wd[i]);
1062 nregrm(max_wd);
1063 nregrm(max_ht);