Annotation of mandoc/eqn.c, Revision 1.25
1.25 ! kristaps 1: /* $Id: eqn.c,v 1.24 2011/07/22 10:22:47 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);
312: if (EQN_DESCOPE != (c = eqn_eqn(ep, last)))
313: return(c);
314: assert(last->last);
315: last->last->left = left;
316: eqn_rewind(ep);
317: start = eqn_nexttok(ep, &sz);
318: assert(start);
1.24 kristaps 319: if (STRNEQ(start, sz, "right", 5))
1.20 kristaps 320: return(EQN_DESCOPE);
321: if (NULL == (start = eqn_nexttok(ep, &sz))) {
322: EQN_MSG(MANDOCERR_EQNEOF, ep);
323: return(EQN_ERR);
324: }
325: last->last->right = mandoc_strndup(start, sz);
326: return(EQN_OK);
327: }
328:
329: for (i = 0; i < (int)EQNPOS__MAX; i++) {
1.24 kristaps 330: if ( ! EQNSTREQ(&eqnposs[i], start, sz))
1.18 kristaps 331: continue;
1.20 kristaps 332: if (NULL == last->last) {
333: EQN_MSG(MANDOCERR_EQNSYNT, ep);
334: return(EQN_ERR);
335: }
336: last->last->pos = (enum eqn_post)i;
337: if (EQN_EOF == (c = eqn_box(ep, last))) {
338: EQN_MSG(MANDOCERR_EQNEOF, ep);
339: return(EQN_ERR);
340: }
341: return(c);
1.17 kristaps 342: }
343:
1.16 kristaps 344: for (i = 0; i < (int)EQNMARK__MAX; i++) {
1.24 kristaps 345: if ( ! EQNSTREQ(&eqnmarks[i], start, sz))
1.16 kristaps 346: continue;
1.20 kristaps 347: if (NULL == last->last) {
348: EQN_MSG(MANDOCERR_EQNSYNT, ep);
349: return(EQN_ERR);
350: }
351: last->last->mark = (enum eqn_markt)i;
352: if (EQN_EOF == (c = eqn_box(ep, last))) {
353: EQN_MSG(MANDOCERR_EQNEOF, ep);
354: return(EQN_ERR);
355: }
356: return(c);
1.16 kristaps 357: }
1.12 kristaps 358:
1.20 kristaps 359: for (i = 0; i < (int)EQNFONT__MAX; i++) {
1.24 kristaps 360: if ( ! EQNSTREQ(&eqnfonts[i], start, sz))
1.20 kristaps 361: continue;
362: if (EQN_EOF == (c = eqn_box(ep, last))) {
363: EQN_MSG(MANDOCERR_EQNEOF, ep);
364: return(EQN_ERR);
365: } else if (EQN_OK == c)
366: last->last->font = (enum eqn_fontt)i;
367: return(c);
1.19 kristaps 368: }
1.15 kristaps 369:
1.24 kristaps 370: if (STRNEQ(start, sz, "size", 4)) {
1.20 kristaps 371: if (NULL == (start = eqn_nexttok(ep, &sz))) {
372: EQN_MSG(MANDOCERR_EQNEOF, ep);
373: return(EQN_ERR);
374: }
375: size = mandoc_strntoi(start, sz, 10);
376: if (EQN_EOF == (c = eqn_box(ep, last))) {
377: EQN_MSG(MANDOCERR_EQNEOF, ep);
378: return(EQN_ERR);
379: } else if (EQN_OK != c)
380: return(c);
381: last->last->size = size;
1.15 kristaps 382: }
383:
1.20 kristaps 384: bp = eqn_box_alloc(last);
1.15 kristaps 385: bp->type = EQN_TEXT;
1.20 kristaps 386: bp->text = mandoc_strndup(start, sz);
387: return(EQN_OK);
1.1 kristaps 388: }
389:
390: void
391: eqn_free(struct eqn_node *p)
392: {
1.6 kristaps 393: int i;
1.1 kristaps 394:
1.13 kristaps 395: eqn_box_free(p->eqn.root);
1.6 kristaps 396:
397: for (i = 0; i < (int)p->defsz; i++) {
398: free(p->defs[i].key);
399: free(p->defs[i].val);
400: }
401:
1.12 kristaps 402: free(p->data);
1.6 kristaps 403: free(p->defs);
1.1 kristaps 404: free(p);
1.6 kristaps 405: }
406:
1.20 kristaps 407: static struct eqn_box *
408: eqn_box_alloc(struct eqn_box *parent)
409: {
410: struct eqn_box *bp;
411:
412: bp = mandoc_calloc(1, sizeof(struct eqn_box));
413: bp->parent = parent;
414: bp->size = EQN_DEFSIZE;
415:
416: if (NULL == parent->first)
417: parent->first = bp;
418: else
419: parent->last->next = bp;
420:
421: parent->last = bp;
422: return(bp);
423: }
424:
1.13 kristaps 425: static void
426: eqn_box_free(struct eqn_box *bp)
427: {
428:
1.20 kristaps 429: if (bp->first)
430: eqn_box_free(bp->first);
1.13 kristaps 431: if (bp->next)
432: eqn_box_free(bp->next);
433:
434: free(bp->text);
1.20 kristaps 435: free(bp->left);
436: free(bp->right);
1.13 kristaps 437: free(bp);
438: }
439:
1.6 kristaps 440: static const char *
1.14 kristaps 441: eqn_nextrawtok(struct eqn_node *ep, size_t *sz)
442: {
443:
444: return(eqn_next(ep, '"', sz, 0));
445: }
446:
447: static const char *
1.12 kristaps 448: eqn_nexttok(struct eqn_node *ep, size_t *sz)
449: {
450:
1.14 kristaps 451: return(eqn_next(ep, '"', sz, 1));
1.12 kristaps 452: }
453:
1.20 kristaps 454: static void
455: eqn_rewind(struct eqn_node *ep)
456: {
457:
458: ep->cur = ep->rew;
459: }
460:
1.12 kristaps 461: static const char *
1.14 kristaps 462: eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
1.6 kristaps 463: {
1.12 kristaps 464: char *start, *next;
465: int q, diff, lim;
1.22 kristaps 466: size_t ssz, dummy;
1.12 kristaps 467: struct eqn_def *def;
468:
469: if (NULL == sz)
1.22 kristaps 470: sz = &dummy;
1.6 kristaps 471:
1.13 kristaps 472: lim = 0;
1.20 kristaps 473: ep->rew = ep->cur;
1.13 kristaps 474: again:
475: /* Prevent self-definitions. */
476:
477: if (lim >= EQN_NEST_MAX) {
478: EQN_MSG(MANDOCERR_EQNNEST, ep);
479: return(NULL);
480: }
481:
1.20 kristaps 482: ep->cur = ep->rew;
1.12 kristaps 483: start = &ep->data[(int)ep->cur];
1.6 kristaps 484: q = 0;
485:
486: if ('\0' == *start)
487: return(NULL);
488:
1.12 kristaps 489: if (quote == *start) {
490: ep->cur++;
1.6 kristaps 491: q = 1;
492: }
493:
1.12 kristaps 494: start = &ep->data[(int)ep->cur];
1.22 kristaps 495:
496: if ( ! q) {
497: if ('{' == *start || '}' == *start)
498: ssz = 1;
499: else
500: ssz = strcspn(start + 1, " ~\"{}\t") + 1;
501: next = start + (int)ssz;
502: if ('\0' == *next)
503: next = NULL;
504: } else
505: next = strchr(start, quote);
1.12 kristaps 506:
507: if (NULL != next) {
508: *sz = (size_t)(next - start);
509: ep->cur += *sz;
1.6 kristaps 510: if (q)
1.12 kristaps 511: ep->cur++;
1.22 kristaps 512: while (' ' == ep->data[(int)ep->cur] ||
513: '\t' == ep->data[(int)ep->cur] ||
514: '~' == ep->data[(int)ep->cur])
1.12 kristaps 515: ep->cur++;
1.6 kristaps 516: } else {
517: if (q)
1.12 kristaps 518: EQN_MSG(MANDOCERR_BADQUOTE, ep);
519: next = strchr(start, '\0');
520: *sz = (size_t)(next - start);
521: ep->cur += *sz;
522: }
523:
1.13 kristaps 524: /* Quotes aren't expanded for values. */
525:
1.14 kristaps 526: if (q || ! repl)
1.13 kristaps 527: return(start);
528:
1.12 kristaps 529: if (NULL != (def = eqn_def_find(ep, start, *sz))) {
530: diff = def->valsz - *sz;
531:
532: if (def->valsz > *sz) {
533: ep->sz += diff;
534: ep->data = mandoc_realloc(ep->data, ep->sz + 1);
535: ep->data[ep->sz] = '\0';
1.20 kristaps 536: start = &ep->data[(int)ep->rew];
1.12 kristaps 537: }
538:
539: diff = def->valsz - *sz;
540: memmove(start + *sz + diff, start + *sz,
541: (strlen(start) - *sz) + 1);
542: memcpy(start, def->val, def->valsz);
543: goto again;
1.6 kristaps 544: }
545:
546: return(start);
1.8 kristaps 547: }
548:
549: static int
1.14 kristaps 550: eqn_do_set(struct eqn_node *ep)
1.8 kristaps 551: {
552: const char *start;
553:
1.14 kristaps 554: if (NULL == (start = eqn_nextrawtok(ep, NULL)))
1.12 kristaps 555: EQN_MSG(MANDOCERR_EQNARGS, ep);
1.14 kristaps 556: else if (NULL == (start = eqn_nextrawtok(ep, NULL)))
1.12 kristaps 557: EQN_MSG(MANDOCERR_EQNARGS, ep);
558: else
559: return(1);
1.8 kristaps 560:
1.12 kristaps 561: return(0);
1.8 kristaps 562: }
563:
564: static int
1.12 kristaps 565: eqn_do_define(struct eqn_node *ep)
1.8 kristaps 566: {
567: const char *start;
568: size_t sz;
1.12 kristaps 569: struct eqn_def *def;
1.8 kristaps 570: int i;
571:
1.14 kristaps 572: if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
1.12 kristaps 573: EQN_MSG(MANDOCERR_EQNARGS, ep);
1.8 kristaps 574: return(0);
575: }
576:
577: /*
578: * Search for a key that already exists.
1.12 kristaps 579: * Create a new key if none is found.
1.8 kristaps 580: */
581:
1.12 kristaps 582: if (NULL == (def = eqn_def_find(ep, start, sz))) {
1.8 kristaps 583: /* Find holes in string array. */
584: for (i = 0; i < (int)ep->defsz; i++)
585: if (0 == ep->defs[i].keysz)
586: break;
587:
588: if (i == (int)ep->defsz) {
589: ep->defsz++;
590: ep->defs = mandoc_realloc
591: (ep->defs, ep->defsz *
592: sizeof(struct eqn_def));
1.9 kristaps 593: ep->defs[i].key = ep->defs[i].val = NULL;
1.8 kristaps 594: }
595:
596: ep->defs[i].keysz = sz;
597: ep->defs[i].key = mandoc_realloc
598: (ep->defs[i].key, sz + 1);
599:
600: memcpy(ep->defs[i].key, start, sz);
601: ep->defs[i].key[(int)sz] = '\0';
1.12 kristaps 602: def = &ep->defs[i];
1.8 kristaps 603: }
604:
1.14 kristaps 605: start = eqn_next(ep, ep->data[(int)ep->cur], &sz, 0);
1.8 kristaps 606:
1.12 kristaps 607: if (NULL == start) {
608: EQN_MSG(MANDOCERR_EQNARGS, ep);
1.8 kristaps 609: return(0);
610: }
611:
1.12 kristaps 612: def->valsz = sz;
1.13 kristaps 613: def->val = mandoc_realloc(def->val, sz + 1);
1.12 kristaps 614: memcpy(def->val, start, sz);
615: def->val[(int)sz] = '\0';
616: return(1);
1.8 kristaps 617: }
618:
619: static int
1.12 kristaps 620: eqn_do_undef(struct eqn_node *ep)
1.8 kristaps 621: {
622: const char *start;
1.12 kristaps 623: struct eqn_def *def;
1.8 kristaps 624: size_t sz;
625:
1.14 kristaps 626: if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
1.12 kristaps 627: EQN_MSG(MANDOCERR_EQNARGS, ep);
628: return(0);
629: } else if (NULL != (def = eqn_def_find(ep, start, sz)))
630: def->keysz = 0;
1.8 kristaps 631:
1.12 kristaps 632: return(1);
633: }
634:
635: static struct eqn_def *
636: eqn_def_find(struct eqn_node *ep, const char *key, size_t sz)
637: {
638: int i;
1.8 kristaps 639:
1.12 kristaps 640: for (i = 0; i < (int)ep->defsz; i++)
1.24 kristaps 641: if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key,
642: ep->defs[i].keysz, key, sz))
1.12 kristaps 643: return(&ep->defs[i]);
1.8 kristaps 644:
1.12 kristaps 645: return(NULL);
1.1 kristaps 646: }
CVSweb