]>
git.cameronkatri.com Git - mandoc.git/blob - eqn.c
1 /* $Id: eqn.c,v 1.46 2014/09/28 11:32:08 kristaps Exp $ */
3 * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
29 #include "mandoc_aux.h"
30 #include "libmandoc.h"
33 #define EQN_NEST_MAX 128 /* maximum nesting of defines */
34 #define EQN_MSG(t, x) mandoc_msg((t), (x)->parse, (x)->eqn.ln, (x)->eqn.pos, NULL)
126 #define STRNEQ(p1, sz1, p2, sz2) \
127 ((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1)))
128 #define EQNSTREQ(x, p, sz) \
129 STRNEQ((x)->name, (x)->sz, (p), (sz))
133 int (*fp
)(struct eqn_node
*);
141 static enum eqn_rest
eqn_box(struct eqn_node
*, struct eqn_box
*);
142 static struct eqn_box
*eqn_box_alloc(struct eqn_node
*,
144 static void eqn_box_free(struct eqn_box
*);
145 static struct eqn_def
*eqn_def_find(struct eqn_node
*,
146 const char *, size_t);
147 static int eqn_do_gfont(struct eqn_node
*);
148 static int eqn_do_gsize(struct eqn_node
*);
149 static int eqn_do_define(struct eqn_node
*);
150 static int eqn_do_ign1(struct eqn_node
*);
151 static int eqn_do_ign2(struct eqn_node
*);
152 static int eqn_do_tdefine(struct eqn_node
*);
153 static int eqn_do_undef(struct eqn_node
*);
154 static enum eqn_rest
eqn_eqn(struct eqn_node
*, struct eqn_box
*);
155 static enum eqn_rest
eqn_list(struct eqn_node
*, struct eqn_box
*);
156 static enum eqn_rest
eqn_matrix(struct eqn_node
*, struct eqn_box
*);
157 static const char *eqn_nexttok(struct eqn_node
*, size_t *);
158 static const char *eqn_nextrawtok(struct eqn_node
*, size_t *);
159 static const char *eqn_next(struct eqn_node
*,
160 char, size_t *, int);
161 static void eqn_rewind(struct eqn_node
*);
163 static const struct eqnpart eqnparts
[EQN__MAX
] = {
164 { { "define", 6 }, eqn_do_define
}, /* EQN_DEFINE */
165 { { "ndefine", 7 }, eqn_do_define
}, /* EQN_NDEFINE */
166 { { "tdefine", 7 }, eqn_do_tdefine
}, /* EQN_TDEFINE */
167 { { "set", 3 }, eqn_do_ign2
}, /* EQN_SET */
168 { { "undef", 5 }, eqn_do_undef
}, /* EQN_UNDEF */
169 { { "gfont", 5 }, eqn_do_gfont
}, /* EQN_GFONT */
170 { { "gsize", 5 }, eqn_do_gsize
}, /* EQN_GSIZE */
171 { { "back", 4 }, eqn_do_ign1
}, /* EQN_BACK */
172 { { "fwd", 3 }, eqn_do_ign1
}, /* EQN_FWD */
173 { { "up", 2 }, eqn_do_ign1
}, /* EQN_UP */
174 { { "down", 4 }, eqn_do_ign1
}, /* EQN_DOWN */
177 static const struct eqnstr eqnmarks
[EQNMARK__MAX
] = {
178 { "", 0 }, /* EQNMARK_NONE */
179 { "dot", 3 }, /* EQNMARK_DOT */
180 { "dotdot", 6 }, /* EQNMARK_DOTDOT */
181 { "hat", 3 }, /* EQNMARK_HAT */
182 { "tilde", 5 }, /* EQNMARK_TILDE */
183 { "vec", 3 }, /* EQNMARK_VEC */
184 { "dyad", 4 }, /* EQNMARK_DYAD */
185 { "bar", 3 }, /* EQNMARK_BAR */
186 { "under", 5 }, /* EQNMARK_UNDER */
189 static const struct eqnstr eqnfonts
[EQNFONT__MAX
] = {
190 { "", 0 }, /* EQNFONT_NONE */
191 { "roman", 5 }, /* EQNFONT_ROMAN */
192 { "bold", 4 }, /* EQNFONT_BOLD */
193 { "fat", 3 }, /* EQNFONT_FAT */
194 { "italic", 6 }, /* EQNFONT_ITALIC */
197 static const struct eqnstr eqnposs
[EQNPOS__MAX
] = {
198 { "", 0 }, /* EQNPOS_NONE */
199 { "over", 4 }, /* EQNPOS_OVER */
200 { "sup", 3 }, /* EQNPOS_SUP */
201 { NULL
, 0 }, /* EQNPOS_SUPSUB */
202 { "sub", 3 }, /* EQNPOS_SUB */
203 { "to", 2 }, /* EQNPOS_TO */
204 { "from", 4 }, /* EQNPOS_FROM */
207 static const struct eqnstr eqnpiles
[EQNPILE__MAX
] = {
208 { "", 0 }, /* EQNPILE_NONE */
209 { "pile", 4 }, /* EQNPILE_PILE */
210 { "cpile", 5 }, /* EQNPILE_CPILE */
211 { "rpile", 5 }, /* EQNPILE_RPILE */
212 { "lpile", 5 }, /* EQNPILE_LPILE */
213 { "col", 3 }, /* EQNPILE_COL */
214 { "ccol", 4 }, /* EQNPILE_CCOL */
215 { "rcol", 4 }, /* EQNPILE_RCOL */
216 { "lcol", 4 }, /* EQNPILE_LCOL */
219 static const struct eqnsym eqnsyms
[EQNSYM__MAX
] = {
220 { { "alpha", 5 }, "*a" }, /* EQNSYM_alpha */
221 { { "beta", 4 }, "*b" }, /* EQNSYM_beta */
222 { { "chi", 3 }, "*x" }, /* EQNSYM_chi */
223 { { "delta", 5 }, "*d" }, /* EQNSYM_delta */
224 { { "epsilon", 7 }, "*e" }, /* EQNSYM_epsilon */
225 { { "eta", 3 }, "*y" }, /* EQNSYM_eta */
226 { { "gamma", 5 }, "*g" }, /* EQNSYM_gamma */
227 { { "iota", 4 }, "*i" }, /* EQNSYM_iota */
228 { { "kappa", 5 }, "*k" }, /* EQNSYM_kappa */
229 { { "lambda", 6 }, "*l" }, /* EQNSYM_lambda */
230 { { "mu", 2 }, "*m" }, /* EQNSYM_mu */
231 { { "nu", 2 }, "*n" }, /* EQNSYM_nu */
232 { { "omega", 5 }, "*w" }, /* EQNSYM_omega */
233 { { "omicron", 7 }, "*o" }, /* EQNSYM_omicron */
234 { { "phi", 3 }, "*f" }, /* EQNSYM_phi */
235 { { "pi", 2 }, "*p" }, /* EQNSYM_pi */
236 { { "psi", 2 }, "*q" }, /* EQNSYM_psi */
237 { { "rho", 3 }, "*r" }, /* EQNSYM_rho */
238 { { "sigma", 5 }, "*s" }, /* EQNSYM_sigma */
239 { { "tau", 3 }, "*t" }, /* EQNSYM_tau */
240 { { "theta", 5 }, "*h" }, /* EQNSYM_theta */
241 { { "upsilon", 7 }, "*u" }, /* EQNSYM_upsilon */
242 { { "xi", 2 }, "*c" }, /* EQNSYM_xi */
243 { { "zeta", 4 }, "*z" }, /* EQNSYM_zeta */
244 { { "DELTA", 5 }, "*D" }, /* EQNSYM_DELTA */
245 { { "GAMMA", 5 }, "*G" }, /* EQNSYM_GAMMA */
246 { { "LAMBDA", 6 }, "*L" }, /* EQNSYM_LAMBDA */
247 { { "OMEGA", 5 }, "*W" }, /* EQNSYM_OMEGA */
248 { { "PHI", 3 }, "*F" }, /* EQNSYM_PHI */
249 { { "PI", 2 }, "*P" }, /* EQNSYM_PI */
250 { { "PSI", 3 }, "*Q" }, /* EQNSYM_PSI */
251 { { "SIGMA", 5 }, "*S" }, /* EQNSYM_SIGMA */
252 { { "THETA", 5 }, "*H" }, /* EQNSYM_THETA */
253 { { "UPSILON", 7 }, "*U" }, /* EQNSYM_UPSILON */
254 { { "XI", 2 }, "*C" }, /* EQNSYM_XI */
255 { { "inter", 5 }, "ca" }, /* EQNSYM_inter */
256 { { "union", 5 }, "cu" }, /* EQNSYM_union */
257 { { "prod", 4 }, "product" }, /* EQNSYM_prod */
258 { { "int", 3 }, "integral" }, /* EQNSYM_int */
259 { { "sum", 3 }, "sum" }, /* EQNSYM_sum */
260 { { "grad", 4 }, "gr" }, /* EQNSYM_grad */
261 { { "del", 3 }, "gr" }, /* EQNSYM_del */
262 { { "times", 5 }, "mu" }, /* EQNSYM_times */
263 { { "cdot", 4 }, "pc" }, /* EQNSYM_cdot */
264 { { "nothing", 7 }, "&" }, /* EQNSYM_nothing */
265 { { "approx", 6 }, "~~" }, /* EQNSYM_approx */
266 { { "prime", 5 }, "aq" }, /* EQNSYM_prime */
267 { { "half", 4 }, "12" }, /* EQNSYM_half */
268 { { "partial", 7 }, "pd" }, /* EQNSYM_partial */
269 { { "inf", 3 }, "if" }, /* EQNSYM_inf */
270 { { ">>", 2 }, ">>" }, /* EQNSYM_muchgreat */
271 { { "<<", 2 }, "<<" }, /* EQNSYM_muchless */
272 { { "<-", 2 }, "<-" }, /* EQNSYM_larrow */
273 { { "->", 2 }, "->" }, /* EQNSYM_rarrow */
274 { { "+-", 2 }, "+-" }, /* EQNSYM_pm */
275 { { "!=", 2 }, "!=" }, /* EQNSYM_nequal */
276 { { "==", 2 }, "==" }, /* EQNSYM_equiv */
277 { { "<=", 2 }, "<=" }, /* EQNSYM_lessequal */
278 { { ">=", 2 }, ">=" }, /* EQNSYM_moreequal */
283 eqn_read(struct eqn_node
**epp
, int ln
,
284 const char *p
, int pos
, int *offs
)
293 * If we're the terminating mark, unset our equation status and
294 * validate the full equation.
297 if (0 == strncmp(p
, ".EN", 3)) {
300 while (' ' == *p
|| '\t' == *p
)
304 mandoc_vmsg(MANDOCERR_ARG_SKIP
, ep
->parse
,
305 ln
, pos
, "EN %s", p
);
310 * Build up the full string, replacing all newlines with regular
314 sz
= strlen(p
+ pos
) + 1;
315 ep
->data
= mandoc_realloc(ep
->data
, ep
->sz
+ sz
+ 1);
317 /* First invocation: nil terminate the string. */
323 strlcat(ep
->data
, p
+ pos
, ep
->sz
+ 1);
324 strlcat(ep
->data
, " ", ep
->sz
+ 1);
329 eqn_alloc(const char *name
, int pos
, int line
, struct mparse
*parse
)
335 p
= mandoc_calloc(1, sizeof(struct eqn_node
));
337 if (name
&& '\0' != *name
) {
342 end
= name
+ (int)sz
;
343 } while (' ' == *end
|| '\t' == *end
);
344 p
->eqn
.name
= mandoc_strndup(name
, sz
+ 1);
350 p
->gsize
= EQN_DEFSIZE
;
356 eqn_end(struct eqn_node
**epp
)
359 struct eqn_box
*root
;
365 ep
->eqn
.root
= mandoc_calloc(1, sizeof(struct eqn_box
));
368 root
->type
= EQN_ROOT
;
373 if (EQN_DESCOPE
== (c
= eqn_eqn(ep
, root
))) {
374 EQN_MSG(MANDOCERR_EQNNSCOPE
, ep
);
378 return(EQN_EOF
== c
? ROFF_EQN
: ROFF_IGN
);
382 eqn_eqn(struct eqn_node
*ep
, struct eqn_box
*last
)
387 bp
= eqn_box_alloc(ep
, last
);
388 bp
->type
= EQN_SUBEXPR
;
390 while (EQN_OK
== (c
= eqn_box(ep
, bp
)))
397 eqn_matrix(struct eqn_node
*ep
, struct eqn_box
*last
)
404 bp
= eqn_box_alloc(ep
, last
);
405 bp
->type
= EQN_MATRIX
;
407 if (NULL
== (start
= eqn_nexttok(ep
, &sz
))) {
408 EQN_MSG(MANDOCERR_EQNEOF
, ep
);
411 if ( ! STRNEQ(start
, sz
, "{", 1)) {
412 EQN_MSG(MANDOCERR_EQNSYNT
, ep
);
416 while (EQN_OK
== (c
= eqn_box(ep
, bp
)))
417 switch (bp
->last
->pile
) {
425 EQN_MSG(MANDOCERR_EQNSYNT
, ep
);
429 if (EQN_DESCOPE
!= c
) {
431 EQN_MSG(MANDOCERR_EQNEOF
, ep
);
436 start
= eqn_nexttok(ep
, &sz
);
438 if (STRNEQ(start
, sz
, "}", 1))
441 EQN_MSG(MANDOCERR_EQNBADSCOPE
, ep
);
446 eqn_list(struct eqn_node
*ep
, struct eqn_box
*last
)
453 bp
= eqn_box_alloc(ep
, last
);
456 if (NULL
== (start
= eqn_nexttok(ep
, &sz
))) {
457 EQN_MSG(MANDOCERR_EQNEOF
, ep
);
460 if ( ! STRNEQ(start
, sz
, "{", 1)) {
461 EQN_MSG(MANDOCERR_EQNSYNT
, ep
);
465 while (EQN_DESCOPE
== (c
= eqn_eqn(ep
, bp
))) {
467 start
= eqn_nexttok(ep
, &sz
);
469 if ( ! STRNEQ(start
, sz
, "above", 5))
473 if (EQN_DESCOPE
!= c
) {
475 EQN_MSG(MANDOCERR_EQNSCOPE
, ep
);
480 start
= eqn_nexttok(ep
, &sz
);
482 if (STRNEQ(start
, sz
, "}", 1))
485 EQN_MSG(MANDOCERR_EQNBADSCOPE
, ep
);
490 eqn_box(struct eqn_node
*ep
, struct eqn_box
*last
)
500 if (NULL
== (start
= eqn_nexttok(ep
, &sz
)))
503 if (STRNEQ(start
, sz
, "}", 1))
505 else if (STRNEQ(start
, sz
, "right", 5))
507 else if (STRNEQ(start
, sz
, "above", 5))
509 else if (STRNEQ(start
, sz
, "mark", 4))
511 else if (STRNEQ(start
, sz
, "lineup", 6))
514 for (i
= 0; i
< (int)EQN__MAX
; i
++) {
515 if ( ! EQNSTREQ(&eqnparts
[i
].str
, start
, sz
))
517 return((*eqnparts
[i
].fp
)(ep
) ? EQN_OK
: EQN_ERR
);
520 if (STRNEQ(start
, sz
, "{", 1)) {
521 if (EQN_DESCOPE
!= (c
= eqn_eqn(ep
, last
))) {
523 EQN_MSG(MANDOCERR_EQNSCOPE
, ep
);
527 start
= eqn_nexttok(ep
, &sz
);
529 if (STRNEQ(start
, sz
, "}", 1))
531 EQN_MSG(MANDOCERR_EQNBADSCOPE
, ep
);
535 for (i
= 0; i
< (int)EQNPILE__MAX
; i
++) {
536 if ( ! EQNSTREQ(&eqnpiles
[i
], start
, sz
))
538 if (EQN_OK
== (c
= eqn_list(ep
, last
)))
539 last
->last
->pile
= (enum eqn_pilet
)i
;
543 if (STRNEQ(start
, sz
, "matrix", 6))
544 return(eqn_matrix(ep
, last
));
546 if (STRNEQ(start
, sz
, "left", 4)) {
547 if (NULL
== (start
= eqn_nexttok(ep
, &sz
))) {
548 EQN_MSG(MANDOCERR_EQNEOF
, ep
);
551 left
= mandoc_strndup(start
, sz
);
552 c
= eqn_eqn(ep
, last
);
554 last
->last
->left
= left
;
557 if (EQN_DESCOPE
!= c
)
561 start
= eqn_nexttok(ep
, &sz
);
563 if ( ! STRNEQ(start
, sz
, "right", 5))
565 if (NULL
== (start
= eqn_nexttok(ep
, &sz
))) {
566 EQN_MSG(MANDOCERR_EQNEOF
, ep
);
569 last
->last
->right
= mandoc_strndup(start
, sz
);
574 * Positional elements (e.g., over, sub, sup, ...).
576 for (i
= 0; i
< (int)EQNPOS__MAX
; i
++) {
577 /* Some elements don't have names (are virtual). */
578 if (NULL
== eqnposs
[i
].name
)
580 else if ( ! EQNSTREQ(&eqnposs
[i
], start
, sz
))
582 if (NULL
== last
->last
) {
583 EQN_MSG(MANDOCERR_EQNSYNT
, ep
);
587 * If we encounter x sub y sup z, then according to the
588 * eqn manual, we regard this as x subsup y z.
590 if (EQNPOS_SUP
== i
&&
591 NULL
!= last
->last
->prev
&&
592 EQNPOS_SUB
== last
->last
->prev
->pos
)
593 last
->last
->prev
->pos
= EQNPOS_SUBSUP
;
595 last
->last
->pos
= (enum eqn_post
)i
;
597 if (EQN_EOF
== (c
= eqn_box(ep
, last
))) {
598 EQN_MSG(MANDOCERR_EQNEOF
, ep
);
604 for (i
= 0; i
< (int)EQNMARK__MAX
; i
++) {
605 if ( ! EQNSTREQ(&eqnmarks
[i
], start
, sz
))
607 if (NULL
== last
->last
) {
608 EQN_MSG(MANDOCERR_EQNSYNT
, ep
);
611 last
->last
->mark
= (enum eqn_markt
)i
;
612 if (EQN_EOF
== (c
= eqn_box(ep
, last
))) {
613 EQN_MSG(MANDOCERR_EQNEOF
, ep
);
619 for (i
= 0; i
< (int)EQNFONT__MAX
; i
++) {
620 if ( ! EQNSTREQ(&eqnfonts
[i
], start
, sz
))
622 if (EQN_EOF
== (c
= eqn_box(ep
, last
))) {
623 EQN_MSG(MANDOCERR_EQNEOF
, ep
);
625 } else if (EQN_OK
== c
)
626 last
->last
->font
= (enum eqn_fontt
)i
;
630 if (STRNEQ(start
, sz
, "size", 4)) {
631 if (NULL
== (start
= eqn_nexttok(ep
, &sz
))) {
632 EQN_MSG(MANDOCERR_EQNEOF
, ep
);
635 size
= mandoc_strntoi(start
, sz
, 10);
636 if (EQN_EOF
== (c
= eqn_box(ep
, last
))) {
637 EQN_MSG(MANDOCERR_EQNEOF
, ep
);
639 } else if (EQN_OK
!= c
)
641 last
->last
->size
= size
;
644 bp
= eqn_box_alloc(ep
, last
);
646 for (i
= 0; i
< (int)EQNSYM__MAX
; i
++)
647 if (EQNSTREQ(&eqnsyms
[i
].str
, start
, sz
)) {
649 (void)snprintf(sym
, 62, "\\[%s]", eqnsyms
[i
].sym
);
650 bp
->text
= mandoc_strdup(sym
);
654 bp
->text
= mandoc_strndup(start
, sz
);
659 eqn_free(struct eqn_node
*p
)
663 eqn_box_free(p
->eqn
.root
);
665 for (i
= 0; i
< (int)p
->defsz
; i
++) {
666 free(p
->defs
[i
].key
);
667 free(p
->defs
[i
].val
);
676 static struct eqn_box
*
677 eqn_box_alloc(struct eqn_node
*ep
, struct eqn_box
*parent
)
681 bp
= mandoc_calloc(1, sizeof(struct eqn_box
));
683 bp
->size
= ep
->gsize
;
685 if (NULL
!= parent
->first
) {
686 parent
->last
->next
= bp
;
687 bp
->prev
= parent
->last
;
696 eqn_box_free(struct eqn_box
*bp
)
700 eqn_box_free(bp
->first
);
702 eqn_box_free(bp
->next
);
711 eqn_nextrawtok(struct eqn_node
*ep
, size_t *sz
)
714 return(eqn_next(ep
, '"', sz
, 0));
718 eqn_nexttok(struct eqn_node
*ep
, size_t *sz
)
721 return(eqn_next(ep
, '"', sz
, 1));
725 eqn_rewind(struct eqn_node
*ep
)
732 eqn_next(struct eqn_node
*ep
, char quote
, size_t *sz
, int repl
)
745 /* Prevent self-definitions. */
747 if (lim
>= EQN_NEST_MAX
) {
748 EQN_MSG(MANDOCERR_ROFFLOOP
, ep
);
753 start
= &ep
->data
[(int)ep
->cur
];
759 if (quote
== *start
) {
764 start
= &ep
->data
[(int)ep
->cur
];
767 if ('{' == *start
|| '}' == *start
)
770 ssz
= strcspn(start
+ 1, " ^~\"{}\t") + 1;
771 next
= start
+ (int)ssz
;
775 next
= strchr(start
, quote
);
778 *sz
= (size_t)(next
- start
);
782 while (' ' == ep
->data
[(int)ep
->cur
] ||
783 '\t' == ep
->data
[(int)ep
->cur
] ||
784 '^' == ep
->data
[(int)ep
->cur
] ||
785 '~' == ep
->data
[(int)ep
->cur
])
789 EQN_MSG(MANDOCERR_ARG_QUOTE
, ep
);
790 next
= strchr(start
, '\0');
791 *sz
= (size_t)(next
- start
);
795 /* Quotes aren't expanded for values. */
800 if (NULL
!= (def
= eqn_def_find(ep
, start
, *sz
))) {
801 diff
= def
->valsz
- *sz
;
803 if (def
->valsz
> *sz
) {
805 ep
->data
= mandoc_realloc(ep
->data
, ep
->sz
+ 1);
806 ep
->data
[ep
->sz
] = '\0';
807 start
= &ep
->data
[(int)ep
->rew
];
810 diff
= def
->valsz
- *sz
;
811 memmove(start
+ *sz
+ diff
, start
+ *sz
,
812 (strlen(start
) - *sz
) + 1);
813 memcpy(start
, def
->val
, def
->valsz
);
821 eqn_do_ign1(struct eqn_node
*ep
)
824 if (NULL
== eqn_nextrawtok(ep
, NULL
))
825 EQN_MSG(MANDOCERR_EQNEOF
, ep
);
833 eqn_do_ign2(struct eqn_node
*ep
)
836 if (NULL
== eqn_nextrawtok(ep
, NULL
))
837 EQN_MSG(MANDOCERR_EQNEOF
, ep
);
838 else if (NULL
== eqn_nextrawtok(ep
, NULL
))
839 EQN_MSG(MANDOCERR_EQNEOF
, ep
);
847 eqn_do_tdefine(struct eqn_node
*ep
)
850 if (NULL
== eqn_nextrawtok(ep
, NULL
))
851 EQN_MSG(MANDOCERR_EQNEOF
, ep
);
852 else if (NULL
== eqn_next(ep
, ep
->data
[(int)ep
->cur
], NULL
, 0))
853 EQN_MSG(MANDOCERR_EQNEOF
, ep
);
861 eqn_do_define(struct eqn_node
*ep
)
868 if (NULL
== (start
= eqn_nextrawtok(ep
, &sz
))) {
869 EQN_MSG(MANDOCERR_EQNEOF
, ep
);
874 * Search for a key that already exists.
875 * Create a new key if none is found.
878 if (NULL
== (def
= eqn_def_find(ep
, start
, sz
))) {
879 /* Find holes in string array. */
880 for (i
= 0; i
< (int)ep
->defsz
; i
++)
881 if (0 == ep
->defs
[i
].keysz
)
884 if (i
== (int)ep
->defsz
) {
886 ep
->defs
= mandoc_reallocarray(ep
->defs
,
887 ep
->defsz
, sizeof(struct eqn_def
));
888 ep
->defs
[i
].key
= ep
->defs
[i
].val
= NULL
;
891 ep
->defs
[i
].keysz
= sz
;
892 ep
->defs
[i
].key
= mandoc_realloc(
893 ep
->defs
[i
].key
, sz
+ 1);
895 memcpy(ep
->defs
[i
].key
, start
, sz
);
896 ep
->defs
[i
].key
[(int)sz
] = '\0';
900 start
= eqn_next(ep
, ep
->data
[(int)ep
->cur
], &sz
, 0);
903 EQN_MSG(MANDOCERR_EQNEOF
, ep
);
908 def
->val
= mandoc_realloc(def
->val
, sz
+ 1);
909 memcpy(def
->val
, start
, sz
);
910 def
->val
[(int)sz
] = '\0';
915 eqn_do_gfont(struct eqn_node
*ep
)
918 if (NULL
== eqn_nextrawtok(ep
, NULL
)) {
919 EQN_MSG(MANDOCERR_EQNEOF
, ep
);
926 eqn_do_gsize(struct eqn_node
*ep
)
931 if (NULL
== (start
= eqn_nextrawtok(ep
, &sz
))) {
932 EQN_MSG(MANDOCERR_EQNEOF
, ep
);
935 ep
->gsize
= mandoc_strntoi(start
, sz
, 10);
940 eqn_do_undef(struct eqn_node
*ep
)
946 if (NULL
== (start
= eqn_nextrawtok(ep
, &sz
))) {
947 EQN_MSG(MANDOCERR_EQNEOF
, ep
);
949 } else if (NULL
!= (def
= eqn_def_find(ep
, start
, sz
)))
955 static struct eqn_def
*
956 eqn_def_find(struct eqn_node
*ep
, const char *key
, size_t sz
)
960 for (i
= 0; i
< (int)ep
->defsz
; i
++)
961 if (ep
->defs
[i
].keysz
&& STRNEQ(ep
->defs
[i
].key
,
962 ep
->defs
[i
].keysz
, key
, sz
))
963 return(&ep
->defs
[i
]);