eqn.c (6d38604fc532a3fc060788e3ce40464b46047eaf) eqn.c (c1c95add8c80843ba15d784f95c361d795b1f593)
1/* $Id: eqn.c,v 1.84 2020/01/08 12:16:24 schwarze Exp $ */
1/* $Id: eqn.c,v 1.86 2023/04/28 19:11:03 schwarze Exp $ */
2/*
2/*
3 * Copyright (c) 2014, 2015, 2017, 2018, 2020, 2022
4 * Ingo Schwarze <schwarze@openbsd.org>
3 * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
5 * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2014,2015,2017,2018,2020 Ingo Schwarze <schwarze@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR

--- 337 unchanged lines hidden (view full) ---

350 return &ep->defs[i];
351
352 return NULL;
353}
354
355/*
356 * Parse a token from the input text. The modes are:
357 * MODE_QUOTED: Use *ep->start as the delimiter; the token ends
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR

--- 337 unchanged lines hidden (view full) ---

351 return &ep->defs[i];
352
353 return NULL;
354}
355
356/*
357 * Parse a token from the input text. The modes are:
358 * MODE_QUOTED: Use *ep->start as the delimiter; the token ends
358 * before its next occurence. Do not interpret the token in any
359 * before its next occurrence. Do not interpret the token in any
359 * way and return EQN_TOK_QUOTED. All other modes behave like
360 * MODE_QUOTED when *ep->start is '"'.
361 * MODE_NOSUB: If *ep->start is a curly brace, the token ends after it;
362 * otherwise, it ends before the next whitespace or brace.
363 * Do not interpret the token and return EQN_TOK__MAX.
364 * MODE_SUB: Like MODE_NOSUB, but try to interpret the token as an
365 * alias created with define. If it is an alias, replace it with
366 * its string value and reparse.
367 * MODE_TOK: Like MODE_SUB, but also check the token against the list
368 * of tokens, and if there is a match, return that token. Otherwise,
369 * if the token matches a symbol, return EQN_TOK_SYM; if it matches
370 * a function name, EQN_TOK_FUNC, or else EQN_TOK__MAX. Except for
371 * a token match, *ep->start is set to an allocated string that the
372 * caller is expected to free.
373 * All modes skip whitespace following the end of the token.
374 */
375static enum eqn_tok
376eqn_next(struct eqn_node *ep, enum parse_mode mode)
377{
360 * way and return EQN_TOK_QUOTED. All other modes behave like
361 * MODE_QUOTED when *ep->start is '"'.
362 * MODE_NOSUB: If *ep->start is a curly brace, the token ends after it;
363 * otherwise, it ends before the next whitespace or brace.
364 * Do not interpret the token and return EQN_TOK__MAX.
365 * MODE_SUB: Like MODE_NOSUB, but try to interpret the token as an
366 * alias created with define. If it is an alias, replace it with
367 * its string value and reparse.
368 * MODE_TOK: Like MODE_SUB, but also check the token against the list
369 * of tokens, and if there is a match, return that token. Otherwise,
370 * if the token matches a symbol, return EQN_TOK_SYM; if it matches
371 * a function name, EQN_TOK_FUNC, or else EQN_TOK__MAX. Except for
372 * a token match, *ep->start is set to an allocated string that the
373 * caller is expected to free.
374 * All modes skip whitespace following the end of the token.
375 */
376static enum eqn_tok
377eqn_next(struct eqn_node *ep, enum parse_mode mode)
378{
378 static int last_len, lim;
379
380 struct eqn_def *def;
381 size_t start;
379 struct eqn_def *def;
380 size_t start;
382 int diff, i, quoted;
381 int diff, i, newlen, quoted;
383 enum eqn_tok tok;
384
385 /*
386 * Reset the recursion counter after advancing
382 enum eqn_tok tok;
383
384 /*
385 * Reset the recursion counter after advancing
387 * beyond the end of the previous substitution.
386 * beyond the end of the rightmost substitution.
388 */
387 */
389 if (ep->end - ep->data >= last_len)
390 lim = 0;
388 if (ep->end - ep->data >= ep->sublen)
389 ep->subcnt = 0;
391
392 ep->start = ep->end;
393 quoted = mode == MODE_QUOTED;
394 for (;;) {
395 switch (*ep->start) {
396 case '\0':
397 ep->toksz = 0;
398 return EQN_TOK_EOF;

--- 30 unchanged lines hidden (view full) ---

429 while (*ep->end != '\0' && strchr(" \t^~", *ep->end) != NULL)
430 ep->end++;
431 if (quoted) /* Cannot return, may have to strndup. */
432 break;
433 if (mode == MODE_NOSUB)
434 return EQN_TOK__MAX;
435 if ((def = eqn_def_find(ep)) == NULL)
436 break;
390
391 ep->start = ep->end;
392 quoted = mode == MODE_QUOTED;
393 for (;;) {
394 switch (*ep->start) {
395 case '\0':
396 ep->toksz = 0;
397 return EQN_TOK_EOF;

--- 30 unchanged lines hidden (view full) ---

428 while (*ep->end != '\0' && strchr(" \t^~", *ep->end) != NULL)
429 ep->end++;
430 if (quoted) /* Cannot return, may have to strndup. */
431 break;
432 if (mode == MODE_NOSUB)
433 return EQN_TOK__MAX;
434 if ((def = eqn_def_find(ep)) == NULL)
435 break;
437 if (++lim > EQN_NEST_MAX) {
436 if (++ep->subcnt > EQN_NEST_MAX) {
438 mandoc_msg(MANDOCERR_ROFFLOOP,
439 ep->node->line, ep->node->pos, NULL);
437 mandoc_msg(MANDOCERR_ROFFLOOP,
438 ep->node->line, ep->node->pos, NULL);
440 return EQN_TOK_EOF;
439 break;
441 }
442
443 /* Replace a defined name with its string value. */
444 if ((diff = def->valsz - ep->toksz) > 0) {
445 start = ep->start - ep->data;
446 ep->sz += diff;
447 ep->data = mandoc_realloc(ep->data, ep->sz + 1);
448 ep->start = ep->data + start;
440 }
441
442 /* Replace a defined name with its string value. */
443 if ((diff = def->valsz - ep->toksz) > 0) {
444 start = ep->start - ep->data;
445 ep->sz += diff;
446 ep->data = mandoc_realloc(ep->data, ep->sz + 1);
447 ep->start = ep->data + start;
448 ep->sublen += diff;
449 }
450 if (diff)
451 memmove(ep->start + def->valsz, ep->start + ep->toksz,
452 strlen(ep->start + ep->toksz) + 1);
453 memcpy(ep->start, def->val, def->valsz);
449 }
450 if (diff)
451 memmove(ep->start + def->valsz, ep->start + ep->toksz,
452 strlen(ep->start + ep->toksz) + 1);
453 memcpy(ep->start, def->val, def->valsz);
454 last_len = ep->start - ep->data + def->valsz;
454 newlen = ep->start - ep->data + def->valsz;
455 if (ep->sublen < newlen)
456 ep->sublen = newlen;
455 }
456 if (mode != MODE_TOK)
457 return quoted ? EQN_TOK_QUOTED : EQN_TOK__MAX;
458 if (quoted) {
459 ep->start = mandoc_strndup(ep->start, ep->toksz);
460 return EQN_TOK_QUOTED;
461 }
462 for (tok = 0; tok < EQN_TOK__MAX; tok++)

--- 210 unchanged lines hidden (view full) ---

673 * Empty equation.
674 * Do not add it to the high-level syntax tree.
675 */
676
677 if (ep->data == NULL)
678 return;
679
680 ep->start = ep->end = ep->data;
457 }
458 if (mode != MODE_TOK)
459 return quoted ? EQN_TOK_QUOTED : EQN_TOK__MAX;
460 if (quoted) {
461 ep->start = mandoc_strndup(ep->start, ep->toksz);
462 return EQN_TOK_QUOTED;
463 }
464 for (tok = 0; tok < EQN_TOK__MAX; tok++)

--- 210 unchanged lines hidden (view full) ---

675 * Empty equation.
676 * Do not add it to the high-level syntax tree.
677 */
678
679 if (ep->data == NULL)
680 return;
681
682 ep->start = ep->end = ep->data;
683 ep->sublen = 0;
684 ep->subcnt = 0;
681
682next_tok:
683 tok = eqn_next(ep, MODE_TOK);
684 switch (tok) {
685 case EQN_TOK_UNDEF:
686 eqn_undef(ep);
687 break;
688 case EQN_TOK_NDEFINE:

--- 444 unchanged lines hidden ---
685
686next_tok:
687 tok = eqn_next(ep, MODE_TOK);
688 switch (tok) {
689 case EQN_TOK_UNDEF:
690 eqn_undef(ep);
691 break;
692 case EQN_TOK_NDEFINE:

--- 444 unchanged lines hidden ---