Annotation of mandoc/roff.c, Revision 1.97
1.97 ! kristaps 1: /* $Id: roff.c,v 1.96 2010/07/27 13:16:00 kristaps Exp $ */
1.1 kristaps 2: /*
1.67 kristaps 3: * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
1.93 schwarze 4: * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org>
1.1 kristaps 5: *
6: * Permission to use, copy, modify, and distribute this software for any
1.66 kristaps 7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 9: *
1.66 kristaps 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 kristaps 17: */
1.66 kristaps 18: #ifdef HAVE_CONFIG_H
19: #include "config.h"
20: #endif
1.30 kristaps 21:
1.67 kristaps 22: #include <assert.h>
1.89 kristaps 23: #include <errno.h>
1.85 kristaps 24: #include <ctype.h>
1.89 kristaps 25: #include <limits.h>
1.1 kristaps 26: #include <stdlib.h>
1.67 kristaps 27: #include <string.h>
1.75 kristaps 28: #include <stdio.h>
1.1 kristaps 29:
1.67 kristaps 30: #include "mandoc.h"
1.43 kristaps 31: #include "roff.h"
1.94 kristaps 32: #include "libmandoc.h"
1.33 kristaps 33:
1.82 kristaps 34: #define RSTACK_MAX 128
35:
1.75 kristaps 36: #define ROFF_CTL(c) \
37: ('.' == (c) || '\'' == (c))
38:
1.88 kristaps 39: #if 1
40: #define ROFF_DEBUG(fmt, args...) \
41: do { /* Nothing. */ } while (/*CONSTCOND*/ 0)
42: #else
43: #define ROFF_DEBUG(fmt, args...) \
44: do { fprintf(stderr, fmt , ##args); } while (/*CONSTCOND*/ 0)
45: #endif
46:
1.67 kristaps 47: enum rofft {
1.80 kristaps 48: ROFF_am,
49: ROFF_ami,
50: ROFF_am1,
51: ROFF_de,
52: ROFF_dei,
53: ROFF_de1,
1.83 schwarze 54: ROFF_ds,
1.82 kristaps 55: ROFF_el,
56: ROFF_ie,
1.75 kristaps 57: ROFF_if,
1.76 kristaps 58: ROFF_ig,
1.83 schwarze 59: ROFF_rm,
60: ROFF_tr,
1.76 kristaps 61: ROFF_cblock,
1.75 kristaps 62: ROFF_ccond,
1.89 kristaps 63: ROFF_nr,
1.67 kristaps 64: ROFF_MAX
65: };
66:
1.82 kristaps 67: enum roffrule {
68: ROFFRULE_ALLOW,
69: ROFFRULE_DENY
70: };
71:
1.94 kristaps 72:
73: struct roffstr {
74: char *name; /* key of symbol */
75: char *string; /* current value */
76: struct roffstr *next; /* next in list */
77: };
78:
1.67 kristaps 79: struct roff {
80: struct roffnode *last; /* leaf of stack */
81: mandocmsg msg; /* err/warn/fatal messages */
82: void *data; /* privdata for messages */
1.82 kristaps 83: enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */
84: int rstackpos; /* position in rstack */
1.90 kristaps 85: struct regset *regs; /* read/writable registers */
1.94 kristaps 86: struct roffstr *first_string;
1.79 kristaps 87: };
88:
1.67 kristaps 89: struct roffnode {
90: enum rofft tok; /* type of node */
91: struct roffnode *parent; /* up one in stack */
92: int line; /* parse line */
93: int col; /* parse col */
1.79 kristaps 94: char *end; /* end-rules: custom token */
95: int endspan; /* end-rules: next-line or infty */
1.82 kristaps 96: enum roffrule rule; /* current evaluation rule */
1.67 kristaps 97: };
98:
99: #define ROFF_ARGS struct roff *r, /* parse ctx */ \
1.72 kristaps 100: enum rofft tok, /* tok of macro */ \
1.67 kristaps 101: char **bufp, /* input buffer */ \
102: size_t *szp, /* size of input buffer */ \
103: int ln, /* parse line */ \
1.75 kristaps 104: int ppos, /* original pos in buffer */ \
105: int pos, /* current pos in buffer */ \
1.74 kristaps 106: int *offs /* reset offset of buffer data */
1.67 kristaps 107:
108: typedef enum rofferr (*roffproc)(ROFF_ARGS);
109:
110: struct roffmac {
111: const char *name; /* macro name */
1.79 kristaps 112: roffproc proc; /* process new macro */
113: roffproc text; /* process as child text of macro */
114: roffproc sub; /* process as child of macro */
115: int flags;
116: #define ROFFMAC_STRUCT (1 << 0) /* always interpret */
1.85 kristaps 117: struct roffmac *next;
1.67 kristaps 118: };
119:
1.80 kristaps 120: static enum rofferr roff_block(ROFF_ARGS);
121: static enum rofferr roff_block_text(ROFF_ARGS);
122: static enum rofferr roff_block_sub(ROFF_ARGS);
123: static enum rofferr roff_cblock(ROFF_ARGS);
124: static enum rofferr roff_ccond(ROFF_ARGS);
1.82 kristaps 125: static enum rofferr roff_cond(ROFF_ARGS);
126: static enum rofferr roff_cond_text(ROFF_ARGS);
127: static enum rofferr roff_cond_sub(ROFF_ARGS);
1.92 schwarze 128: static enum rofferr roff_ds(ROFF_ARGS);
1.94 kristaps 129: static enum roffrule roff_evalcond(const char *, int *);
130: static void roff_freestr(struct roff *);
131: static const char *roff_getstrn(const struct roff *,
132: const char *, size_t);
1.89 kristaps 133: static enum rofferr roff_line(ROFF_ARGS);
134: static enum rofferr roff_nr(ROFF_ARGS);
1.95 kristaps 135: static int roff_res(struct roff *,
136: char **, size_t *, int);
1.94 kristaps 137: static void roff_setstr(struct roff *,
138: const char *, const char *);
1.67 kristaps 139:
1.85 kristaps 140: /* See roff_hash_find() */
141:
142: #define ASCII_HI 126
143: #define ASCII_LO 33
144: #define HASHWIDTH (ASCII_HI - ASCII_LO + 1)
145:
146: static struct roffmac *hash[HASHWIDTH];
147:
148: static struct roffmac roffs[ROFF_MAX] = {
149: { "am", roff_block, roff_block_text, roff_block_sub, 0, NULL },
150: { "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },
151: { "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
152: { "de", roff_block, roff_block_text, roff_block_sub, 0, NULL },
153: { "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },
154: { "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
1.92 schwarze 155: { "ds", roff_ds, NULL, NULL, 0, NULL },
1.85 kristaps 156: { "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
157: { "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
158: { "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
159: { "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL },
160: { "rm", roff_line, NULL, NULL, 0, NULL },
161: { "tr", roff_line, NULL, NULL, 0, NULL },
162: { ".", roff_cblock, NULL, NULL, 0, NULL },
163: { "\\}", roff_ccond, NULL, NULL, 0, NULL },
1.89 kristaps 164: { "nr", roff_nr, NULL, NULL, 0, NULL },
1.67 kristaps 165: };
166:
167: static void roff_free1(struct roff *);
168: static enum rofft roff_hash_find(const char *);
1.85 kristaps 169: static void roff_hash_init(void);
1.76 kristaps 170: static void roffnode_cleanscope(struct roff *);
1.67 kristaps 171: static int roffnode_push(struct roff *,
172: enum rofft, int, int);
173: static void roffnode_pop(struct roff *);
174: static enum rofft roff_parse(const char *, int *);
1.91 kristaps 175: static int roff_parse_nat(const char *, unsigned int *);
1.67 kristaps 176:
1.85 kristaps 177: /* See roff_hash_find() */
178: #define ROFF_HASH(p) (p[0] - ASCII_LO)
179:
180: static void
181: roff_hash_init(void)
182: {
183: struct roffmac *n;
184: int buc, i;
185:
186: for (i = 0; i < (int)ROFF_MAX; i++) {
187: assert(roffs[i].name[0] >= ASCII_LO);
188: assert(roffs[i].name[0] <= ASCII_HI);
189:
190: buc = ROFF_HASH(roffs[i].name);
191:
192: if (NULL != (n = hash[buc])) {
193: for ( ; n->next; n = n->next)
194: /* Do nothing. */ ;
195: n->next = &roffs[i];
196: } else
197: hash[buc] = &roffs[i];
198: }
199: }
200:
1.67 kristaps 201:
202: /*
203: * Look up a roff token by its name. Returns ROFF_MAX if no macro by
204: * the nil-terminated string name could be found.
205: */
206: static enum rofft
207: roff_hash_find(const char *p)
208: {
1.85 kristaps 209: int buc;
210: struct roffmac *n;
1.67 kristaps 211:
1.85 kristaps 212: /*
213: * libroff has an extremely simple hashtable, for the time
214: * being, which simply keys on the first character, which must
215: * be printable, then walks a chain. It works well enough until
216: * optimised.
217: */
218:
219: if (p[0] < ASCII_LO || p[0] > ASCII_HI)
220: return(ROFF_MAX);
221:
222: buc = ROFF_HASH(p);
223:
224: if (NULL == (n = hash[buc]))
225: return(ROFF_MAX);
226: for ( ; n; n = n->next)
227: if (0 == strcmp(n->name, p))
228: return((enum rofft)(n - roffs));
1.67 kristaps 229:
230: return(ROFF_MAX);
231: }
232:
233:
234: /*
235: * Pop the current node off of the stack of roff instructions currently
236: * pending.
237: */
238: static void
239: roffnode_pop(struct roff *r)
240: {
241: struct roffnode *p;
242:
1.75 kristaps 243: assert(r->last);
244: p = r->last;
1.82 kristaps 245:
246: if (ROFF_el == p->tok)
247: if (r->rstackpos > -1)
248: r->rstackpos--;
249:
1.75 kristaps 250: r->last = r->last->parent;
1.74 kristaps 251: if (p->end)
252: free(p->end);
1.67 kristaps 253: free(p);
254: }
255:
256:
257: /*
258: * Push a roff node onto the instruction stack. This must later be
259: * removed with roffnode_pop().
260: */
261: static int
262: roffnode_push(struct roff *r, enum rofft tok, int line, int col)
263: {
264: struct roffnode *p;
265:
266: if (NULL == (p = calloc(1, sizeof(struct roffnode)))) {
267: (*r->msg)(MANDOCERR_MEM, r->data, line, col, NULL);
268: return(0);
269: }
270:
271: p->tok = tok;
272: p->parent = r->last;
273: p->line = line;
274: p->col = col;
1.79 kristaps 275: p->rule = p->parent ? p->parent->rule : ROFFRULE_DENY;
1.67 kristaps 276:
277: r->last = p;
278: return(1);
279: }
280:
281:
282: static void
283: roff_free1(struct roff *r)
284: {
285:
286: while (r->last)
287: roffnode_pop(r);
1.94 kristaps 288: roff_freestr(r);
1.67 kristaps 289: }
290:
291:
292: void
293: roff_reset(struct roff *r)
294: {
295:
296: roff_free1(r);
297: }
298:
299:
300: void
301: roff_free(struct roff *r)
302: {
303:
304: roff_free1(r);
305: free(r);
306: }
307:
308:
309: struct roff *
1.90 kristaps 310: roff_alloc(struct regset *regs, const mandocmsg msg, void *data)
1.67 kristaps 311: {
312: struct roff *r;
313:
314: if (NULL == (r = calloc(1, sizeof(struct roff)))) {
315: (*msg)(MANDOCERR_MEM, data, 0, 0, NULL);
316: return(0);
317: }
318:
1.90 kristaps 319: r->regs = regs;
1.67 kristaps 320: r->msg = msg;
321: r->data = data;
1.82 kristaps 322: r->rstackpos = -1;
1.85 kristaps 323:
324: roff_hash_init();
1.67 kristaps 325: return(r);
326: }
327:
328:
1.94 kristaps 329: /*
330: * Pre-filter each and every line for reserved words (one beginning with
331: * `\*', e.g., `\*(ab'). These must be handled before the actual line
332: * is processed.
333: */
334: static int
1.95 kristaps 335: roff_res(struct roff *r, char **bufp, size_t *szp, int pos)
1.94 kristaps 336: {
337: const char *cp, *cpp, *st, *res;
338: int i, maxl;
339: size_t nsz;
340: char *n;
341:
1.95 kristaps 342: /* LINTED */
1.94 kristaps 343: for (cp = &(*bufp)[pos]; (cpp = strstr(cp, "\\*")); cp++) {
344: cp = cpp + 2;
345: switch (*cp) {
346: case ('('):
347: cp++;
348: maxl = 2;
349: break;
350: case ('['):
351: cp++;
352: maxl = 0;
353: break;
354: default:
355: maxl = 1;
356: break;
357: }
358:
359: st = cp;
360:
361: for (i = 0; 0 == maxl || i < maxl; i++, cp++) {
362: if ('\0' == *cp)
363: return(1); /* Error. */
364: if (0 == maxl && ']' == *cp)
365: break;
366: }
367:
368: res = roff_getstrn(r, st, (size_t)i);
369:
370: if (NULL == res) {
371: cp -= maxl ? 1 : 0;
372: continue;
373: }
374:
375: ROFF_DEBUG("roff: splicing reserved: [%.*s]\n", i, st);
376:
377: nsz = *szp + strlen(res) + 1;
378: n = mandoc_malloc(nsz);
379:
380: *n = '\0';
381:
382: strlcat(n, *bufp, (size_t)(cpp - *bufp + 1));
383: strlcat(n, res, nsz);
384: strlcat(n, cp + (maxl ? 0 : 1), nsz);
385:
386: free(*bufp);
387:
388: *bufp = n;
389: *szp = nsz;
390: return(0);
391: }
392:
393: return(1);
394: }
395:
396:
1.67 kristaps 397: enum rofferr
1.90 kristaps 398: roff_parseln(struct roff *r, int ln, char **bufp,
399: size_t *szp, int pos, int *offs)
1.67 kristaps 400: {
401: enum rofft t;
1.79 kristaps 402: int ppos;
403:
404: /*
1.94 kristaps 405: * Run the reserved-word filter only if we have some reserved
406: * words to fill in.
407: */
408:
1.95 kristaps 409: if (r->first_string && ! roff_res(r, bufp, szp, pos))
1.94 kristaps 410: return(ROFF_RERUN);
411:
412: /*
1.79 kristaps 413: * First, if a scope is open and we're not a macro, pass the
414: * text through the macro's filter. If a scope isn't open and
415: * we're not a macro, just let it through.
416: */
1.74 kristaps 417:
1.75 kristaps 418: if (r->last && ! ROFF_CTL((*bufp)[pos])) {
1.78 kristaps 419: t = r->last->tok;
420: assert(roffs[t].text);
1.88 kristaps 421: ROFF_DEBUG("roff: intercept scoped text: %s, [%s]\n",
422: roffs[t].name, &(*bufp)[pos]);
1.78 kristaps 423: return((*roffs[t].text)
1.90 kristaps 424: (r, t, bufp, szp,
425: ln, pos, pos, offs));
1.94 kristaps 426: } else if ( ! ROFF_CTL((*bufp)[pos]))
1.67 kristaps 427: return(ROFF_CONT);
428:
1.79 kristaps 429: /*
430: * If a scope is open, go to the child handler for that macro,
431: * as it may want to preprocess before doing anything with it.
432: */
1.78 kristaps 433:
1.79 kristaps 434: if (r->last) {
435: t = r->last->tok;
436: assert(roffs[t].sub);
1.88 kristaps 437: ROFF_DEBUG("roff: intercept scoped context: %s\n",
438: roffs[t].name);
1.79 kristaps 439: return((*roffs[t].sub)
1.90 kristaps 440: (r, t, bufp, szp,
441: ln, pos, pos, offs));
1.79 kristaps 442: }
1.78 kristaps 443:
1.79 kristaps 444: /*
445: * Lastly, as we've no scope open, try to look up and execute
446: * the new macro. If no macro is found, simply return and let
447: * the compilers handle it.
448: */
1.67 kristaps 449:
1.75 kristaps 450: ppos = pos;
1.94 kristaps 451: if (ROFF_MAX == (t = roff_parse(*bufp, &pos)))
1.79 kristaps 452: return(ROFF_CONT);
1.67 kristaps 453:
1.88 kristaps 454: ROFF_DEBUG("roff: intercept new-scope: %s, [%s]\n",
455: roffs[t].name, &(*bufp)[pos]);
1.75 kristaps 456: assert(roffs[t].proc);
1.78 kristaps 457: return((*roffs[t].proc)
1.90 kristaps 458: (r, t, bufp, szp,
459: ln, ppos, pos, offs));
1.74 kristaps 460: }
461:
462:
463: int
464: roff_endparse(struct roff *r)
465: {
466:
467: if (NULL == r->last)
468: return(1);
469: return((*r->msg)(MANDOCERR_SCOPEEXIT, r->data, r->last->line,
470: r->last->col, NULL));
1.67 kristaps 471: }
472:
473:
474: /*
475: * Parse a roff node's type from the input buffer. This must be in the
476: * form of ".foo xxx" in the usual way.
477: */
478: static enum rofft
479: roff_parse(const char *buf, int *pos)
480: {
481: int j;
482: char mac[5];
483: enum rofft t;
484:
1.75 kristaps 485: assert(ROFF_CTL(buf[*pos]));
486: (*pos)++;
1.67 kristaps 487:
488: while (buf[*pos] && (' ' == buf[*pos] || '\t' == buf[*pos]))
489: (*pos)++;
490:
491: if ('\0' == buf[*pos])
492: return(ROFF_MAX);
493:
494: for (j = 0; j < 4; j++, (*pos)++)
495: if ('\0' == (mac[j] = buf[*pos]))
496: break;
1.82 kristaps 497: else if (' ' == buf[*pos] || (j && '\\' == buf[*pos]))
1.67 kristaps 498: break;
499:
500: if (j == 4 || j < 1)
501: return(ROFF_MAX);
502:
503: mac[j] = '\0';
504:
505: if (ROFF_MAX == (t = roff_hash_find(mac)))
506: return(t);
507:
508: while (buf[*pos] && ' ' == buf[*pos])
509: (*pos)++;
510:
511: return(t);
512: }
513:
514:
1.89 kristaps 515: static int
1.91 kristaps 516: roff_parse_nat(const char *buf, unsigned int *res)
1.89 kristaps 517: {
518: char *ep;
519: long lval;
520:
521: errno = 0;
522: lval = strtol(buf, &ep, 10);
523: if (buf[0] == '\0' || *ep != '\0')
524: return(0);
525: if ((errno == ERANGE &&
526: (lval == LONG_MAX || lval == LONG_MIN)) ||
1.91 kristaps 527: (lval > INT_MAX || lval < 0))
1.89 kristaps 528: return(0);
529:
1.91 kristaps 530: *res = (unsigned int)lval;
1.89 kristaps 531: return(1);
532: }
533:
534:
1.67 kristaps 535: /* ARGSUSED */
536: static enum rofferr
1.76 kristaps 537: roff_cblock(ROFF_ARGS)
1.67 kristaps 538: {
539:
1.79 kristaps 540: /*
541: * A block-close `..' should only be invoked as a child of an
542: * ignore macro, otherwise raise a warning and just ignore it.
543: */
544:
1.76 kristaps 545: if (NULL == r->last) {
546: if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL))
547: return(ROFF_ERR);
548: return(ROFF_IGN);
549: }
1.67 kristaps 550:
1.81 kristaps 551: switch (r->last->tok) {
552: case (ROFF_am):
553: /* FALLTHROUGH */
554: case (ROFF_ami):
555: /* FALLTHROUGH */
556: case (ROFF_am1):
557: /* FALLTHROUGH */
558: case (ROFF_de):
559: /* FALLTHROUGH */
560: case (ROFF_dei):
561: /* FALLTHROUGH */
562: case (ROFF_de1):
563: /* FALLTHROUGH */
564: case (ROFF_ig):
565: break;
566: default:
1.76 kristaps 567: if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL))
568: return(ROFF_ERR);
1.67 kristaps 569: return(ROFF_IGN);
1.76 kristaps 570: }
1.67 kristaps 571:
1.76 kristaps 572: if ((*bufp)[pos])
573: if ( ! (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL))
574: return(ROFF_ERR);
1.71 kristaps 575:
576: roffnode_pop(r);
1.76 kristaps 577: roffnode_cleanscope(r);
578: return(ROFF_IGN);
1.71 kristaps 579:
1.67 kristaps 580: }
581:
582:
1.76 kristaps 583: static void
584: roffnode_cleanscope(struct roff *r)
1.67 kristaps 585: {
586:
1.76 kristaps 587: while (r->last) {
588: if (--r->last->endspan < 0)
589: break;
590: roffnode_pop(r);
591: }
1.67 kristaps 592: }
593:
594:
1.75 kristaps 595: /* ARGSUSED */
1.74 kristaps 596: static enum rofferr
1.75 kristaps 597: roff_ccond(ROFF_ARGS)
1.74 kristaps 598: {
599:
1.76 kristaps 600: if (NULL == r->last) {
601: if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL))
602: return(ROFF_ERR);
603: return(ROFF_IGN);
604: }
605:
1.82 kristaps 606: switch (r->last->tok) {
607: case (ROFF_el):
608: /* FALLTHROUGH */
609: case (ROFF_ie):
610: /* FALLTHROUGH */
611: case (ROFF_if):
612: break;
613: default:
1.75 kristaps 614: if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL))
615: return(ROFF_ERR);
616: return(ROFF_IGN);
617: }
618:
1.76 kristaps 619: if (r->last->endspan > -1) {
620: if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL))
621: return(ROFF_ERR);
622: return(ROFF_IGN);
623: }
624:
625: if ((*bufp)[pos])
626: if ( ! (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL))
627: return(ROFF_ERR);
628:
1.75 kristaps 629: roffnode_pop(r);
1.76 kristaps 630: roffnode_cleanscope(r);
631: return(ROFF_IGN);
632: }
633:
1.75 kristaps 634:
1.76 kristaps 635: /* ARGSUSED */
636: static enum rofferr
1.80 kristaps 637: roff_block(ROFF_ARGS)
1.76 kristaps 638: {
1.78 kristaps 639: int sv;
640: size_t sz;
1.76 kristaps 641:
1.80 kristaps 642: if (ROFF_ig != tok && '\0' == (*bufp)[pos]) {
643: if ( ! (*r->msg)(MANDOCERR_NOARGS, r->data, ln, ppos, NULL))
644: return(ROFF_ERR);
645: return(ROFF_IGN);
646: } else if (ROFF_ig != tok) {
647: while ((*bufp)[pos] && ' ' != (*bufp)[pos])
648: pos++;
649: while (' ' == (*bufp)[pos])
650: pos++;
651: }
652:
1.76 kristaps 653: if ( ! roffnode_push(r, tok, ln, ppos))
654: return(ROFF_ERR);
655:
1.79 kristaps 656: if ('\0' == (*bufp)[pos])
1.78 kristaps 657: return(ROFF_IGN);
658:
659: sv = pos;
660: while ((*bufp)[pos] && ' ' != (*bufp)[pos] &&
661: '\t' != (*bufp)[pos])
662: pos++;
663:
664: /*
665: * Note: groff does NOT like escape characters in the input.
666: * Instead of detecting this, we're just going to let it fly and
667: * to hell with it.
668: */
669:
670: assert(pos > sv);
671: sz = (size_t)(pos - sv);
672:
1.79 kristaps 673: if (1 == sz && '.' == (*bufp)[sv])
674: return(ROFF_IGN);
675:
1.78 kristaps 676: r->last->end = malloc(sz + 1);
677:
678: if (NULL == r->last->end) {
679: (*r->msg)(MANDOCERR_MEM, r->data, ln, pos, NULL);
680: return(ROFF_ERR);
681: }
682:
683: memcpy(r->last->end, *bufp + sv, sz);
684: r->last->end[(int)sz] = '\0';
685:
1.77 kristaps 686: if ((*bufp)[pos])
687: if ( ! (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL))
688: return(ROFF_ERR);
1.74 kristaps 689:
1.78 kristaps 690: return(ROFF_IGN);
691: }
692:
693:
694: /* ARGSUSED */
695: static enum rofferr
1.80 kristaps 696: roff_block_sub(ROFF_ARGS)
1.79 kristaps 697: {
698: enum rofft t;
699: int i, j;
700:
701: /*
702: * First check whether a custom macro exists at this level. If
703: * it does, then check against it. This is some of groff's
704: * stranger behaviours. If we encountered a custom end-scope
705: * tag and that tag also happens to be a "real" macro, then we
706: * need to try interpreting it again as a real macro. If it's
707: * not, then return ignore. Else continue.
708: */
709:
710: if (r->last->end) {
711: i = pos + 1;
712: while (' ' == (*bufp)[i] || '\t' == (*bufp)[i])
713: i++;
714:
715: for (j = 0; r->last->end[j]; j++, i++)
716: if ((*bufp)[i] != r->last->end[j])
717: break;
718:
719: if ('\0' == r->last->end[j] &&
720: ('\0' == (*bufp)[i] ||
721: ' ' == (*bufp)[i] ||
722: '\t' == (*bufp)[i])) {
723: roffnode_pop(r);
724: roffnode_cleanscope(r);
725:
726: if (ROFF_MAX != roff_parse(*bufp, &pos))
727: return(ROFF_RERUN);
728: return(ROFF_IGN);
729: }
730: }
731:
732: /*
733: * If we have no custom end-query or lookup failed, then try
734: * pulling it out of the hashtable.
735: */
736:
737: ppos = pos;
738: t = roff_parse(*bufp, &pos);
739:
740: /* If we're not a comment-end, then throw it away. */
741: if (ROFF_cblock != t)
742: return(ROFF_IGN);
743:
744: assert(roffs[t].proc);
1.90 kristaps 745: return((*roffs[t].proc)(r, t, bufp, szp,
746: ln, ppos, pos, offs));
1.79 kristaps 747: }
748:
749:
750: /* ARGSUSED */
751: static enum rofferr
1.80 kristaps 752: roff_block_text(ROFF_ARGS)
1.78 kristaps 753: {
754:
755: return(ROFF_IGN);
756: }
757:
758:
759: /* ARGSUSED */
760: static enum rofferr
1.82 kristaps 761: roff_cond_sub(ROFF_ARGS)
762: {
763: enum rofft t;
764: enum roffrule rr;
1.87 kristaps 765: struct roffnode *l;
1.82 kristaps 766:
767: ppos = pos;
768: rr = r->last->rule;
769:
1.87 kristaps 770: /*
771: * Clean out scope. If we've closed ourselves, then don't
772: * continue.
773: */
774:
775: l = r->last;
776: roffnode_cleanscope(r);
777:
778: if (l != r->last)
779: return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
1.82 kristaps 780:
781: if (ROFF_MAX == (t = roff_parse(*bufp, &pos)))
782: return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
783:
784: /*
785: * A denied conditional must evaluate its children if and only
786: * if they're either structurally required (such as loops and
787: * conditionals) or a closing macro.
788: */
789: if (ROFFRULE_DENY == rr)
790: if ( ! (ROFFMAC_STRUCT & roffs[t].flags))
791: if (ROFF_ccond != t)
792: return(ROFF_IGN);
793:
794: assert(roffs[t].proc);
1.90 kristaps 795: return((*roffs[t].proc)(r, t, bufp, szp,
796: ln, ppos, pos, offs));
1.82 kristaps 797: }
798:
799:
800: /* ARGSUSED */
801: static enum rofferr
802: roff_cond_text(ROFF_ARGS)
1.78 kristaps 803: {
804: char *ep, *st;
1.82 kristaps 805: enum roffrule rr;
806:
807: rr = r->last->rule;
808:
809: /*
810: * We display the value of the text if out current evaluation
811: * scope permits us to do so.
812: */
1.78 kristaps 813:
814: st = &(*bufp)[pos];
815: if (NULL == (ep = strstr(st, "\\}"))) {
816: roffnode_cleanscope(r);
1.82 kristaps 817: return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
1.78 kristaps 818: }
819:
1.86 kristaps 820: if (ep == st || (ep > st && '\\' != *(ep - 1)))
1.78 kristaps 821: roffnode_pop(r);
822:
823: roffnode_cleanscope(r);
1.82 kristaps 824: return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
1.74 kristaps 825: }
826:
827:
1.88 kristaps 828: static enum roffrule
829: roff_evalcond(const char *v, int *pos)
830: {
831:
832: switch (v[*pos]) {
833: case ('n'):
834: (*pos)++;
835: return(ROFFRULE_ALLOW);
836: case ('e'):
837: /* FALLTHROUGH */
838: case ('o'):
839: /* FALLTHROUGH */
840: case ('t'):
841: (*pos)++;
842: return(ROFFRULE_DENY);
843: default:
844: break;
845: }
846:
847: while (v[*pos] && ' ' != v[*pos])
848: (*pos)++;
849: return(ROFFRULE_DENY);
850: }
851:
852:
1.75 kristaps 853: /* ARGSUSED */
1.74 kristaps 854: static enum rofferr
1.89 kristaps 855: roff_line(ROFF_ARGS)
856: {
857:
858: return(ROFF_IGN);
859: }
860:
861:
862: /* ARGSUSED */
863: static enum rofferr
1.82 kristaps 864: roff_cond(ROFF_ARGS)
1.74 kristaps 865: {
1.77 kristaps 866: int sv;
1.88 kristaps 867: enum roffrule rule;
1.74 kristaps 868:
1.82 kristaps 869: /* Stack overflow! */
870:
871: if (ROFF_ie == tok && r->rstackpos == RSTACK_MAX - 1) {
872: (*r->msg)(MANDOCERR_MEM, r->data, ln, ppos, NULL);
873: return(ROFF_ERR);
874: }
1.74 kristaps 875:
1.88 kristaps 876: /* First, evaluate the conditional. */
1.84 schwarze 877:
1.88 kristaps 878: if (ROFF_el == tok) {
879: /*
880: * An `.el' will get the value of the current rstack
881: * entry set in prior `ie' calls or defaults to DENY.
882: */
883: if (r->rstackpos < 0)
884: rule = ROFFRULE_DENY;
885: else
886: rule = r->rstack[r->rstackpos];
887: } else
888: rule = roff_evalcond(*bufp, &pos);
1.77 kristaps 889:
890: sv = pos;
1.88 kristaps 891:
1.75 kristaps 892: while (' ' == (*bufp)[pos])
893: pos++;
1.74 kristaps 894:
1.77 kristaps 895: /*
896: * Roff is weird. If we have just white-space after the
897: * conditional, it's considered the BODY and we exit without
898: * really doing anything. Warn about this. It's probably
899: * wrong.
900: */
1.88 kristaps 901:
1.77 kristaps 902: if ('\0' == (*bufp)[pos] && sv != pos) {
1.88 kristaps 903: if ((*r->msg)(MANDOCERR_NOARGS, r->data, ln, ppos, NULL))
904: return(ROFF_IGN);
905: return(ROFF_ERR);
1.77 kristaps 906: }
907:
908: if ( ! roffnode_push(r, tok, ln, ppos))
909: return(ROFF_ERR);
910:
1.88 kristaps 911: r->last->rule = rule;
912:
913: ROFF_DEBUG("roff: cond: %s -> %s\n", roffs[tok].name,
914: ROFFRULE_ALLOW == rule ? "allow" : "deny");
1.82 kristaps 915:
1.84 schwarze 916: if (ROFF_ie == tok) {
1.82 kristaps 917: /*
918: * An if-else will put the NEGATION of the current
919: * evaluated conditional into the stack.
920: */
921: r->rstackpos++;
922: if (ROFFRULE_DENY == r->last->rule)
923: r->rstack[r->rstackpos] = ROFFRULE_ALLOW;
924: else
925: r->rstack[r->rstackpos] = ROFFRULE_DENY;
926: }
1.88 kristaps 927:
928: /* If the parent has false as its rule, then so do we. */
929:
930: if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule) {
1.84 schwarze 931: r->last->rule = ROFFRULE_DENY;
1.88 kristaps 932: ROFF_DEBUG("roff: cond override: %s -> deny\n",
933: roffs[tok].name);
934: }
935:
936: /*
937: * Determine scope. If we're invoked with "\{" trailing the
938: * conditional, then we're in a multiline scope. Else our scope
939: * expires on the next line.
940: */
1.74 kristaps 941:
1.75 kristaps 942: r->last->endspan = 1;
943:
944: if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) {
945: r->last->endspan = -1;
946: pos += 2;
1.88 kristaps 947: ROFF_DEBUG("roff: cond-scope: %s, multi-line\n",
948: roffs[tok].name);
949: } else
950: ROFF_DEBUG("roff: cond-scope: %s, one-line\n",
951: roffs[tok].name);
1.74 kristaps 952:
1.77 kristaps 953: /*
954: * If there are no arguments on the line, the next-line scope is
955: * assumed.
956: */
957:
1.75 kristaps 958: if ('\0' == (*bufp)[pos])
959: return(ROFF_IGN);
1.77 kristaps 960:
961: /* Otherwise re-run the roff parser after recalculating. */
1.74 kristaps 962:
1.75 kristaps 963: *offs = pos;
964: return(ROFF_RERUN);
1.83 schwarze 965: }
966:
967:
968: /* ARGSUSED */
969: static enum rofferr
1.92 schwarze 970: roff_ds(ROFF_ARGS)
971: {
1.96 kristaps 972: char *name, *string;
973:
974: /*
975: * A symbol is named by the first word following the macro
976: * invocation up to a space. Its value is anything after the
977: * name's trailing whitespace and optional double-quote. Thus,
978: *
979: * [.ds foo "bar " ]
980: *
981: * will have `bar " ' as its value.
982: */
1.92 schwarze 983:
984: name = *bufp + pos;
985: if ('\0' == *name)
986: return(ROFF_IGN);
987:
988: string = name;
1.96 kristaps 989: /* Read until end of name. */
1.92 schwarze 990: while (*string && ' ' != *string)
991: string++;
1.96 kristaps 992:
993: /* Nil-terminate name. */
1.92 schwarze 994: if (*string)
1.96 kristaps 995: *(string++) = '\0';
996:
997: /* Read past spaces. */
998: while (*string && ' ' == *string)
999: string++;
1000:
1001: /* Read passed initial double-quote. */
1.92 schwarze 1002: if (*string && '"' == *string)
1003: string++;
1004:
1.96 kristaps 1005: /* The rest is the value. */
1.94 kristaps 1006: roff_setstr(r, name, string);
1.92 schwarze 1007: return(ROFF_IGN);
1008: }
1009:
1010:
1011: /* ARGSUSED */
1012: static enum rofferr
1.89 kristaps 1013: roff_nr(ROFF_ARGS)
1.83 schwarze 1014: {
1.89 kristaps 1015: const char *key, *val;
1.91 kristaps 1016: struct reg *rg;
1.89 kristaps 1017:
1018: key = &(*bufp)[pos];
1.91 kristaps 1019: rg = r->regs->regs;
1.89 kristaps 1020:
1021: /* Parse register request. */
1022: while ((*bufp)[pos] && ' ' != (*bufp)[pos])
1023: pos++;
1024:
1025: /*
1026: * Set our nil terminator. Because this line is going to be
1027: * ignored anyway, we can munge it as we please.
1028: */
1029: if ((*bufp)[pos])
1030: (*bufp)[pos++] = '\0';
1031:
1032: /* Skip whitespace to register token. */
1033: while ((*bufp)[pos] && ' ' == (*bufp)[pos])
1034: pos++;
1035:
1036: val = &(*bufp)[pos];
1037:
1038: /* Process register token. */
1039:
1040: if (0 == strcmp(key, "nS")) {
1.91 kristaps 1041: rg[(int)REG_nS].set = 1;
1042: if ( ! roff_parse_nat(val, &rg[(int)REG_nS].v.u))
1043: rg[(int)REG_nS].v.u = 0;
1.89 kristaps 1044:
1.91 kristaps 1045: ROFF_DEBUG("roff: register nS: %u\n",
1046: rg[(int)REG_nS].v.u);
1.89 kristaps 1047: } else
1048: ROFF_DEBUG("roff: ignoring register: %s\n", key);
1.83 schwarze 1049:
1050: return(ROFF_IGN);
1.92 schwarze 1051: }
1052:
1053:
1.94 kristaps 1054: static void
1055: roff_setstr(struct roff *r, const char *name, const char *string)
1.92 schwarze 1056: {
1057: struct roffstr *n;
1058: char *namecopy;
1059:
1.94 kristaps 1060: n = r->first_string;
1.92 schwarze 1061: while (n && strcmp(name, n->name))
1062: n = n->next;
1.94 kristaps 1063:
1064: if (NULL == n) {
1065: namecopy = mandoc_strdup(name);
1066: n = mandoc_malloc(sizeof(struct roffstr));
1067: n->name = namecopy;
1068: n->next = r->first_string;
1069: r->first_string = n;
1070: } else
1.92 schwarze 1071: free(n->string);
1.94 kristaps 1072:
1.96 kristaps 1073: ROFF_DEBUG("roff: new symbol: [%s] = [%s]\n", name, string);
1.94 kristaps 1074: n->string = string ? strdup(string) : NULL;
1.92 schwarze 1075: }
1076:
1077:
1.94 kristaps 1078: static const char *
1079: roff_getstrn(const struct roff *r, const char *name, size_t len)
1.92 schwarze 1080: {
1.94 kristaps 1081: const struct roffstr *n;
1.92 schwarze 1082:
1.94 kristaps 1083: n = r->first_string;
1.97 ! kristaps 1084: while (n && (strncmp(name, n->name, len) || '\0' != n->name[(int)len]))
1.92 schwarze 1085: n = n->next;
1.94 kristaps 1086:
1087: return(n ? n->string : NULL);
1.92 schwarze 1088: }
1089:
1.94 kristaps 1090:
1091: static void
1092: roff_freestr(struct roff *r)
1.92 schwarze 1093: {
1094: struct roffstr *n, *nn;
1095:
1.94 kristaps 1096: for (n = r->first_string; n; n = nn) {
1.92 schwarze 1097: free(n->name);
1098: free(n->string);
1099: nn = n->next;
1100: free(n);
1101: }
1.94 kristaps 1102:
1103: r->first_string = NULL;
1.74 kristaps 1104: }
CVSweb