1*d4c8d4a3Sschwarze /* $OpenBSD: eqn_term.c,v 1.15 2018/12/13 05:13:15 schwarze Exp $ */
2f8618d99Sschwarze /*
3f8618d99Sschwarze * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4b6a9b0a3Sschwarze * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
5f8618d99Sschwarze *
6f8618d99Sschwarze * Permission to use, copy, modify, and distribute this software for any
7f8618d99Sschwarze * purpose with or without fee is hereby granted, provided that the above
8f8618d99Sschwarze * copyright notice and this permission notice appear in all copies.
9f8618d99Sschwarze *
10f8618d99Sschwarze * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11f8618d99Sschwarze * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12f8618d99Sschwarze * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13f8618d99Sschwarze * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14f8618d99Sschwarze * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15f8618d99Sschwarze * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16f8618d99Sschwarze * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17f8618d99Sschwarze */
185409f16eSschwarze #include <sys/types.h>
195409f16eSschwarze
20f8618d99Sschwarze #include <assert.h>
21655001d5Sschwarze #include <ctype.h>
22f8618d99Sschwarze #include <stdio.h>
23f8618d99Sschwarze #include <stdlib.h>
24f8618d99Sschwarze #include <string.h>
25f8618d99Sschwarze
26*d4c8d4a3Sschwarze #include "eqn.h"
27f8618d99Sschwarze #include "out.h"
28f8618d99Sschwarze #include "term.h"
29f8618d99Sschwarze
30f8618d99Sschwarze static const enum termfont fontmap[EQNFONT__MAX] = {
31f8618d99Sschwarze TERMFONT_NONE, /* EQNFONT_NONE */
32f8618d99Sschwarze TERMFONT_NONE, /* EQNFONT_ROMAN */
33f8618d99Sschwarze TERMFONT_BOLD, /* EQNFONT_BOLD */
34f8618d99Sschwarze TERMFONT_BOLD, /* EQNFONT_FAT */
35f8618d99Sschwarze TERMFONT_UNDER /* EQNFONT_ITALIC */
36f8618d99Sschwarze };
37f8618d99Sschwarze
38f8618d99Sschwarze static void eqn_box(struct termp *, const struct eqn_box *);
39f8618d99Sschwarze
4049aff9f8Sschwarze
41f8618d99Sschwarze void
term_eqn(struct termp * p,const struct eqn_box * bp)42bf9acac6Sschwarze term_eqn(struct termp *p, const struct eqn_box *bp)
43f8618d99Sschwarze {
44f8618d99Sschwarze
45bf9acac6Sschwarze eqn_box(p, bp);
465409f16eSschwarze p->flags &= ~TERMP_NOSPACE;
47f8618d99Sschwarze }
48f8618d99Sschwarze
49f8618d99Sschwarze static void
eqn_box(struct termp * p,const struct eqn_box * bp)50f8618d99Sschwarze eqn_box(struct termp *p, const struct eqn_box *bp)
51f8618d99Sschwarze {
525409f16eSschwarze const struct eqn_box *child;
534c273204Sschwarze const char *cp;
548b65095eSschwarze int delim;
558b65095eSschwarze
568b65095eSschwarze /* Delimiters around this box? */
57f8618d99Sschwarze
5832e49996Sschwarze if ((bp->type == EQN_LIST && bp->expectargs > 1) ||
595409f16eSschwarze (bp->type == EQN_PILE && (bp->prev || bp->next)) ||
608b65095eSschwarze (bp->parent != NULL && (bp->parent->pos == EQNPOS_SQRT ||
618b65095eSschwarze /* Diacritic followed by ^ or _. */
628b65095eSschwarze ((bp->top != NULL || bp->bottom != NULL) &&
638b65095eSschwarze bp->parent->type == EQN_SUBEXPR &&
648b65095eSschwarze bp->parent->pos != EQNPOS_OVER && bp->next != NULL) ||
658b65095eSschwarze /* Nested over, sub, sup, from, to. */
668b65095eSschwarze (bp->type == EQN_SUBEXPR && bp->pos != EQNPOS_SQRT &&
678b65095eSschwarze ((bp->parent->type == EQN_LIST && bp->expectargs == 1) ||
688b65095eSschwarze (bp->parent->type == EQN_SUBEXPR &&
698b65095eSschwarze bp->pos != EQNPOS_SQRT)))))) {
70655001d5Sschwarze if ((bp->parent->type == EQN_SUBEXPR && bp->prev != NULL) ||
71655001d5Sschwarze (bp->type == EQN_LIST &&
72655001d5Sschwarze bp->first != NULL &&
73655001d5Sschwarze bp->first->type != EQN_PILE &&
74655001d5Sschwarze bp->first->type != EQN_MATRIX &&
75655001d5Sschwarze bp->prev != NULL &&
76655001d5Sschwarze (bp->prev->type == EQN_LIST ||
77655001d5Sschwarze (bp->prev->type == EQN_TEXT &&
78655001d5Sschwarze (*bp->prev->text == '\\' ||
79655001d5Sschwarze isalpha((unsigned char)*bp->prev->text))))))
805409f16eSschwarze p->flags |= TERMP_NOSPACE;
815409f16eSschwarze term_word(p, bp->left != NULL ? bp->left : "(");
825409f16eSschwarze p->flags |= TERMP_NOSPACE;
838b65095eSschwarze delim = 1;
848b65095eSschwarze } else
858b65095eSschwarze delim = 0;
868b65095eSschwarze
878b65095eSschwarze /* Handle Fonts and text. */
888b65095eSschwarze
895409f16eSschwarze if (bp->font != EQNFONT_NONE)
90f8618d99Sschwarze term_fontpush(p, fontmap[(int)bp->font]);
91f8618d99Sschwarze
925c36141bSschwarze if (bp->text != NULL) {
935c36141bSschwarze if (strchr("!\"'),.:;?]}", *bp->text) != NULL)
945c36141bSschwarze p->flags |= TERMP_NOSPACE;
95f8618d99Sschwarze term_word(p, bp->text);
964c273204Sschwarze if ((cp = strchr(bp->text, '\0')) > bp->text &&
97af943bc9Sschwarze (strchr("\"'([{", cp[-1]) != NULL ||
98af943bc9Sschwarze (bp->prev == NULL && (cp[-1] == '-' ||
99af943bc9Sschwarze (cp >= bp->text + 5 &&
100af943bc9Sschwarze strcmp(cp - 5, "\\[mi]") == 0)))))
1015c36141bSschwarze p->flags |= TERMP_NOSPACE;
1025c36141bSschwarze }
103f8618d99Sschwarze
1048b65095eSschwarze /* Special box types. */
1058b65095eSschwarze
1065409f16eSschwarze if (bp->pos == EQNPOS_SQRT) {
107eb9ded0cSschwarze term_word(p, "\\(sr");
108b6a9b0a3Sschwarze if (bp->first != NULL) {
1095409f16eSschwarze p->flags |= TERMP_NOSPACE;
110f8618d99Sschwarze eqn_box(p, bp->first);
111b6a9b0a3Sschwarze }
1125409f16eSschwarze } else if (bp->type == EQN_SUBEXPR) {
1135409f16eSschwarze child = bp->first;
1145409f16eSschwarze eqn_box(p, child);
1155409f16eSschwarze p->flags |= TERMP_NOSPACE;
1165409f16eSschwarze term_word(p, bp->pos == EQNPOS_OVER ? "/" :
1175409f16eSschwarze (bp->pos == EQNPOS_SUP ||
1185409f16eSschwarze bp->pos == EQNPOS_TO) ? "^" : "_");
1195409f16eSschwarze child = child->next;
12044e7abbfSschwarze if (child != NULL) {
121655001d5Sschwarze p->flags |= TERMP_NOSPACE;
1225409f16eSschwarze eqn_box(p, child);
1235409f16eSschwarze if (bp->pos == EQNPOS_FROMTO ||
1245409f16eSschwarze bp->pos == EQNPOS_SUBSUP) {
1255409f16eSschwarze p->flags |= TERMP_NOSPACE;
1265409f16eSschwarze term_word(p, "^");
1275409f16eSschwarze p->flags |= TERMP_NOSPACE;
1285409f16eSschwarze child = child->next;
12944e7abbfSschwarze if (child != NULL)
1305409f16eSschwarze eqn_box(p, child);
1315409f16eSschwarze }
13244e7abbfSschwarze }
1335409f16eSschwarze } else {
1345409f16eSschwarze child = bp->first;
135b6a9b0a3Sschwarze if (bp->type == EQN_MATRIX &&
13632e49996Sschwarze child != NULL &&
13732e49996Sschwarze child->type == EQN_LIST &&
13832e49996Sschwarze child->expectargs > 1)
1395409f16eSschwarze child = child->first;
1405409f16eSschwarze while (child != NULL) {
1415409f16eSschwarze eqn_box(p,
1425409f16eSschwarze bp->type == EQN_PILE &&
1435409f16eSschwarze child->type == EQN_LIST &&
14432e49996Sschwarze child->expectargs > 1 &&
1455409f16eSschwarze child->args == 1 ?
1465409f16eSschwarze child->first : child);
1475409f16eSschwarze child = child->next;
1485409f16eSschwarze }
1495409f16eSschwarze }
150f8618d99Sschwarze
1518b65095eSschwarze /* Handle Fonts and diacritics. */
1528b65095eSschwarze
1535409f16eSschwarze if (bp->font != EQNFONT_NONE)
154f8618d99Sschwarze term_fontpop(p);
1555409f16eSschwarze if (bp->top != NULL) {
1565409f16eSschwarze p->flags |= TERMP_NOSPACE;
1575409f16eSschwarze term_word(p, bp->top);
1585409f16eSschwarze }
1595409f16eSschwarze if (bp->bottom != NULL) {
1605409f16eSschwarze p->flags |= TERMP_NOSPACE;
1615409f16eSschwarze term_word(p, "_");
1625409f16eSschwarze }
1638b65095eSschwarze
1648b65095eSschwarze /* Right delimiter after this box? */
1658b65095eSschwarze
1668b65095eSschwarze if (delim) {
1672fe51f68Sschwarze p->flags |= TERMP_NOSPACE;
1682fe51f68Sschwarze term_word(p, bp->right != NULL ? bp->right : ")");
1692fe51f68Sschwarze if (bp->parent->type == EQN_SUBEXPR && bp->next != NULL)
1702fe51f68Sschwarze p->flags |= TERMP_NOSPACE;
1712fe51f68Sschwarze }
172f8618d99Sschwarze }
173