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