1*61d06d6bSBaptiste Daroussin /* $Id: eqn_term.c,v 1.17 2017/08/23 21:56:20 schwarze Exp $ */ 2*61d06d6bSBaptiste Daroussin /* 3*61d06d6bSBaptiste Daroussin * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4*61d06d6bSBaptiste Daroussin * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> 5*61d06d6bSBaptiste Daroussin * 6*61d06d6bSBaptiste Daroussin * Permission to use, copy, modify, and distribute this software for any 7*61d06d6bSBaptiste Daroussin * purpose with or without fee is hereby granted, provided that the above 8*61d06d6bSBaptiste Daroussin * copyright notice and this permission notice appear in all copies. 9*61d06d6bSBaptiste Daroussin * 10*61d06d6bSBaptiste Daroussin * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11*61d06d6bSBaptiste Daroussin * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*61d06d6bSBaptiste Daroussin * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13*61d06d6bSBaptiste Daroussin * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14*61d06d6bSBaptiste Daroussin * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15*61d06d6bSBaptiste Daroussin * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16*61d06d6bSBaptiste Daroussin * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*61d06d6bSBaptiste Daroussin */ 18*61d06d6bSBaptiste Daroussin #include "config.h" 19*61d06d6bSBaptiste Daroussin 20*61d06d6bSBaptiste Daroussin #include <sys/types.h> 21*61d06d6bSBaptiste Daroussin 22*61d06d6bSBaptiste Daroussin #include <assert.h> 23*61d06d6bSBaptiste Daroussin #include <ctype.h> 24*61d06d6bSBaptiste Daroussin #include <stdio.h> 25*61d06d6bSBaptiste Daroussin #include <stdlib.h> 26*61d06d6bSBaptiste Daroussin #include <string.h> 27*61d06d6bSBaptiste Daroussin 28*61d06d6bSBaptiste Daroussin #include "mandoc.h" 29*61d06d6bSBaptiste Daroussin #include "out.h" 30*61d06d6bSBaptiste Daroussin #include "term.h" 31*61d06d6bSBaptiste Daroussin 32*61d06d6bSBaptiste Daroussin static const enum termfont fontmap[EQNFONT__MAX] = { 33*61d06d6bSBaptiste Daroussin TERMFONT_NONE, /* EQNFONT_NONE */ 34*61d06d6bSBaptiste Daroussin TERMFONT_NONE, /* EQNFONT_ROMAN */ 35*61d06d6bSBaptiste Daroussin TERMFONT_BOLD, /* EQNFONT_BOLD */ 36*61d06d6bSBaptiste Daroussin TERMFONT_BOLD, /* EQNFONT_FAT */ 37*61d06d6bSBaptiste Daroussin TERMFONT_UNDER /* EQNFONT_ITALIC */ 38*61d06d6bSBaptiste Daroussin }; 39*61d06d6bSBaptiste Daroussin 40*61d06d6bSBaptiste Daroussin static void eqn_box(struct termp *, const struct eqn_box *); 41*61d06d6bSBaptiste Daroussin 42*61d06d6bSBaptiste Daroussin 43*61d06d6bSBaptiste Daroussin void 44*61d06d6bSBaptiste Daroussin term_eqn(struct termp *p, const struct eqn_box *bp) 45*61d06d6bSBaptiste Daroussin { 46*61d06d6bSBaptiste Daroussin 47*61d06d6bSBaptiste Daroussin eqn_box(p, bp); 48*61d06d6bSBaptiste Daroussin p->flags &= ~TERMP_NOSPACE; 49*61d06d6bSBaptiste Daroussin } 50*61d06d6bSBaptiste Daroussin 51*61d06d6bSBaptiste Daroussin static void 52*61d06d6bSBaptiste Daroussin eqn_box(struct termp *p, const struct eqn_box *bp) 53*61d06d6bSBaptiste Daroussin { 54*61d06d6bSBaptiste Daroussin const struct eqn_box *child; 55*61d06d6bSBaptiste Daroussin const char *cp; 56*61d06d6bSBaptiste Daroussin int delim; 57*61d06d6bSBaptiste Daroussin 58*61d06d6bSBaptiste Daroussin /* Delimiters around this box? */ 59*61d06d6bSBaptiste Daroussin 60*61d06d6bSBaptiste Daroussin if ((bp->type == EQN_LIST && bp->expectargs > 1) || 61*61d06d6bSBaptiste Daroussin (bp->type == EQN_PILE && (bp->prev || bp->next)) || 62*61d06d6bSBaptiste Daroussin (bp->parent != NULL && (bp->parent->pos == EQNPOS_SQRT || 63*61d06d6bSBaptiste Daroussin /* Diacritic followed by ^ or _. */ 64*61d06d6bSBaptiste Daroussin ((bp->top != NULL || bp->bottom != NULL) && 65*61d06d6bSBaptiste Daroussin bp->parent->type == EQN_SUBEXPR && 66*61d06d6bSBaptiste Daroussin bp->parent->pos != EQNPOS_OVER && bp->next != NULL) || 67*61d06d6bSBaptiste Daroussin /* Nested over, sub, sup, from, to. */ 68*61d06d6bSBaptiste Daroussin (bp->type == EQN_SUBEXPR && bp->pos != EQNPOS_SQRT && 69*61d06d6bSBaptiste Daroussin ((bp->parent->type == EQN_LIST && bp->expectargs == 1) || 70*61d06d6bSBaptiste Daroussin (bp->parent->type == EQN_SUBEXPR && 71*61d06d6bSBaptiste Daroussin bp->pos != EQNPOS_SQRT)))))) { 72*61d06d6bSBaptiste Daroussin if ((bp->parent->type == EQN_SUBEXPR && bp->prev != NULL) || 73*61d06d6bSBaptiste Daroussin (bp->type == EQN_LIST && 74*61d06d6bSBaptiste Daroussin bp->first != NULL && 75*61d06d6bSBaptiste Daroussin bp->first->type != EQN_PILE && 76*61d06d6bSBaptiste Daroussin bp->first->type != EQN_MATRIX && 77*61d06d6bSBaptiste Daroussin bp->prev != NULL && 78*61d06d6bSBaptiste Daroussin (bp->prev->type == EQN_LIST || 79*61d06d6bSBaptiste Daroussin (bp->prev->type == EQN_TEXT && 80*61d06d6bSBaptiste Daroussin (*bp->prev->text == '\\' || 81*61d06d6bSBaptiste Daroussin isalpha((unsigned char)*bp->prev->text)))))) 82*61d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 83*61d06d6bSBaptiste Daroussin term_word(p, bp->left != NULL ? bp->left : "("); 84*61d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 85*61d06d6bSBaptiste Daroussin delim = 1; 86*61d06d6bSBaptiste Daroussin } else 87*61d06d6bSBaptiste Daroussin delim = 0; 88*61d06d6bSBaptiste Daroussin 89*61d06d6bSBaptiste Daroussin /* Handle Fonts and text. */ 90*61d06d6bSBaptiste Daroussin 91*61d06d6bSBaptiste Daroussin if (bp->font != EQNFONT_NONE) 92*61d06d6bSBaptiste Daroussin term_fontpush(p, fontmap[(int)bp->font]); 93*61d06d6bSBaptiste Daroussin 94*61d06d6bSBaptiste Daroussin if (bp->text != NULL) { 95*61d06d6bSBaptiste Daroussin if (strchr("!\"'),.:;?]}", *bp->text) != NULL) 96*61d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 97*61d06d6bSBaptiste Daroussin term_word(p, bp->text); 98*61d06d6bSBaptiste Daroussin if ((cp = strchr(bp->text, '\0')) > bp->text && 99*61d06d6bSBaptiste Daroussin (strchr("\"'([{", cp[-1]) != NULL || 100*61d06d6bSBaptiste Daroussin (bp->prev == NULL && (cp[-1] == '-' || 101*61d06d6bSBaptiste Daroussin (cp >= bp->text + 5 && 102*61d06d6bSBaptiste Daroussin strcmp(cp - 5, "\\[mi]") == 0))))) 103*61d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 104*61d06d6bSBaptiste Daroussin } 105*61d06d6bSBaptiste Daroussin 106*61d06d6bSBaptiste Daroussin /* Special box types. */ 107*61d06d6bSBaptiste Daroussin 108*61d06d6bSBaptiste Daroussin if (bp->pos == EQNPOS_SQRT) { 109*61d06d6bSBaptiste Daroussin term_word(p, "sqrt"); 110*61d06d6bSBaptiste Daroussin if (bp->first != NULL) { 111*61d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 112*61d06d6bSBaptiste Daroussin eqn_box(p, bp->first); 113*61d06d6bSBaptiste Daroussin } 114*61d06d6bSBaptiste Daroussin } else if (bp->type == EQN_SUBEXPR) { 115*61d06d6bSBaptiste Daroussin child = bp->first; 116*61d06d6bSBaptiste Daroussin eqn_box(p, child); 117*61d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 118*61d06d6bSBaptiste Daroussin term_word(p, bp->pos == EQNPOS_OVER ? "/" : 119*61d06d6bSBaptiste Daroussin (bp->pos == EQNPOS_SUP || 120*61d06d6bSBaptiste Daroussin bp->pos == EQNPOS_TO) ? "^" : "_"); 121*61d06d6bSBaptiste Daroussin child = child->next; 122*61d06d6bSBaptiste Daroussin if (child != NULL) { 123*61d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 124*61d06d6bSBaptiste Daroussin eqn_box(p, child); 125*61d06d6bSBaptiste Daroussin if (bp->pos == EQNPOS_FROMTO || 126*61d06d6bSBaptiste Daroussin bp->pos == EQNPOS_SUBSUP) { 127*61d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 128*61d06d6bSBaptiste Daroussin term_word(p, "^"); 129*61d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 130*61d06d6bSBaptiste Daroussin child = child->next; 131*61d06d6bSBaptiste Daroussin if (child != NULL) 132*61d06d6bSBaptiste Daroussin eqn_box(p, child); 133*61d06d6bSBaptiste Daroussin } 134*61d06d6bSBaptiste Daroussin } 135*61d06d6bSBaptiste Daroussin } else { 136*61d06d6bSBaptiste Daroussin child = bp->first; 137*61d06d6bSBaptiste Daroussin if (bp->type == EQN_MATRIX && 138*61d06d6bSBaptiste Daroussin child != NULL && 139*61d06d6bSBaptiste Daroussin child->type == EQN_LIST && 140*61d06d6bSBaptiste Daroussin child->expectargs > 1) 141*61d06d6bSBaptiste Daroussin child = child->first; 142*61d06d6bSBaptiste Daroussin while (child != NULL) { 143*61d06d6bSBaptiste Daroussin eqn_box(p, 144*61d06d6bSBaptiste Daroussin bp->type == EQN_PILE && 145*61d06d6bSBaptiste Daroussin child->type == EQN_LIST && 146*61d06d6bSBaptiste Daroussin child->expectargs > 1 && 147*61d06d6bSBaptiste Daroussin child->args == 1 ? 148*61d06d6bSBaptiste Daroussin child->first : child); 149*61d06d6bSBaptiste Daroussin child = child->next; 150*61d06d6bSBaptiste Daroussin } 151*61d06d6bSBaptiste Daroussin } 152*61d06d6bSBaptiste Daroussin 153*61d06d6bSBaptiste Daroussin /* Handle Fonts and diacritics. */ 154*61d06d6bSBaptiste Daroussin 155*61d06d6bSBaptiste Daroussin if (bp->font != EQNFONT_NONE) 156*61d06d6bSBaptiste Daroussin term_fontpop(p); 157*61d06d6bSBaptiste Daroussin if (bp->top != NULL) { 158*61d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 159*61d06d6bSBaptiste Daroussin term_word(p, bp->top); 160*61d06d6bSBaptiste Daroussin } 161*61d06d6bSBaptiste Daroussin if (bp->bottom != NULL) { 162*61d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 163*61d06d6bSBaptiste Daroussin term_word(p, "_"); 164*61d06d6bSBaptiste Daroussin } 165*61d06d6bSBaptiste Daroussin 166*61d06d6bSBaptiste Daroussin /* Right delimiter after this box? */ 167*61d06d6bSBaptiste Daroussin 168*61d06d6bSBaptiste Daroussin if (delim) { 169*61d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 170*61d06d6bSBaptiste Daroussin term_word(p, bp->right != NULL ? bp->right : ")"); 171*61d06d6bSBaptiste Daroussin if (bp->parent->type == EQN_SUBEXPR && bp->next != NULL) 172*61d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 173*61d06d6bSBaptiste Daroussin } 174*61d06d6bSBaptiste Daroussin } 175