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