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