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