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