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