Annotation of mandoc/eqn.c, Revision 1.19
1.19 ! kristaps 1: /* $Id: eqn.c,v 1.18 2011/07/21 14:13:00 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.17 kristaps 35: struct eqnstr {
1.8 kristaps 36: const char *name;
37: size_t sz;
38: };
39:
1.17 kristaps 40: struct eqnpart {
41: struct eqnstr str;
42: int (*fp)(struct eqn_node *);
1.16 kristaps 43: };
44:
1.8 kristaps 45: enum eqnpartt {
46: EQN_DEFINE = 0,
47: EQN_SET,
48: EQN_UNDEF,
49: EQN__MAX
50: };
51:
1.13 kristaps 52: static void eqn_box_free(struct eqn_box *);
1.12 kristaps 53: static struct eqn_def *eqn_def_find(struct eqn_node *,
54: const char *, size_t);
55: static int eqn_do_define(struct eqn_node *);
1.14 kristaps 56: static int eqn_do_set(struct eqn_node *);
1.12 kristaps 57: static int eqn_do_undef(struct eqn_node *);
58: static const char *eqn_nexttok(struct eqn_node *, size_t *);
1.14 kristaps 59: static const char *eqn_nextrawtok(struct eqn_node *, size_t *);
60: static const char *eqn_next(struct eqn_node *,
61: char, size_t *, int);
1.15 kristaps 62: static int eqn_box(struct eqn_node *,
63: struct eqn_box *, struct eqn_box **);
1.6 kristaps 64:
1.8 kristaps 65: static const struct eqnpart eqnparts[EQN__MAX] = {
1.17 kristaps 66: { { "define", 6 }, eqn_do_define }, /* EQN_DEFINE */
67: { { "set", 3 }, eqn_do_set }, /* EQN_SET */
68: { { "undef", 5 }, eqn_do_undef }, /* EQN_UNDEF */
1.8 kristaps 69: };
70:
1.17 kristaps 71: static const struct eqnstr eqnmarks[EQNMARK__MAX] = {
1.16 kristaps 72: { "", 0 }, /* EQNMARK_NONE */
73: { "dot", 3 }, /* EQNMARK_DOT */
74: { "dotdot", 6 }, /* EQNMARK_DOTDOT */
75: { "hat", 3 }, /* EQNMARK_HAT */
76: { "tilde", 5 }, /* EQNMARK_TILDE */
77: { "vec", 3 }, /* EQNMARK_VEC */
78: { "dyad", 4 }, /* EQNMARK_DYAD */
79: { "bar", 3 }, /* EQNMARK_BAR */
80: { "under", 5 }, /* EQNMARK_UNDER */
81: };
82:
1.17 kristaps 83: static const struct eqnstr eqnfonts[EQNFONT__MAX] = {
1.18 kristaps 84: { "", 0 },
1.17 kristaps 85: { "roman", 5 },
86: { "bold", 4 },
87: { "italic", 6 },
88: };
89:
1.18 kristaps 90: static const struct eqnstr eqnposs[EQNPOS__MAX] = {
91: { "", 0 },
92: { "over", 4 },
93: { "sup", 3 },
94: { "sub", 3 },
95: { "to", 2 },
96: { "from", 4 },
97: { "above", 5 },
98: };
99:
1.1 kristaps 100: /* ARGSUSED */
101: enum rofferr
1.6 kristaps 102: eqn_read(struct eqn_node **epp, int ln,
103: const char *p, int pos, int *offs)
1.1 kristaps 104: {
1.8 kristaps 105: size_t sz;
106: struct eqn_node *ep;
1.12 kristaps 107: enum rofferr er;
108:
109: ep = *epp;
110:
111: /*
112: * If we're the terminating mark, unset our equation status and
113: * validate the full equation.
114: */
1.1 kristaps 115:
116: if (0 == strcmp(p, ".EN")) {
1.12 kristaps 117: er = eqn_end(ep);
1.1 kristaps 118: *epp = NULL;
1.12 kristaps 119: return(er);
1.1 kristaps 120: }
121:
1.12 kristaps 122: /*
123: * Build up the full string, replacing all newlines with regular
124: * whitespace.
125: */
1.6 kristaps 126:
1.12 kristaps 127: sz = strlen(p + pos) + 1;
128: ep->data = mandoc_realloc(ep->data, ep->sz + sz + 1);
1.6 kristaps 129:
1.12 kristaps 130: /* First invocation: nil terminate the string. */
1.8 kristaps 131:
1.12 kristaps 132: if (0 == ep->sz)
133: *ep->data = '\0';
1.8 kristaps 134:
1.12 kristaps 135: ep->sz += sz;
136: strlcat(ep->data, p + pos, ep->sz + 1);
137: strlcat(ep->data, " ", ep->sz + 1);
1.11 kristaps 138: return(ROFF_IGN);
139: }
140:
1.1 kristaps 141: struct eqn_node *
1.5 kristaps 142: eqn_alloc(int pos, int line, struct mparse *parse)
1.1 kristaps 143: {
144: struct eqn_node *p;
145:
146: p = mandoc_calloc(1, sizeof(struct eqn_node));
1.5 kristaps 147: p->parse = parse;
1.12 kristaps 148: p->eqn.ln = line;
1.2 kristaps 149: p->eqn.pos = pos;
1.1 kristaps 150:
151: return(p);
152: }
153:
1.12 kristaps 154: enum rofferr
155: eqn_end(struct eqn_node *ep)
156: {
1.15 kristaps 157: struct eqn_box *root, *last;
158: int c;
1.13 kristaps 159:
160: ep->eqn.root = root =
161: mandoc_calloc(1, sizeof(struct eqn_box));
162: root->type = EQN_ROOT;
163:
164: if (0 == ep->sz)
165: return(ROFF_IGN);
1.12 kristaps 166:
167: /*
1.15 kristaps 168: * Run the parser.
169: * If we return before reaching the end of our input, our scope
170: * is still open somewhere.
171: * If we return alright but don't have a symmetric scoping, then
172: * something's not right either.
173: * Otherwise, return the equation.
1.12 kristaps 174: */
175:
1.16 kristaps 176: if (0 == (c = eqn_box(ep, root, &last))) {
177: if (last != root) {
178: EQN_MSG(MANDOCERR_EQNSCOPE, ep);
179: c = 0;
180: }
181: } else if (c > 0)
1.15 kristaps 182: EQN_MSG(MANDOCERR_EQNNSCOPE, ep);
183:
1.16 kristaps 184: return(0 == c ? ROFF_EQN : ROFF_IGN);
1.12 kristaps 185: }
186:
187: static int
1.15 kristaps 188: eqn_box(struct eqn_node *ep, struct eqn_box *last, struct eqn_box **sv)
1.1 kristaps 189: {
1.12 kristaps 190: size_t sz;
191: const char *start;
1.19 ! kristaps 192: int c, i, nextc, size;
1.17 kristaps 193: enum eqn_fontt font;
1.13 kristaps 194: struct eqn_box *bp;
1.12 kristaps 195:
1.15 kristaps 196: /*
197: * Mark our last level of subexpression.
198: * Also mark whether that the next node should be a
199: * subexpression node.
200: */
201:
202: *sv = last;
1.13 kristaps 203: nextc = 1;
1.18 kristaps 204: font = EQNFONT_NONE;
1.19 ! kristaps 205: size = EQN_DEFSIZE;
1.13 kristaps 206: again:
1.12 kristaps 207: if (NULL == (start = eqn_nexttok(ep, &sz)))
208: return(0);
209:
1.17 kristaps 210: for (i = 0; i < (int)EQNFONT__MAX; i++) {
211: if (eqnfonts[i].sz != sz)
212: continue;
213: if (strncmp(eqnfonts[i].name, start, sz))
214: continue;
215: font = (enum eqn_fontt)i;
1.18 kristaps 216: goto again;
217: }
218:
219: for (i = 0; i < (int)EQNFONT__MAX; i++) {
220: if (eqnposs[i].sz != sz)
221: continue;
222: if (strncmp(eqnposs[i].name, start, sz))
223: continue;
224: last->pos = (enum eqn_post)i;
1.17 kristaps 225: goto again;
226: }
227:
1.12 kristaps 228: for (i = 0; i < (int)EQN__MAX; i++) {
1.17 kristaps 229: if (eqnparts[i].str.sz != sz)
1.12 kristaps 230: continue;
1.17 kristaps 231: if (strncmp(eqnparts[i].str.name, start, sz))
1.12 kristaps 232: continue;
233: if ( ! (*eqnparts[i].fp)(ep))
234: return(-1);
1.13 kristaps 235: goto again;
1.12 kristaps 236: }
1.16 kristaps 237:
238: for (i = 0; i < (int)EQNMARK__MAX; i++) {
239: if (eqnmarks[i].sz != sz)
240: continue;
241: if (strncmp(eqnmarks[i].name, start, sz))
242: continue;
243: last->mark = (enum eqn_markt)i;
244: goto again;
245: }
1.12 kristaps 246:
1.19 ! kristaps 247: if (sz == 4 && 0 == strncmp("size", start, 1)) {
! 248: if (NULL == (start = eqn_nexttok(ep, &sz)))
! 249: return(0);
! 250: size = mandoc_strntoi(start, sz, 10);
! 251: goto again;
! 252: }
1.15 kristaps 253:
254: if (sz == 1 && 0 == strncmp("}", start, 1))
255: return(1);
256:
1.13 kristaps 257: bp = mandoc_calloc(1, sizeof(struct eqn_box));
1.17 kristaps 258: bp->font = font;
1.19 ! kristaps 259: bp->size = size;
! 260:
1.17 kristaps 261: font = EQNFONT_NONE;
1.19 ! kristaps 262: size = EQN_DEFSIZE;
1.17 kristaps 263:
1.13 kristaps 264: if (nextc)
265: last->child = bp;
266: else
267: last->next = bp;
1.1 kristaps 268:
1.15 kristaps 269: last = bp;
270:
271: /*
272: * See if we're to open a new subexpression.
273: * If so, mark our node as such and descend.
274: */
275:
276: if (sz == 1 && 0 == strncmp("{", start, 1)) {
277: bp->type = EQN_SUBEXPR;
278: c = eqn_box(ep, bp, sv);
279:
280: nextc = 0;
281: goto again;
282: }
283:
284: /* A regular text node. */
285:
286: bp->type = EQN_TEXT;
1.13 kristaps 287: bp->text = mandoc_malloc(sz + 1);
288: *bp->text = '\0';
289: strlcat(bp->text, start, sz + 1);
290:
291: nextc = 0;
292: goto again;
1.1 kristaps 293: }
294:
295: void
296: eqn_free(struct eqn_node *p)
297: {
1.6 kristaps 298: int i;
1.1 kristaps 299:
1.13 kristaps 300: eqn_box_free(p->eqn.root);
1.6 kristaps 301:
302: for (i = 0; i < (int)p->defsz; i++) {
303: free(p->defs[i].key);
304: free(p->defs[i].val);
305: }
306:
1.12 kristaps 307: free(p->data);
1.6 kristaps 308: free(p->defs);
1.1 kristaps 309: free(p);
1.6 kristaps 310: }
311:
1.13 kristaps 312: static void
313: eqn_box_free(struct eqn_box *bp)
314: {
315:
316: if (bp->child)
317: eqn_box_free(bp->child);
318: if (bp->next)
319: eqn_box_free(bp->next);
320:
321: free(bp->text);
322: free(bp);
323: }
324:
1.6 kristaps 325: static const char *
1.14 kristaps 326: eqn_nextrawtok(struct eqn_node *ep, size_t *sz)
327: {
328:
329: return(eqn_next(ep, '"', sz, 0));
330: }
331:
332: static const char *
1.12 kristaps 333: eqn_nexttok(struct eqn_node *ep, size_t *sz)
334: {
335:
1.14 kristaps 336: return(eqn_next(ep, '"', sz, 1));
1.12 kristaps 337: }
338:
339: static const char *
1.14 kristaps 340: eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
1.6 kristaps 341: {
1.12 kristaps 342: char *start, *next;
343: int q, diff, lim;
344: size_t sv, ssz;
345: struct eqn_def *def;
346:
347: if (NULL == sz)
348: sz = &ssz;
1.6 kristaps 349:
1.13 kristaps 350: lim = 0;
351: sv = ep->cur;
352: again:
353: /* Prevent self-definitions. */
354:
355: if (lim >= EQN_NEST_MAX) {
356: EQN_MSG(MANDOCERR_EQNNEST, ep);
357: return(NULL);
358: }
359:
360: ep->cur = sv;
1.12 kristaps 361: start = &ep->data[(int)ep->cur];
1.6 kristaps 362: q = 0;
363:
364: if ('\0' == *start)
365: return(NULL);
366:
1.12 kristaps 367: if (quote == *start) {
368: ep->cur++;
1.6 kristaps 369: q = 1;
370: }
371:
1.12 kristaps 372: start = &ep->data[(int)ep->cur];
373: next = q ? strchr(start, quote) : strchr(start, ' ');
374:
375: if (NULL != next) {
376: *sz = (size_t)(next - start);
377: ep->cur += *sz;
1.6 kristaps 378: if (q)
1.12 kristaps 379: ep->cur++;
380: while (' ' == ep->data[(int)ep->cur])
381: ep->cur++;
1.6 kristaps 382: } else {
383: if (q)
1.12 kristaps 384: EQN_MSG(MANDOCERR_BADQUOTE, ep);
385: next = strchr(start, '\0');
386: *sz = (size_t)(next - start);
387: ep->cur += *sz;
388: }
389:
1.13 kristaps 390: /* Quotes aren't expanded for values. */
391:
1.14 kristaps 392: if (q || ! repl)
1.13 kristaps 393: return(start);
394:
1.12 kristaps 395: if (NULL != (def = eqn_def_find(ep, start, *sz))) {
396: diff = def->valsz - *sz;
397:
398: if (def->valsz > *sz) {
399: ep->sz += diff;
400: ep->data = mandoc_realloc(ep->data, ep->sz + 1);
401: ep->data[ep->sz] = '\0';
402: start = &ep->data[(int)sv];
403: }
404:
405: diff = def->valsz - *sz;
406: memmove(start + *sz + diff, start + *sz,
407: (strlen(start) - *sz) + 1);
408: memcpy(start, def->val, def->valsz);
409: goto again;
1.6 kristaps 410: }
411:
412: return(start);
1.8 kristaps 413: }
414:
415: static int
1.14 kristaps 416: eqn_do_set(struct eqn_node *ep)
1.8 kristaps 417: {
418: const char *start;
419:
1.14 kristaps 420: if (NULL == (start = eqn_nextrawtok(ep, NULL)))
1.12 kristaps 421: EQN_MSG(MANDOCERR_EQNARGS, ep);
1.14 kristaps 422: else if (NULL == (start = eqn_nextrawtok(ep, NULL)))
1.12 kristaps 423: EQN_MSG(MANDOCERR_EQNARGS, ep);
424: else
425: return(1);
1.8 kristaps 426:
1.12 kristaps 427: return(0);
1.8 kristaps 428: }
429:
430: static int
1.12 kristaps 431: eqn_do_define(struct eqn_node *ep)
1.8 kristaps 432: {
433: const char *start;
434: size_t sz;
1.12 kristaps 435: struct eqn_def *def;
1.8 kristaps 436: int i;
437:
1.14 kristaps 438: if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
1.12 kristaps 439: EQN_MSG(MANDOCERR_EQNARGS, ep);
1.8 kristaps 440: return(0);
441: }
442:
443: /*
444: * Search for a key that already exists.
1.12 kristaps 445: * Create a new key if none is found.
1.8 kristaps 446: */
447:
1.12 kristaps 448: if (NULL == (def = eqn_def_find(ep, start, sz))) {
1.8 kristaps 449: /* Find holes in string array. */
450: for (i = 0; i < (int)ep->defsz; i++)
451: if (0 == ep->defs[i].keysz)
452: break;
453:
454: if (i == (int)ep->defsz) {
455: ep->defsz++;
456: ep->defs = mandoc_realloc
457: (ep->defs, ep->defsz *
458: sizeof(struct eqn_def));
1.9 kristaps 459: ep->defs[i].key = ep->defs[i].val = NULL;
1.8 kristaps 460: }
461:
462: ep->defs[i].keysz = sz;
463: ep->defs[i].key = mandoc_realloc
464: (ep->defs[i].key, sz + 1);
465:
466: memcpy(ep->defs[i].key, start, sz);
467: ep->defs[i].key[(int)sz] = '\0';
1.12 kristaps 468: def = &ep->defs[i];
1.8 kristaps 469: }
470:
1.14 kristaps 471: start = eqn_next(ep, ep->data[(int)ep->cur], &sz, 0);
1.8 kristaps 472:
1.12 kristaps 473: if (NULL == start) {
474: EQN_MSG(MANDOCERR_EQNARGS, ep);
1.8 kristaps 475: return(0);
476: }
477:
1.12 kristaps 478: def->valsz = sz;
1.13 kristaps 479: def->val = mandoc_realloc(def->val, sz + 1);
1.12 kristaps 480: memcpy(def->val, start, sz);
481: def->val[(int)sz] = '\0';
482: return(1);
1.8 kristaps 483: }
484:
485: static int
1.12 kristaps 486: eqn_do_undef(struct eqn_node *ep)
1.8 kristaps 487: {
488: const char *start;
1.12 kristaps 489: struct eqn_def *def;
1.8 kristaps 490: size_t sz;
491:
1.14 kristaps 492: if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
1.12 kristaps 493: EQN_MSG(MANDOCERR_EQNARGS, ep);
494: return(0);
495: } else if (NULL != (def = eqn_def_find(ep, start, sz)))
496: def->keysz = 0;
1.8 kristaps 497:
1.12 kristaps 498: return(1);
499: }
500:
501: static struct eqn_def *
502: eqn_def_find(struct eqn_node *ep, const char *key, size_t sz)
503: {
504: int i;
1.8 kristaps 505:
1.12 kristaps 506: for (i = 0; i < (int)ep->defsz; i++)
507: if (ep->defs[i].keysz && ep->defs[i].keysz == sz &&
508: 0 == strncmp(ep->defs[i].key, key, sz))
509: return(&ep->defs[i]);
1.8 kristaps 510:
1.12 kristaps 511: return(NULL);
1.1 kristaps 512: }
CVSweb