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