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