Annotation of mandoc/eqn.c, Revision 1.20
1.20 ! kristaps 1: /* $Id: eqn.c,v 1.19 2011/07/21 15:21:13 kristaps Exp $ */
1.1 kristaps 2: /*
3: * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4: *
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.
8: *
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.
16: */
17: #ifdef HAVE_CONFIG_H
18: #include "config.h"
19: #endif
20:
21: #include <assert.h>
1.19 kristaps 22: #include <limits.h>
1.1 kristaps 23: #include <stdio.h>
24: #include <stdlib.h>
25: #include <string.h>
26: #include <time.h>
27:
28: #include "mandoc.h"
29: #include "libmandoc.h"
30: #include "libroff.h"
31:
1.11 kristaps 32: #define EQN_NEST_MAX 128 /* maximum nesting of defines */
1.12 kristaps 33: #define EQN_MSG(t, x) mandoc_msg((t), (x)->parse, (x)->eqn.ln, (x)->eqn.pos, NULL)
1.8 kristaps 34:
1.20 ! kristaps 35: enum eqn_rest {
! 36: EQN_DESCOPE,
! 37: EQN_ERR,
! 38: EQN_OK,
! 39: EQN_EOF
! 40: };
! 41:
1.17 kristaps 42: struct eqnstr {
1.8 kristaps 43: const char *name;
44: size_t sz;
45: };
46:
1.17 kristaps 47: struct eqnpart {
48: struct eqnstr str;
49: int (*fp)(struct eqn_node *);
1.16 kristaps 50: };
51:
1.8 kristaps 52: enum eqnpartt {
53: EQN_DEFINE = 0,
54: EQN_SET,
55: EQN_UNDEF,
56: EQN__MAX
57: };
58:
1.20 ! kristaps 59: static struct eqn_box *eqn_box_alloc(struct eqn_box *);
1.13 kristaps 60: static void eqn_box_free(struct eqn_box *);
1.12 kristaps 61: static struct eqn_def *eqn_def_find(struct eqn_node *,
62: const char *, size_t);
63: static int eqn_do_define(struct eqn_node *);
1.14 kristaps 64: static int eqn_do_set(struct eqn_node *);
1.12 kristaps 65: static int eqn_do_undef(struct eqn_node *);
66: static const char *eqn_nexttok(struct eqn_node *, size_t *);
1.14 kristaps 67: static const char *eqn_nextrawtok(struct eqn_node *, size_t *);
68: static const char *eqn_next(struct eqn_node *,
69: char, size_t *, int);
1.20 ! kristaps 70: static void eqn_rewind(struct eqn_node *);
! 71: static enum eqn_rest eqn_eqn(struct eqn_node *, struct eqn_box *);
! 72: static enum eqn_rest eqn_box(struct eqn_node *, struct eqn_box *);
1.6 kristaps 73:
1.8 kristaps 74: static const struct eqnpart eqnparts[EQN__MAX] = {
1.17 kristaps 75: { { "define", 6 }, eqn_do_define }, /* EQN_DEFINE */
76: { { "set", 3 }, eqn_do_set }, /* EQN_SET */
77: { { "undef", 5 }, eqn_do_undef }, /* EQN_UNDEF */
1.8 kristaps 78: };
79:
1.17 kristaps 80: static const struct eqnstr eqnmarks[EQNMARK__MAX] = {
1.16 kristaps 81: { "", 0 }, /* EQNMARK_NONE */
82: { "dot", 3 }, /* EQNMARK_DOT */
83: { "dotdot", 6 }, /* EQNMARK_DOTDOT */
84: { "hat", 3 }, /* EQNMARK_HAT */
85: { "tilde", 5 }, /* EQNMARK_TILDE */
86: { "vec", 3 }, /* EQNMARK_VEC */
87: { "dyad", 4 }, /* EQNMARK_DYAD */
88: { "bar", 3 }, /* EQNMARK_BAR */
89: { "under", 5 }, /* EQNMARK_UNDER */
90: };
91:
1.17 kristaps 92: static const struct eqnstr eqnfonts[EQNFONT__MAX] = {
1.20 ! kristaps 93: { "", 0 }, /* EQNFONT_NONE */
! 94: { "roman", 5 }, /* EQNFONT_ROMAN */
! 95: { "bold", 4 }, /* EQNFONT_BOLD */
! 96: { "italic", 6 }, /* EQNFONT_ITALIC */
1.17 kristaps 97: };
98:
1.18 kristaps 99: static const struct eqnstr eqnposs[EQNPOS__MAX] = {
1.20 ! kristaps 100: { "", 0 }, /* EQNPOS_NONE */
! 101: { "over", 4 }, /* EQNPOS_OVER */
! 102: { "sup", 3 }, /* EQNPOS_SUP */
! 103: { "sub", 3 }, /* EQNPOS_SUB */
! 104: { "to", 2 }, /* EQNPOS_TO */
! 105: { "from", 4 }, /* EQNPOS_FROM */
! 106: };
! 107:
! 108: static const struct eqnstr eqnpiles[EQNPILE__MAX] = {
! 109: { "", 0 }, /* EQNPILE_NONE */
! 110: { "cpile", 5 }, /* EQNPILE_CPILE */
! 111: { "rpile", 5 }, /* EQNPILE_RPILE */
! 112: { "lpile", 5 }, /* EQNPILE_LPILE */
1.18 kristaps 113: };
114:
1.1 kristaps 115: /* ARGSUSED */
116: enum rofferr
1.6 kristaps 117: eqn_read(struct eqn_node **epp, int ln,
118: const char *p, int pos, int *offs)
1.1 kristaps 119: {
1.8 kristaps 120: size_t sz;
121: struct eqn_node *ep;
1.12 kristaps 122: enum rofferr er;
123:
124: ep = *epp;
125:
126: /*
127: * If we're the terminating mark, unset our equation status and
128: * validate the full equation.
129: */
1.1 kristaps 130:
131: if (0 == strcmp(p, ".EN")) {
1.12 kristaps 132: er = eqn_end(ep);
1.1 kristaps 133: *epp = NULL;
1.12 kristaps 134: return(er);
1.1 kristaps 135: }
136:
1.12 kristaps 137: /*
138: * Build up the full string, replacing all newlines with regular
139: * whitespace.
140: */
1.6 kristaps 141:
1.12 kristaps 142: sz = strlen(p + pos) + 1;
143: ep->data = mandoc_realloc(ep->data, ep->sz + sz + 1);
1.6 kristaps 144:
1.12 kristaps 145: /* First invocation: nil terminate the string. */
1.8 kristaps 146:
1.12 kristaps 147: if (0 == ep->sz)
148: *ep->data = '\0';
1.8 kristaps 149:
1.12 kristaps 150: ep->sz += sz;
151: strlcat(ep->data, p + pos, ep->sz + 1);
152: strlcat(ep->data, " ", ep->sz + 1);
1.11 kristaps 153: return(ROFF_IGN);
154: }
155:
1.1 kristaps 156: struct eqn_node *
1.5 kristaps 157: eqn_alloc(int pos, int line, struct mparse *parse)
1.1 kristaps 158: {
159: struct eqn_node *p;
160:
161: p = mandoc_calloc(1, sizeof(struct eqn_node));
1.5 kristaps 162: p->parse = parse;
1.12 kristaps 163: p->eqn.ln = line;
1.2 kristaps 164: p->eqn.pos = pos;
1.1 kristaps 165:
166: return(p);
167: }
168:
1.12 kristaps 169: enum rofferr
170: eqn_end(struct eqn_node *ep)
171: {
1.20 ! kristaps 172: struct eqn_box *root;
! 173: enum eqn_rest c;
! 174:
! 175: ep->eqn.root = mandoc_calloc(1, sizeof(struct eqn_box));
1.13 kristaps 176:
1.20 ! kristaps 177: root = ep->eqn.root;
1.13 kristaps 178: root->type = EQN_ROOT;
179:
180: if (0 == ep->sz)
181: return(ROFF_IGN);
1.12 kristaps 182:
1.20 ! kristaps 183: if (EQN_DESCOPE == (c = eqn_eqn(ep, root))) {
! 184: EQN_MSG(MANDOCERR_EQNNSCOPE, ep);
! 185: c = EQN_ERR;
! 186: }
! 187:
! 188: return(EQN_EOF == c ? ROFF_EQN : ROFF_IGN);
! 189: }
! 190:
! 191: static enum eqn_rest
! 192: eqn_eqn(struct eqn_node *ep, struct eqn_box *last)
! 193: {
! 194: struct eqn_box *bp;
! 195: enum eqn_rest c;
! 196:
! 197: bp = eqn_box_alloc(last);
! 198: bp->type = EQN_SUBEXPR;
1.12 kristaps 199:
1.20 ! kristaps 200: while (EQN_OK == (c = eqn_box(ep, bp)))
! 201: /* Spin! */ ;
1.15 kristaps 202:
1.20 ! kristaps 203: return(c);
1.12 kristaps 204: }
205:
1.20 ! kristaps 206: static enum eqn_rest
! 207: eqn_box(struct eqn_node *ep, struct eqn_box *last)
1.1 kristaps 208: {
1.12 kristaps 209: size_t sz;
210: const char *start;
1.20 ! kristaps 211: char *left;
! 212: enum eqn_rest c;
! 213: int i, size;
1.13 kristaps 214: struct eqn_box *bp;
1.12 kristaps 215:
1.20 ! kristaps 216: if (NULL == (start = eqn_nexttok(ep, &sz)))
! 217: return(EQN_EOF);
! 218:
! 219: if (1 == sz && 0 == strncmp("}", start, 1))
! 220: return(EQN_DESCOPE);
! 221: else if (5 == sz && 0 == strncmp("right", start, 5))
! 222: return(EQN_DESCOPE);
! 223: else if (5 == sz && 0 == strncmp("above", start, 5))
! 224: return(EQN_DESCOPE);
! 225:
! 226: for (i = 0; i < (int)EQN__MAX; i++) {
! 227: if (eqnparts[i].str.sz != sz)
! 228: continue;
! 229: if (strncmp(eqnparts[i].str.name, start, sz))
! 230: continue;
! 231: return((*eqnparts[i].fp)(ep) ? EQN_OK : EQN_ERR);
! 232: }
1.15 kristaps 233:
1.20 ! kristaps 234: if (1 == sz && 0 == strncmp("{", start, 1)) {
! 235: if (EQN_DESCOPE != (c = eqn_eqn(ep, last))) {
! 236: if (EQN_ERR != c)
! 237: EQN_MSG(MANDOCERR_EQNSCOPE, ep);
! 238: return(EQN_ERR);
! 239: }
! 240: eqn_rewind(ep);
! 241: start = eqn_nexttok(ep, &sz);
! 242: assert(start);
! 243: if (1 == sz && 0 == strncmp("}", start, 1))
! 244: return(EQN_OK);
! 245: EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
! 246: return(EQN_ERR);
! 247: }
1.12 kristaps 248:
1.20 ! kristaps 249: for (i = 0; i < (int)EQNPILE__MAX; i++) {
! 250: if (eqnpiles[i].sz != sz)
1.17 kristaps 251: continue;
1.20 ! kristaps 252: if (strncmp(eqnpiles[i].name, start, sz))
1.17 kristaps 253: continue;
1.20 ! kristaps 254: if (NULL == (start = eqn_nexttok(ep, &sz))) {
! 255: EQN_MSG(MANDOCERR_EQNEOF, ep);
! 256: return(EQN_ERR);
! 257: }
! 258: if (1 != sz || strncmp("{", start, 1)) {
! 259: EQN_MSG(MANDOCERR_EQNSYNT, ep);
! 260: return(EQN_ERR);
! 261: }
! 262: if (EQN_DESCOPE != (c = eqn_eqn(ep, last))) {
! 263: if (EQN_ERR != c)
! 264: EQN_MSG(MANDOCERR_EQNSCOPE, ep);
! 265: return(EQN_ERR);
! 266: }
! 267: assert(last->last);
! 268: last->last->pile = (enum eqn_pilet)i;
! 269: eqn_rewind(ep);
! 270: start = eqn_nexttok(ep, &sz);
! 271: assert(start);
! 272: if (1 == sz && 0 == strncmp("}", start, 1))
! 273: return(EQN_OK);
! 274: if (5 != sz || strncmp("above", start, 5)) {
! 275: EQN_MSG(MANDOCERR_EQNSYNT, ep);
! 276: return(EQN_ERR);
! 277: }
! 278: last->last->above = 1;
! 279: if (EQN_DESCOPE != (c = eqn_eqn(ep, last))) {
! 280: if (EQN_ERR != c)
! 281: EQN_MSG(MANDOCERR_EQNSCOPE, ep);
! 282: return(EQN_ERR);
! 283: }
! 284: eqn_rewind(ep);
! 285: start = eqn_nexttok(ep, &sz);
! 286: assert(start);
! 287: if (1 == sz && 0 == strncmp("}", start, 1))
! 288: return(EQN_OK);
! 289: EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
! 290: return(EQN_ERR);
1.18 kristaps 291: }
292:
1.20 ! kristaps 293: if (4 == sz && 0 == strncmp("left", start, 4)) {
! 294: if (NULL == (start = eqn_nexttok(ep, &sz))) {
! 295: EQN_MSG(MANDOCERR_EQNEOF, ep);
! 296: return(EQN_ERR);
! 297: }
! 298: left = mandoc_strndup(start, sz);
! 299: if (EQN_DESCOPE != (c = eqn_eqn(ep, last)))
! 300: return(c);
! 301: assert(last->last);
! 302: last->last->left = left;
! 303: eqn_rewind(ep);
! 304: start = eqn_nexttok(ep, &sz);
! 305: assert(start);
! 306: if (5 != sz || strncmp("right", start, 5))
! 307: return(EQN_DESCOPE);
! 308: if (NULL == (start = eqn_nexttok(ep, &sz))) {
! 309: EQN_MSG(MANDOCERR_EQNEOF, ep);
! 310: return(EQN_ERR);
! 311: }
! 312: last->last->right = mandoc_strndup(start, sz);
! 313: return(EQN_OK);
! 314: }
! 315:
! 316: for (i = 0; i < (int)EQNPOS__MAX; i++) {
1.18 kristaps 317: if (eqnposs[i].sz != sz)
318: continue;
319: if (strncmp(eqnposs[i].name, start, sz))
320: continue;
1.20 ! kristaps 321: if (NULL == last->last) {
! 322: EQN_MSG(MANDOCERR_EQNSYNT, ep);
! 323: return(EQN_ERR);
! 324: }
! 325: last->last->pos = (enum eqn_post)i;
! 326: if (EQN_EOF == (c = eqn_box(ep, last))) {
! 327: EQN_MSG(MANDOCERR_EQNEOF, ep);
! 328: return(EQN_ERR);
! 329: }
! 330: return(c);
1.17 kristaps 331: }
332:
1.16 kristaps 333: for (i = 0; i < (int)EQNMARK__MAX; i++) {
334: if (eqnmarks[i].sz != sz)
335: continue;
336: if (strncmp(eqnmarks[i].name, start, sz))
337: continue;
1.20 ! kristaps 338: if (NULL == last->last) {
! 339: EQN_MSG(MANDOCERR_EQNSYNT, ep);
! 340: return(EQN_ERR);
! 341: }
! 342: last->last->mark = (enum eqn_markt)i;
! 343: if (EQN_EOF == (c = eqn_box(ep, last))) {
! 344: EQN_MSG(MANDOCERR_EQNEOF, ep);
! 345: return(EQN_ERR);
! 346: }
! 347: return(c);
1.16 kristaps 348: }
1.12 kristaps 349:
1.20 ! kristaps 350: for (i = 0; i < (int)EQNFONT__MAX; i++) {
! 351: if (eqnfonts[i].sz != sz)
! 352: continue;
! 353: if (strncmp(eqnfonts[i].name, start, sz))
! 354: continue;
! 355: if (EQN_EOF == (c = eqn_box(ep, last))) {
! 356: EQN_MSG(MANDOCERR_EQNEOF, ep);
! 357: return(EQN_ERR);
! 358: } else if (EQN_OK == c)
! 359: last->last->font = (enum eqn_fontt)i;
! 360: return(c);
1.19 kristaps 361: }
1.15 kristaps 362:
1.20 ! kristaps 363: if (4 == sz && 0 == strncmp("size", start, 4)) {
! 364: if (NULL == (start = eqn_nexttok(ep, &sz))) {
! 365: EQN_MSG(MANDOCERR_EQNEOF, ep);
! 366: return(EQN_ERR);
! 367: }
! 368: size = mandoc_strntoi(start, sz, 10);
! 369: if (EQN_EOF == (c = eqn_box(ep, last))) {
! 370: EQN_MSG(MANDOCERR_EQNEOF, ep);
! 371: return(EQN_ERR);
! 372: } else if (EQN_OK != c)
! 373: return(c);
! 374: last->last->size = size;
1.15 kristaps 375: }
376:
1.20 ! kristaps 377: bp = eqn_box_alloc(last);
1.15 kristaps 378: bp->type = EQN_TEXT;
1.20 ! kristaps 379: bp->text = mandoc_strndup(start, sz);
! 380: return(EQN_OK);
1.1 kristaps 381: }
382:
383: void
384: eqn_free(struct eqn_node *p)
385: {
1.6 kristaps 386: int i;
1.1 kristaps 387:
1.13 kristaps 388: eqn_box_free(p->eqn.root);
1.6 kristaps 389:
390: for (i = 0; i < (int)p->defsz; i++) {
391: free(p->defs[i].key);
392: free(p->defs[i].val);
393: }
394:
1.12 kristaps 395: free(p->data);
1.6 kristaps 396: free(p->defs);
1.1 kristaps 397: free(p);
1.6 kristaps 398: }
399:
1.20 ! kristaps 400: static struct eqn_box *
! 401: eqn_box_alloc(struct eqn_box *parent)
! 402: {
! 403: struct eqn_box *bp;
! 404:
! 405: bp = mandoc_calloc(1, sizeof(struct eqn_box));
! 406: bp->parent = parent;
! 407: bp->size = EQN_DEFSIZE;
! 408:
! 409: if (NULL == parent->first)
! 410: parent->first = bp;
! 411: else
! 412: parent->last->next = bp;
! 413:
! 414: parent->last = bp;
! 415: return(bp);
! 416: }
! 417:
1.13 kristaps 418: static void
419: eqn_box_free(struct eqn_box *bp)
420: {
421:
1.20 ! kristaps 422: if (bp->first)
! 423: eqn_box_free(bp->first);
1.13 kristaps 424: if (bp->next)
425: eqn_box_free(bp->next);
426:
427: free(bp->text);
1.20 ! kristaps 428: free(bp->left);
! 429: free(bp->right);
1.13 kristaps 430: free(bp);
431: }
432:
1.6 kristaps 433: static const char *
1.14 kristaps 434: eqn_nextrawtok(struct eqn_node *ep, size_t *sz)
435: {
436:
437: return(eqn_next(ep, '"', sz, 0));
438: }
439:
440: static const char *
1.12 kristaps 441: eqn_nexttok(struct eqn_node *ep, size_t *sz)
442: {
443:
1.14 kristaps 444: return(eqn_next(ep, '"', sz, 1));
1.12 kristaps 445: }
446:
1.20 ! kristaps 447: static void
! 448: eqn_rewind(struct eqn_node *ep)
! 449: {
! 450:
! 451: ep->cur = ep->rew;
! 452: }
! 453:
1.12 kristaps 454: static const char *
1.14 kristaps 455: eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
1.6 kristaps 456: {
1.12 kristaps 457: char *start, *next;
458: int q, diff, lim;
1.20 ! kristaps 459: size_t ssz;
1.12 kristaps 460: struct eqn_def *def;
461:
462: if (NULL == sz)
463: sz = &ssz;
1.6 kristaps 464:
1.13 kristaps 465: lim = 0;
1.20 ! kristaps 466: ep->rew = ep->cur;
1.13 kristaps 467: again:
468: /* Prevent self-definitions. */
469:
470: if (lim >= EQN_NEST_MAX) {
471: EQN_MSG(MANDOCERR_EQNNEST, ep);
472: return(NULL);
473: }
474:
1.20 ! kristaps 475: ep->cur = ep->rew;
1.12 kristaps 476: start = &ep->data[(int)ep->cur];
1.6 kristaps 477: q = 0;
478:
479: if ('\0' == *start)
480: return(NULL);
481:
1.12 kristaps 482: if (quote == *start) {
483: ep->cur++;
1.6 kristaps 484: q = 1;
485: }
486:
1.12 kristaps 487: start = &ep->data[(int)ep->cur];
488: next = q ? strchr(start, quote) : strchr(start, ' ');
489:
490: if (NULL != next) {
491: *sz = (size_t)(next - start);
492: ep->cur += *sz;
1.6 kristaps 493: if (q)
1.12 kristaps 494: ep->cur++;
495: while (' ' == ep->data[(int)ep->cur])
496: ep->cur++;
1.6 kristaps 497: } else {
498: if (q)
1.12 kristaps 499: EQN_MSG(MANDOCERR_BADQUOTE, ep);
500: next = strchr(start, '\0');
501: *sz = (size_t)(next - start);
502: ep->cur += *sz;
503: }
504:
1.13 kristaps 505: /* Quotes aren't expanded for values. */
506:
1.14 kristaps 507: if (q || ! repl)
1.13 kristaps 508: return(start);
509:
1.12 kristaps 510: if (NULL != (def = eqn_def_find(ep, start, *sz))) {
511: diff = def->valsz - *sz;
512:
513: if (def->valsz > *sz) {
514: ep->sz += diff;
515: ep->data = mandoc_realloc(ep->data, ep->sz + 1);
516: ep->data[ep->sz] = '\0';
1.20 ! kristaps 517: start = &ep->data[(int)ep->rew];
1.12 kristaps 518: }
519:
520: diff = def->valsz - *sz;
521: memmove(start + *sz + diff, start + *sz,
522: (strlen(start) - *sz) + 1);
523: memcpy(start, def->val, def->valsz);
524: goto again;
1.6 kristaps 525: }
526:
527: return(start);
1.8 kristaps 528: }
529:
530: static int
1.14 kristaps 531: eqn_do_set(struct eqn_node *ep)
1.8 kristaps 532: {
533: const char *start;
534:
1.14 kristaps 535: if (NULL == (start = eqn_nextrawtok(ep, NULL)))
1.12 kristaps 536: EQN_MSG(MANDOCERR_EQNARGS, ep);
1.14 kristaps 537: else if (NULL == (start = eqn_nextrawtok(ep, NULL)))
1.12 kristaps 538: EQN_MSG(MANDOCERR_EQNARGS, ep);
539: else
540: return(1);
1.8 kristaps 541:
1.12 kristaps 542: return(0);
1.8 kristaps 543: }
544:
545: static int
1.12 kristaps 546: eqn_do_define(struct eqn_node *ep)
1.8 kristaps 547: {
548: const char *start;
549: size_t sz;
1.12 kristaps 550: struct eqn_def *def;
1.8 kristaps 551: int i;
552:
1.14 kristaps 553: if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
1.12 kristaps 554: EQN_MSG(MANDOCERR_EQNARGS, ep);
1.8 kristaps 555: return(0);
556: }
557:
558: /*
559: * Search for a key that already exists.
1.12 kristaps 560: * Create a new key if none is found.
1.8 kristaps 561: */
562:
1.12 kristaps 563: if (NULL == (def = eqn_def_find(ep, start, sz))) {
1.8 kristaps 564: /* Find holes in string array. */
565: for (i = 0; i < (int)ep->defsz; i++)
566: if (0 == ep->defs[i].keysz)
567: break;
568:
569: if (i == (int)ep->defsz) {
570: ep->defsz++;
571: ep->defs = mandoc_realloc
572: (ep->defs, ep->defsz *
573: sizeof(struct eqn_def));
1.9 kristaps 574: ep->defs[i].key = ep->defs[i].val = NULL;
1.8 kristaps 575: }
576:
577: ep->defs[i].keysz = sz;
578: ep->defs[i].key = mandoc_realloc
579: (ep->defs[i].key, sz + 1);
580:
581: memcpy(ep->defs[i].key, start, sz);
582: ep->defs[i].key[(int)sz] = '\0';
1.12 kristaps 583: def = &ep->defs[i];
1.8 kristaps 584: }
585:
1.14 kristaps 586: start = eqn_next(ep, ep->data[(int)ep->cur], &sz, 0);
1.8 kristaps 587:
1.12 kristaps 588: if (NULL == start) {
589: EQN_MSG(MANDOCERR_EQNARGS, ep);
1.8 kristaps 590: return(0);
591: }
592:
1.12 kristaps 593: def->valsz = sz;
1.13 kristaps 594: def->val = mandoc_realloc(def->val, sz + 1);
1.12 kristaps 595: memcpy(def->val, start, sz);
596: def->val[(int)sz] = '\0';
597: return(1);
1.8 kristaps 598: }
599:
600: static int
1.12 kristaps 601: eqn_do_undef(struct eqn_node *ep)
1.8 kristaps 602: {
603: const char *start;
1.12 kristaps 604: struct eqn_def *def;
1.8 kristaps 605: size_t sz;
606:
1.14 kristaps 607: if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
1.12 kristaps 608: EQN_MSG(MANDOCERR_EQNARGS, ep);
609: return(0);
610: } else if (NULL != (def = eqn_def_find(ep, start, sz)))
611: def->keysz = 0;
1.8 kristaps 612:
1.12 kristaps 613: return(1);
614: }
615:
616: static struct eqn_def *
617: eqn_def_find(struct eqn_node *ep, const char *key, size_t sz)
618: {
619: int i;
1.8 kristaps 620:
1.12 kristaps 621: for (i = 0; i < (int)ep->defsz; i++)
622: if (ep->defs[i].keysz && ep->defs[i].keysz == sz &&
623: 0 == strncmp(ep->defs[i].key, key, sz))
624: return(&ep->defs[i]);
1.8 kristaps 625:
1.12 kristaps 626: return(NULL);
1.1 kristaps 627: }
CVSweb