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