Annotation of mandoc/eqn.c, Revision 1.11
1.11 ! kristaps 1: /* $Id: eqn.c,v 1.10 2011/07/17 14:15:11 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 */
! 32:
1.8 kristaps 33: #define EQN_ARGS struct eqn_node *ep, \
34: int ln, \
35: int pos, \
36: const char **end
37:
38: struct eqnpart {
39: const char *name;
40: size_t sz;
41: int (*fp)(EQN_ARGS);
42: };
43:
44: enum eqnpartt {
45: EQN_DEFINE = 0,
46: EQN_SET,
47: EQN_UNDEF,
48: EQN__MAX
49: };
50:
1.11 ! kristaps 51: static void eqn_append(struct eqn_node *,
! 52: struct mparse *, int,
! 53: int, const char *, int);
1.8 kristaps 54: static int eqn_do_define(EQN_ARGS);
1.11 ! kristaps 55: static int eqn_do_ign2(EQN_ARGS);
1.8 kristaps 56: static int eqn_do_undef(EQN_ARGS);
57: static const char *eqn_nexttok(struct mparse *, int, int,
1.6 kristaps 58: const char **, size_t *);
59:
1.8 kristaps 60: static const struct eqnpart eqnparts[EQN__MAX] = {
61: { "define", 6, eqn_do_define }, /* EQN_DEFINE */
1.11 ! kristaps 62: { "set", 3, eqn_do_ign2 }, /* 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;
73: struct mparse *mp;
74: const char *start, *end;
75: int i, c;
1.1 kristaps 76:
77: if (0 == strcmp(p, ".EN")) {
78: *epp = NULL;
79: return(ROFF_EQN);
80: }
81:
82: ep = *epp;
1.8 kristaps 83: mp = ep->parse;
1.6 kristaps 84: end = p + pos;
85:
1.8 kristaps 86: if (NULL == (start = eqn_nexttok(mp, ln, pos, &end, &sz)))
1.6 kristaps 87: return(ROFF_IGN);
88:
1.8 kristaps 89: for (i = 0; i < (int)EQN__MAX; i++) {
90: if (eqnparts[i].sz != sz)
91: continue;
92: if (strncmp(eqnparts[i].name, start, sz))
93: continue;
94:
95: if ((c = (*eqnparts[i].fp)(ep, ln, pos, &end)) < 0)
96: return(ROFF_ERR);
97: else if (0 == c || '\0' == *end)
98: return(ROFF_IGN);
99:
100: /*
101: * Re-calculate offset and rerun, if trailing text.
102: * This allows multiple definitions (say) on each line.
103: */
104:
105: *offs = end - (p + pos);
106: return(ROFF_RERUN);
107: }
1.7 kristaps 108:
1.11 ! kristaps 109: eqn_append(ep, mp, ln, pos, p + pos, 0);
! 110: return(ROFF_IGN);
! 111: }
! 112:
! 113: static void
! 114: eqn_append(struct eqn_node *ep, struct mparse *mp,
! 115: int ln, int pos, const char *end, int re)
! 116: {
! 117: const char *start;
! 118: size_t sz;
! 119: int i;
! 120:
! 121: if (re >= EQN_NEST_MAX) {
! 122: mandoc_msg(MANDOCERR_BADQUOTE, mp, ln, pos, NULL);
! 123: return;
! 124: }
! 125:
1.8 kristaps 126: while (NULL != (start = eqn_nexttok(mp, ln, pos, &end, &sz))) {
127: if (0 == sz)
128: continue;
129: for (i = 0; i < (int)ep->defsz; i++) {
130: if (0 == ep->defs[i].keysz)
131: continue;
1.6 kristaps 132: if (ep->defs[i].keysz != sz)
133: continue;
1.8 kristaps 134: if (strncmp(ep->defs[i].key, start, sz))
135: continue;
136: start = ep->defs[i].val;
137: sz = ep->defs[i].valsz;
1.11 ! kristaps 138:
! 139: eqn_append(ep, mp, ln, pos, start, re + 1);
1.8 kristaps 140: break;
1.6 kristaps 141: }
1.11 ! kristaps 142: if (i < (int)ep->defsz)
! 143: continue;
1.6 kristaps 144:
1.8 kristaps 145: ep->eqn.data = mandoc_realloc
146: (ep->eqn.data, ep->eqn.sz + sz + 1);
1.6 kristaps 147:
1.8 kristaps 148: if (0 == ep->eqn.sz)
149: *ep->eqn.data = '\0';
1.6 kristaps 150:
1.8 kristaps 151: ep->eqn.sz += sz;
152: strlcat(ep->eqn.data, start, ep->eqn.sz + 1);
153: }
1.1 kristaps 154: }
155:
156: struct eqn_node *
1.5 kristaps 157: eqn_alloc(int pos, int line, struct mparse *parse)
1.1 kristaps 158: {
159: struct eqn_node *p;
160:
161: p = mandoc_calloc(1, sizeof(struct eqn_node));
1.5 kristaps 162: p->parse = parse;
1.2 kristaps 163: p->eqn.line = line;
164: p->eqn.pos = pos;
1.1 kristaps 165:
166: return(p);
167: }
168:
1.3 kristaps 169: /* ARGSUSED */
1.1 kristaps 170: void
171: eqn_end(struct eqn_node *e)
172: {
173:
174: /* Nothing to do. */
175: }
176:
177: void
178: eqn_free(struct eqn_node *p)
179: {
1.6 kristaps 180: int i;
1.1 kristaps 181:
182: free(p->eqn.data);
1.6 kristaps 183:
184: for (i = 0; i < (int)p->defsz; i++) {
185: free(p->defs[i].key);
186: free(p->defs[i].val);
187: }
188:
189: free(p->defs);
1.1 kristaps 190: free(p);
1.6 kristaps 191: }
192:
1.7 kristaps 193: /*
194: * Return the current equation token setting "next" on the next one,
195: * setting the token size in "sz".
196: * This does the Right Thing for quoted strings, too.
197: * Returns NULL if no more tokens exist.
198: */
1.6 kristaps 199: static const char *
200: eqn_nexttok(struct mparse *mp, int ln, int pos,
201: const char **next, size_t *sz)
202: {
203: const char *start;
204: int q;
205:
206: start = *next;
207: q = 0;
208:
209: if ('\0' == *start)
210: return(NULL);
211:
212: if ('"' == *start) {
213: start++;
214: q = 1;
215: }
216:
217: *next = q ? strchr(start, '"') : strchr(start, ' ');
218:
219: if (NULL != *next) {
220: *sz = (size_t)(*next - start);
221: if (q)
222: (*next)++;
223: while (' ' == **next)
224: (*next)++;
225: } else {
1.7 kristaps 226: /*
227: * XXX: groff gets confused by this and doesn't always
228: * do the "right thing" (just terminate it and warn
229: * about it).
230: */
1.6 kristaps 231: if (q)
232: mandoc_msg(MANDOCERR_BADQUOTE,
233: mp, ln, pos, NULL);
234: *next = strchr(start, '\0');
235: *sz = (size_t)(*next - start);
236: }
237:
238: return(start);
1.8 kristaps 239: }
240:
241: static int
1.11 ! kristaps 242: eqn_do_ign2(struct eqn_node *ep, int ln, int pos, const char **end)
1.8 kristaps 243: {
244: const char *start;
245: struct mparse *mp;
246: size_t sz;
247:
248: mp = ep->parse;
249:
250: start = eqn_nexttok(ep->parse, ln, pos, end, &sz);
251: if (NULL == start || 0 == sz) {
252: mandoc_msg(MANDOCERR_EQNARGS, mp, ln, pos, NULL);
253: return(0);
254: }
255:
256: start = eqn_nexttok(ep->parse, ln, pos, end, &sz);
257: if (NULL == start || 0 == sz) {
258: mandoc_msg(MANDOCERR_EQNARGS, mp, ln, pos, NULL);
259: return(0);
260: }
261:
262: return(1);
263: }
264:
265: static int
266: eqn_do_define(struct eqn_node *ep, int ln, int pos, const char **end)
267: {
268: const char *start;
269: struct mparse *mp;
270: size_t sz;
271: int i;
272:
273: mp = ep->parse;
274:
275: start = eqn_nexttok(mp, ln, pos, end, &sz);
276: if (NULL == start || 0 == sz) {
277: mandoc_msg(MANDOCERR_EQNARGS, mp, ln, pos, NULL);
278: return(0);
279: }
280:
281: /* TODO: merge this code with roff_getstr(). */
282:
283: /*
284: * Search for a key that already exists.
285: * Note that the string array can have "holes" (null key).
286: */
287:
288: for (i = 0; i < (int)ep->defsz; i++) {
289: if (0 == ep->defs[i].keysz || ep->defs[i].keysz != sz)
290: continue;
291: if (0 == strncmp(ep->defs[i].key, start, sz))
292: break;
293: }
294:
295: /* Create a new key. */
296:
297: if (i == (int)ep->defsz) {
298: /* Find holes in string array. */
299: for (i = 0; i < (int)ep->defsz; i++)
300: if (0 == ep->defs[i].keysz)
301: break;
302:
303: if (i == (int)ep->defsz) {
304: ep->defsz++;
305: ep->defs = mandoc_realloc
306: (ep->defs, ep->defsz *
307: sizeof(struct eqn_def));
1.9 kristaps 308: ep->defs[i].key = ep->defs[i].val = NULL;
1.8 kristaps 309: }
310:
311: ep->defs[i].keysz = sz;
312: ep->defs[i].key = mandoc_realloc
313: (ep->defs[i].key, sz + 1);
314:
315: memcpy(ep->defs[i].key, start, sz);
316: ep->defs[i].key[(int)sz] = '\0';
317: }
318:
319: start = eqn_nexttok(mp, ln, pos, end, &sz);
320:
321: if (NULL == start || 0 == sz) {
322: ep->defs[i].keysz = 0;
323: mandoc_msg(MANDOCERR_EQNARGS, mp, ln, pos, NULL);
324: return(0);
325: }
326:
327: ep->defs[i].valsz = sz;
328: ep->defs[i].val = mandoc_realloc
329: (ep->defs[i].val, sz + 1);
330: memcpy(ep->defs[i].val, start, sz);
331: ep->defs[i].val[(int)sz] = '\0';
332:
333: return(sz ? 1 : 0);
334: }
335:
336: static int
337: eqn_do_undef(struct eqn_node *ep, int ln, int pos, const char **end)
338: {
339: const char *start;
340: struct mparse *mp;
341: size_t sz;
342: int i;
343:
344: mp = ep->parse;
345:
346: start = eqn_nexttok(mp, ln, pos, end, &sz);
347: if (NULL == start || 0 == sz) {
348: mandoc_msg(MANDOCERR_EQNARGS, mp, ln, pos, NULL);
349: return(0);
350: }
351:
352: for (i = 0; i < (int)ep->defsz; i++) {
353: if (0 == ep->defs[i].keysz || ep->defs[i].keysz != sz)
354: continue;
355: if (strncmp(ep->defs[i].key, start, sz))
356: continue;
357: ep->defs[i].keysz = 0;
358: break;
359: }
360:
361: return(1);
1.1 kristaps 362: }
CVSweb