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