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