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