=================================================================== RCS file: /cvs/mandoc/eqn.c,v retrieving revision 1.63 retrieving revision 1.66 diff -u -p -r1.63 -r1.66 --- mandoc/eqn.c 2017/06/20 17:24:35 1.63 +++ mandoc/eqn.c 2017/06/21 20:50:50 1.66 @@ -1,7 +1,7 @@ -/* $Id: eqn.c,v 1.63 2017/06/20 17:24:35 schwarze Exp $ */ +/* $OpenBSD: eqn.c,v 1.66 2017/06/21 20:50:50 schwarze Exp $ */ /* * Copyright (c) 2011, 2014 Kristaps Dzonsons - * Copyright (c) 2014, 2015 Ingo Schwarze + * Copyright (c) 2014, 2015, 2017 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -80,9 +81,10 @@ enum eqn_tok { EQN_TOK_TDEFINE, EQN_TOK_NDEFINE, EQN_TOK_UNDEF, - EQN_TOK_EOF, EQN_TOK_ABOVE, - EQN_TOK__MAX + EQN_TOK__MAX, + EQN_TOK_FUNC, + EQN_TOK_EOF }; static const char *eqn_toks[EQN_TOK__MAX] = { @@ -130,10 +132,16 @@ static const char *eqn_toks[EQN_TOK__MAX] = { "tdefine", /* EQN_TOK_TDEFINE */ "ndefine", /* EQN_TOK_NDEFINE */ "undef", /* EQN_TOK_UNDEF */ - NULL, /* EQN_TOK_EOF */ "above", /* EQN_TOK_ABOVE */ }; +static const char *const eqn_func[] = { + "acos", "acsc", "and", "arc", "asec", "asin", "atan", + "cos", "cosh", "coth", "csc", "det", "exp", "for", + "if", "lim", "ln", "log", "max", "min", + "sec", "sin", "sinh", "tan", "tanh", "Im", "Re", +}; + enum eqn_symt { EQNSYM_alpha, EQNSYM_beta, @@ -498,12 +506,12 @@ eqn_tok_parse(struct eqn_node *ep, char **p) size_t i, sz; int quoted; - if (NULL != p) + if (p != NULL) *p = NULL; quoted = ep->data[ep->cur] == '"'; - if (NULL == (start = eqn_nexttok(ep, &sz))) + if ((start = eqn_nexttok(ep, &sz)) == NULL) return EQN_TOK_EOF; if (quoted) { @@ -512,17 +520,26 @@ eqn_tok_parse(struct eqn_node *ep, char **p) return EQN_TOK__MAX; } - for (i = 0; i < EQN_TOK__MAX; i++) { - if (NULL == eqn_toks[i]) - continue; + for (i = 0; i < EQN_TOK__MAX; i++) if (STRNEQ(start, sz, eqn_toks[i], strlen(eqn_toks[i]))) - break; + return i; + + for (i = 0; i < EQNSYM__MAX; i++) { + if (STRNEQ(start, sz, + eqnsyms[i].str, strlen(eqnsyms[i].str))) { + mandoc_asprintf(p, "\\[%s]", eqnsyms[i].sym); + return EQN_TOK__MAX; + } } - if (i == EQN_TOK__MAX && NULL != p) + if (p != NULL) *p = mandoc_strndup(start, sz); - return i; + for (i = 0; i < sizeof(eqn_func)/sizeof(*eqn_func); i++) + if (STRNEQ(start, sz, eqn_func[i], strlen(eqn_func[i]))) + return EQN_TOK_FUNC; + + return EQN_TOK__MAX; } static void @@ -702,10 +719,10 @@ static enum rofferr eqn_parse(struct eqn_node *ep, struct eqn_box *parent) { char sym[64]; - struct eqn_box *cur; - const char *start; + struct eqn_box *cur, *fontp, *nbox; + const char *cp, *cpn, *start; char *p; - size_t i, sz; + size_t sz; enum eqn_tok tok, subtok; enum eqn_post pos; int size; @@ -1067,28 +1084,60 @@ this_tok: * TODO: make sure we're not in an open subexpression. */ return ROFF_EQN; - default: - assert(tok == EQN_TOK__MAX); - assert(NULL != p); + case EQN_TOK_FUNC: + case EQN_TOK__MAX: + assert(p != NULL); /* * If we already have something in the stack and we're * in an expression, then rewind til we're not any more. */ while (parent->args == parent->expectargs) parent = parent->parent; + /* + * Wrap well-known function names in a roman box, + * unless they already are in roman context. + */ + for (fontp = parent; fontp != NULL; fontp = fontp->parent) + if (fontp->font != EQNFONT_NONE) + break; + if (tok == EQN_TOK_FUNC && + (fontp == NULL || fontp->font != EQNFONT_ROMAN)) { + parent = fontp = eqn_box_alloc(ep, parent); + parent->type = EQN_LISTONE; + parent->font = EQNFONT_ROMAN; + parent->expectargs = 1; + } cur = eqn_box_alloc(ep, parent); cur->type = EQN_TEXT; - for (i = 0; i < EQNSYM__MAX; i++) - if (0 == strcmp(eqnsyms[i].str, p)) { - (void)snprintf(sym, sizeof(sym), - "\\[%s]", eqnsyms[i].sym); - cur->text = mandoc_strdup(sym); - free(p); - break; + cur->text = p; + /* + * If not inside any explicit font context, + * give every letter its own box. + */ + if (fontp == NULL && *p != '\0') { + cp = p; + for (;;) { + cpn = cp + 1; + if (*cp == '\\') + mandoc_escape(&cpn, NULL, NULL); + if (*cpn == '\0') + break; + if (isalpha((unsigned char)*cp) == 0 && + isalpha((unsigned char)*cpn) == 0) { + cp = cpn; + continue; + } + nbox = eqn_box_alloc(ep, parent); + nbox->type = EQN_TEXT; + nbox->text = mandoc_strdup(cpn); + p = mandoc_strndup(cur->text, + cpn - cur->text); + free(cur->text); + cur->text = p; + cur = nbox; + cp = nbox->text; } - - if (i == EQNSYM__MAX) - cur->text = p; + } /* * Post-process list status. */ @@ -1096,6 +1145,8 @@ this_tok: parent->args == parent->expectargs) parent = parent->parent; break; + default: + abort(); } goto next_tok; }