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