version 1.80, 2018/12/13 03:40:13 |
version 1.85, 2022/04/13 20:26:19 |
|
|
/* $Id$ */ |
/* $Id$ */ |
/* |
/* |
|
* Copyright (c) 2014, 2015, 2017, 2018, 2020, 2022 |
|
* Ingo Schwarze <schwarze@openbsd.org> |
* Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> |
* Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> |
* Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> |
|
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* purpose with or without fee is hereby granted, provided that the above |
|
|
#include "mandoc_aux.h" |
#include "mandoc_aux.h" |
#include "mandoc.h" |
#include "mandoc.h" |
#include "roff.h" |
#include "roff.h" |
|
#include "eqn.h" |
#include "libmandoc.h" |
#include "libmandoc.h" |
#include "eqn_parse.h" |
#include "eqn_parse.h" |
|
|
Line 302 static void eqn_undef(struct eqn_node *); |
|
Line 304 static void eqn_undef(struct eqn_node *); |
|
|
|
|
|
struct eqn_node * |
struct eqn_node * |
eqn_alloc(struct mparse *parse) |
eqn_alloc(void) |
{ |
{ |
struct eqn_node *ep; |
struct eqn_node *ep; |
|
|
ep = mandoc_calloc(1, sizeof(*ep)); |
ep = mandoc_calloc(1, sizeof(*ep)); |
ep->parse = parse; |
|
ep->gsize = EQN_DEFSIZE; |
ep->gsize = EQN_DEFSIZE; |
return ep; |
return ep; |
} |
} |
Line 375 eqn_def_find(struct eqn_node *ep) |
|
Line 376 eqn_def_find(struct eqn_node *ep) |
|
static enum eqn_tok |
static enum eqn_tok |
eqn_next(struct eqn_node *ep, enum parse_mode mode) |
eqn_next(struct eqn_node *ep, enum parse_mode mode) |
{ |
{ |
static int last_len, lim; |
|
|
|
struct eqn_def *def; |
struct eqn_def *def; |
size_t start; |
size_t start; |
int diff, i, quoted; |
int diff, i, newlen, quoted; |
enum eqn_tok tok; |
enum eqn_tok tok; |
|
|
/* |
/* |
* Reset the recursion counter after advancing |
* Reset the recursion counter after advancing |
* beyond the end of the previous substitution. |
* beyond the end of the rightmost substitution. |
*/ |
*/ |
if (ep->end - ep->data >= last_len) |
if (ep->end - ep->data >= ep->sublen) |
lim = 0; |
ep->subcnt = 0; |
|
|
ep->start = ep->end; |
ep->start = ep->end; |
quoted = mode == MODE_QUOTED; |
quoted = mode == MODE_QUOTED; |
Line 399 eqn_next(struct eqn_node *ep, enum parse_mode mode) |
|
Line 398 eqn_next(struct eqn_node *ep, enum parse_mode mode) |
|
case '"': |
case '"': |
quoted = 1; |
quoted = 1; |
break; |
break; |
|
case ' ': |
|
case '\t': |
|
case '~': |
|
case '^': |
|
if (quoted) |
|
break; |
|
ep->start++; |
|
continue; |
default: |
default: |
break; |
break; |
} |
} |
Line 406 eqn_next(struct eqn_node *ep, enum parse_mode mode) |
|
Line 413 eqn_next(struct eqn_node *ep, enum parse_mode mode) |
|
ep->end = strchr(ep->start + 1, *ep->start); |
ep->end = strchr(ep->start + 1, *ep->start); |
ep->start++; /* Skip opening quote. */ |
ep->start++; /* Skip opening quote. */ |
if (ep->end == NULL) { |
if (ep->end == NULL) { |
mandoc_msg(MANDOCERR_ARG_QUOTE, ep->parse, |
mandoc_msg(MANDOCERR_ARG_QUOTE, |
ep->node->line, ep->node->pos, NULL); |
ep->node->line, ep->node->pos, NULL); |
ep->end = strchr(ep->start, '\0'); |
ep->end = strchr(ep->start, '\0'); |
} |
} |
Line 426 eqn_next(struct eqn_node *ep, enum parse_mode mode) |
|
Line 433 eqn_next(struct eqn_node *ep, enum parse_mode mode) |
|
return EQN_TOK__MAX; |
return EQN_TOK__MAX; |
if ((def = eqn_def_find(ep)) == NULL) |
if ((def = eqn_def_find(ep)) == NULL) |
break; |
break; |
if (++lim > EQN_NEST_MAX) { |
if (++ep->subcnt > EQN_NEST_MAX) { |
mandoc_msg(MANDOCERR_ROFFLOOP, ep->parse, |
mandoc_msg(MANDOCERR_ROFFLOOP, |
ep->node->line, ep->node->pos, NULL); |
ep->node->line, ep->node->pos, NULL); |
return EQN_TOK_EOF; |
break; |
} |
} |
|
|
/* Replace a defined name with its string value. */ |
/* Replace a defined name with its string value. */ |
Line 438 eqn_next(struct eqn_node *ep, enum parse_mode mode) |
|
Line 445 eqn_next(struct eqn_node *ep, enum parse_mode mode) |
|
ep->sz += diff; |
ep->sz += diff; |
ep->data = mandoc_realloc(ep->data, ep->sz + 1); |
ep->data = mandoc_realloc(ep->data, ep->sz + 1); |
ep->start = ep->data + start; |
ep->start = ep->data + start; |
|
ep->sublen += diff; |
} |
} |
if (diff) |
if (diff) |
memmove(ep->start + def->valsz, ep->start + ep->toksz, |
memmove(ep->start + def->valsz, ep->start + ep->toksz, |
strlen(ep->start + ep->toksz) + 1); |
strlen(ep->start + ep->toksz) + 1); |
memcpy(ep->start, def->val, def->valsz); |
memcpy(ep->start, def->val, def->valsz); |
last_len = ep->start - ep->data + def->valsz; |
newlen = ep->start - ep->data + def->valsz; |
|
if (ep->sublen < newlen) |
|
ep->sublen = newlen; |
} |
} |
if (mode != MODE_TOK) |
if (mode != MODE_TOK) |
return quoted ? EQN_TOK_QUOTED : EQN_TOK__MAX; |
return quoted ? EQN_TOK_QUOTED : EQN_TOK__MAX; |
Line 491 eqn_box_free(struct eqn_box *bp) |
|
Line 501 eqn_box_free(struct eqn_box *bp) |
|
free(bp); |
free(bp); |
} |
} |
|
|
|
struct eqn_box * |
|
eqn_box_new(void) |
|
{ |
|
struct eqn_box *bp; |
|
|
|
bp = mandoc_calloc(1, sizeof(*bp)); |
|
bp->expectargs = UINT_MAX; |
|
return bp; |
|
} |
|
|
/* |
/* |
* Allocate a box as the last child of the parent node. |
* Allocate a box as the last child of the parent node. |
*/ |
*/ |
Line 499 eqn_box_alloc(struct eqn_node *ep, struct eqn_box *par |
|
Line 519 eqn_box_alloc(struct eqn_node *ep, struct eqn_box *par |
|
{ |
{ |
struct eqn_box *bp; |
struct eqn_box *bp; |
|
|
bp = mandoc_calloc(1, sizeof(struct eqn_box)); |
bp = eqn_box_new(); |
bp->parent = parent; |
bp->parent = parent; |
bp->parent->args++; |
bp->parent->args++; |
bp->expectargs = UINT_MAX; |
|
bp->font = bp->parent->font; |
bp->font = bp->parent->font; |
bp->size = ep->gsize; |
bp->size = ep->gsize; |
|
|
|
|
eqn_delim(struct eqn_node *ep) |
eqn_delim(struct eqn_node *ep) |
{ |
{ |
if (ep->end[0] == '\0' || ep->end[1] == '\0') { |
if (ep->end[0] == '\0' || ep->end[1] == '\0') { |
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, |
mandoc_msg(MANDOCERR_REQ_EMPTY, |
ep->node->line, ep->node->pos, "delim"); |
ep->node->line, ep->node->pos, "delim"); |
if (ep->end[0] != '\0') |
if (ep->end[0] != '\0') |
ep->end++; |
ep->end++; |
Line 578 eqn_undef(struct eqn_node *ep) |
|
Line 597 eqn_undef(struct eqn_node *ep) |
|
struct eqn_def *def; |
struct eqn_def *def; |
|
|
if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) { |
if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) { |
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, |
mandoc_msg(MANDOCERR_REQ_EMPTY, |
ep->node->line, ep->node->pos, "undef"); |
ep->node->line, ep->node->pos, "undef"); |
return; |
return; |
} |
} |
Line 597 eqn_def(struct eqn_node *ep) |
|
Line 616 eqn_def(struct eqn_node *ep) |
|
int i; |
int i; |
|
|
if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) { |
if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) { |
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, |
mandoc_msg(MANDOCERR_REQ_EMPTY, |
ep->node->line, ep->node->pos, "define"); |
ep->node->line, ep->node->pos, "define"); |
return; |
return; |
} |
} |
Line 626 eqn_def(struct eqn_node *ep) |
|
Line 645 eqn_def(struct eqn_node *ep) |
|
} |
} |
|
|
if (eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF) { |
if (eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF) { |
mandoc_vmsg(MANDOCERR_REQ_EMPTY, ep->parse, |
mandoc_msg(MANDOCERR_REQ_EMPTY, |
ep->node->line, ep->node->pos, "define %s", def->key); |
ep->node->line, ep->node->pos, "define %s", def->key); |
free(def->key); |
free(def->key); |
free(def->val); |
free(def->val); |
Line 660 eqn_parse(struct eqn_node *ep) |
|
Line 679 eqn_parse(struct eqn_node *ep) |
|
if (ep->data == NULL) |
if (ep->data == NULL) |
return; |
return; |
|
|
ep->start = ep->end = ep->data + strspn(ep->data, " ^~"); |
ep->start = ep->end = ep->data; |
|
ep->sublen = 0; |
|
ep->subcnt = 0; |
|
|
next_tok: |
next_tok: |
tok = eqn_next(ep, MODE_TOK); |
tok = eqn_next(ep, MODE_TOK); |
|
|
case EQN_TOK_TDEFINE: |
case EQN_TOK_TDEFINE: |
if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF || |
if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF || |
eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF) |
eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF) |
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, |
mandoc_msg(MANDOCERR_REQ_EMPTY, |
ep->node->line, ep->node->pos, "tdefine"); |
ep->node->line, ep->node->pos, "tdefine"); |
break; |
break; |
case EQN_TOK_DELIM: |
case EQN_TOK_DELIM: |
|
|
break; |
break; |
case EQN_TOK_GFONT: |
case EQN_TOK_GFONT: |
if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) |
if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) |
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, |
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line, |
ep->node->line, ep->node->pos, eqn_toks[tok]); |
ep->node->pos, "%s", eqn_toks[tok]); |
break; |
break; |
case EQN_TOK_MARK: |
case EQN_TOK_MARK: |
case EQN_TOK_LINEUP: |
case EQN_TOK_LINEUP: |
|
|
case EQN_TOK_DOT: |
case EQN_TOK_DOT: |
case EQN_TOK_DOTDOT: |
case EQN_TOK_DOTDOT: |
if (parent->last == NULL) { |
if (parent->last == NULL) { |
mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse, |
mandoc_msg(MANDOCERR_EQN_NOBOX, ep->node->line, |
ep->node->line, ep->node->pos, eqn_toks[tok]); |
ep->node->pos, "%s", eqn_toks[tok]); |
cur = eqn_box_alloc(ep, parent); |
cur = eqn_box_alloc(ep, parent); |
cur->type = EQN_TEXT; |
cur->type = EQN_TEXT; |
cur->text = mandoc_strdup(""); |
cur->text = mandoc_strdup(""); |
|
|
case EQN_TOK_DOWN: |
case EQN_TOK_DOWN: |
case EQN_TOK_UP: |
case EQN_TOK_UP: |
if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) |
if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) |
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, |
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line, |
ep->node->line, ep->node->pos, eqn_toks[tok]); |
ep->node->pos, "%s", eqn_toks[tok]); |
break; |
break; |
case EQN_TOK_FAT: |
case EQN_TOK_FAT: |
case EQN_TOK_ROMAN: |
case EQN_TOK_ROMAN: |
|
|
case EQN_TOK_GSIZE: |
case EQN_TOK_GSIZE: |
/* Accept two values: integral size and a single. */ |
/* Accept two values: integral size and a single. */ |
if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) { |
if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) { |
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, |
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line, |
ep->node->line, ep->node->pos, eqn_toks[tok]); |
ep->node->pos, "%s", eqn_toks[tok]); |
break; |
break; |
} |
} |
size = mandoc_strntoi(ep->start, ep->toksz, 10); |
size = mandoc_strntoi(ep->start, ep->toksz, 10); |
if (-1 == size) { |
if (-1 == size) { |
mandoc_msg(MANDOCERR_IT_NONUM, ep->parse, |
mandoc_msg(MANDOCERR_IT_NONUM, ep->node->line, |
ep->node->line, ep->node->pos, eqn_toks[tok]); |
ep->node->pos, "%s", eqn_toks[tok]); |
break; |
break; |
} |
} |
if (EQN_TOK_GSIZE == tok) { |
if (EQN_TOK_GSIZE == tok) { |
|
|
* and keep on reading. |
* and keep on reading. |
*/ |
*/ |
if (parent->last == NULL) { |
if (parent->last == NULL) { |
mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse, |
mandoc_msg(MANDOCERR_EQN_NOBOX, ep->node->line, |
ep->node->line, ep->node->pos, eqn_toks[tok]); |
ep->node->pos, "%s", eqn_toks[tok]); |
cur = eqn_box_alloc(ep, parent); |
cur = eqn_box_alloc(ep, parent); |
cur->type = EQN_TEXT; |
cur->type = EQN_TEXT; |
cur->text = mandoc_strdup(""); |
cur->text = mandoc_strdup(""); |
|
|
* rebalance and continue reading. |
* rebalance and continue reading. |
*/ |
*/ |
if (parent->last == NULL) { |
if (parent->last == NULL) { |
mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse, |
mandoc_msg(MANDOCERR_EQN_NOBOX, ep->node->line, |
ep->node->line, ep->node->pos, eqn_toks[tok]); |
ep->node->pos, "%s", eqn_toks[tok]); |
cur = eqn_box_alloc(ep, parent); |
cur = eqn_box_alloc(ep, parent); |
cur->type = EQN_TEXT; |
cur->type = EQN_TEXT; |
cur->text = mandoc_strdup(""); |
cur->text = mandoc_strdup(""); |
|
|
cur->left != NULL)) |
cur->left != NULL)) |
break; |
break; |
if (cur == NULL) { |
if (cur == NULL) { |
mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->parse, |
mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->node->line, |
ep->node->line, ep->node->pos, eqn_toks[tok]); |
ep->node->pos, "%s", eqn_toks[tok]); |
break; |
break; |
} |
} |
parent = cur; |
parent = cur; |
if (EQN_TOK_RIGHT == tok) { |
if (EQN_TOK_RIGHT == tok) { |
if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) { |
if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) { |
mandoc_msg(MANDOCERR_REQ_EMPTY, |
mandoc_msg(MANDOCERR_REQ_EMPTY, |
ep->parse, ep->node->line, |
ep->node->line, ep->node->pos, |
ep->node->pos, eqn_toks[tok]); |
"%s", eqn_toks[tok]); |
break; |
break; |
} |
} |
/* Handling depends on right/left. */ |
/* Handling depends on right/left. */ |
|
|
parent = parent->parent; |
parent = parent->parent; |
if (EQN_TOK_LEFT == tok && |
if (EQN_TOK_LEFT == tok && |
eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) { |
eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) { |
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, |
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line, |
ep->node->line, ep->node->pos, eqn_toks[tok]); |
ep->node->pos, "%s", eqn_toks[tok]); |
break; |
break; |
} |
} |
parent = eqn_box_alloc(ep, parent); |
parent = eqn_box_alloc(ep, parent); |
|
|
if (cur->type == EQN_PILE) |
if (cur->type == EQN_PILE) |
break; |
break; |
if (cur == NULL) { |
if (cur == NULL) { |
mandoc_msg(MANDOCERR_IT_STRAY, ep->parse, |
mandoc_msg(MANDOCERR_IT_STRAY, ep->node->line, |
ep->node->line, ep->node->pos, eqn_toks[tok]); |
ep->node->pos, "%s", eqn_toks[tok]); |
break; |
break; |
} |
} |
parent = eqn_box_alloc(ep, cur); |
parent = eqn_box_alloc(ep, cur); |