Annotation of mandoc/roff.c, Revision 1.99
1.99 ! kristaps 1: /* $Id: roff.c,v 1.98 2010/08/20 01:02:07 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.43 kristaps 31: #include "roff.h"
1.94 kristaps 32: #include "libmandoc.h"
1.33 kristaps 33:
1.82 kristaps 34: #define RSTACK_MAX 128
35:
1.75 kristaps 36: #define ROFF_CTL(c) \
37: ('.' == (c) || '\'' == (c))
38:
1.88 kristaps 39: #if 1
40: #define ROFF_DEBUG(fmt, args...) \
41: do { /* Nothing. */ } while (/*CONSTCOND*/ 0)
42: #else
43: #define ROFF_DEBUG(fmt, args...) \
44: do { fprintf(stderr, fmt , ##args); } while (/*CONSTCOND*/ 0)
45: #endif
46:
1.67 kristaps 47: enum rofft {
1.80 kristaps 48: ROFF_am,
49: ROFF_ami,
50: ROFF_am1,
51: ROFF_de,
52: ROFF_dei,
53: ROFF_de1,
1.83 schwarze 54: ROFF_ds,
1.82 kristaps 55: ROFF_el,
56: ROFF_ie,
1.75 kristaps 57: ROFF_if,
1.76 kristaps 58: ROFF_ig,
1.83 schwarze 59: ROFF_rm,
60: ROFF_tr,
1.76 kristaps 61: ROFF_cblock,
1.75 kristaps 62: ROFF_ccond,
1.89 kristaps 63: ROFF_nr,
1.67 kristaps 64: ROFF_MAX
65: };
66:
1.82 kristaps 67: enum roffrule {
68: ROFFRULE_ALLOW,
69: ROFFRULE_DENY
70: };
71:
1.94 kristaps 72:
73: struct roffstr {
74: char *name; /* key of symbol */
75: char *string; /* current value */
76: struct roffstr *next; /* next in list */
77: };
78:
1.67 kristaps 79: struct roff {
80: struct roffnode *last; /* leaf of stack */
81: mandocmsg msg; /* err/warn/fatal messages */
82: void *data; /* privdata for messages */
1.82 kristaps 83: enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */
84: int rstackpos; /* position in rstack */
1.90 kristaps 85: struct regset *regs; /* read/writable registers */
1.94 kristaps 86: struct roffstr *first_string;
1.79 kristaps 87: };
88:
1.67 kristaps 89: struct roffnode {
90: enum rofft tok; /* type of node */
91: struct roffnode *parent; /* up one in stack */
92: int line; /* parse line */
93: int col; /* parse col */
1.79 kristaps 94: char *end; /* end-rules: custom token */
95: int endspan; /* end-rules: next-line or infty */
1.82 kristaps 96: enum roffrule rule; /* current evaluation rule */
1.67 kristaps 97: };
98:
99: #define ROFF_ARGS struct roff *r, /* parse ctx */ \
1.72 kristaps 100: enum rofft tok, /* tok of macro */ \
1.67 kristaps 101: char **bufp, /* input buffer */ \
102: size_t *szp, /* size of input buffer */ \
103: int ln, /* parse line */ \
1.75 kristaps 104: int ppos, /* original pos in buffer */ \
105: int pos, /* current pos in buffer */ \
1.74 kristaps 106: int *offs /* reset offset of buffer data */
1.67 kristaps 107:
108: typedef enum rofferr (*roffproc)(ROFF_ARGS);
109:
110: struct roffmac {
111: const char *name; /* macro name */
1.79 kristaps 112: roffproc proc; /* process new macro */
113: roffproc text; /* process as child text of macro */
114: roffproc sub; /* process as child of macro */
115: int flags;
116: #define ROFFMAC_STRUCT (1 << 0) /* always interpret */
1.85 kristaps 117: struct roffmac *next;
1.67 kristaps 118: };
119:
1.80 kristaps 120: static enum rofferr roff_block(ROFF_ARGS);
121: static enum rofferr roff_block_text(ROFF_ARGS);
122: static enum rofferr roff_block_sub(ROFF_ARGS);
123: static enum rofferr roff_cblock(ROFF_ARGS);
124: static enum rofferr roff_ccond(ROFF_ARGS);
1.82 kristaps 125: static enum rofferr roff_cond(ROFF_ARGS);
126: static enum rofferr roff_cond_text(ROFF_ARGS);
127: static enum rofferr roff_cond_sub(ROFF_ARGS);
1.92 schwarze 128: static enum rofferr roff_ds(ROFF_ARGS);
1.94 kristaps 129: static enum roffrule roff_evalcond(const char *, int *);
130: static void roff_freestr(struct roff *);
131: static const char *roff_getstrn(const struct roff *,
132: const char *, size_t);
1.89 kristaps 133: static enum rofferr roff_line(ROFF_ARGS);
134: static enum rofferr roff_nr(ROFF_ARGS);
1.95 kristaps 135: static int roff_res(struct roff *,
136: char **, size_t *, int);
1.94 kristaps 137: static void roff_setstr(struct roff *,
138: const char *, const char *);
1.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:
767: if (ROFF_MAX == (t = roff_parse(*bufp, &pos)))
768: return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
769:
770: /*
771: * A denied conditional must evaluate its children if and only
772: * if they're either structurally required (such as loops and
773: * conditionals) or a closing macro.
774: */
775: if (ROFFRULE_DENY == rr)
776: if ( ! (ROFFMAC_STRUCT & roffs[t].flags))
777: if (ROFF_ccond != t)
778: return(ROFF_IGN);
779:
780: assert(roffs[t].proc);
1.90 kristaps 781: return((*roffs[t].proc)(r, t, bufp, szp,
782: ln, ppos, pos, offs));
1.82 kristaps 783: }
784:
785:
786: /* ARGSUSED */
787: static enum rofferr
788: roff_cond_text(ROFF_ARGS)
1.78 kristaps 789: {
790: char *ep, *st;
1.82 kristaps 791: enum roffrule rr;
792:
793: rr = r->last->rule;
794:
795: /*
796: * We display the value of the text if out current evaluation
797: * scope permits us to do so.
798: */
1.78 kristaps 799:
800: st = &(*bufp)[pos];
801: if (NULL == (ep = strstr(st, "\\}"))) {
802: roffnode_cleanscope(r);
1.82 kristaps 803: return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
1.78 kristaps 804: }
805:
1.86 kristaps 806: if (ep == st || (ep > st && '\\' != *(ep - 1)))
1.78 kristaps 807: roffnode_pop(r);
808:
809: roffnode_cleanscope(r);
1.82 kristaps 810: return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
1.74 kristaps 811: }
812:
813:
1.88 kristaps 814: static enum roffrule
815: roff_evalcond(const char *v, int *pos)
816: {
817:
818: switch (v[*pos]) {
819: case ('n'):
820: (*pos)++;
821: return(ROFFRULE_ALLOW);
822: case ('e'):
823: /* FALLTHROUGH */
824: case ('o'):
825: /* FALLTHROUGH */
826: case ('t'):
827: (*pos)++;
828: return(ROFFRULE_DENY);
829: default:
830: break;
831: }
832:
833: while (v[*pos] && ' ' != v[*pos])
834: (*pos)++;
835: return(ROFFRULE_DENY);
836: }
837:
838:
1.75 kristaps 839: /* ARGSUSED */
1.74 kristaps 840: static enum rofferr
1.89 kristaps 841: roff_line(ROFF_ARGS)
842: {
843:
844: return(ROFF_IGN);
845: }
846:
847:
848: /* ARGSUSED */
849: static enum rofferr
1.82 kristaps 850: roff_cond(ROFF_ARGS)
1.74 kristaps 851: {
1.77 kristaps 852: int sv;
1.88 kristaps 853: enum roffrule rule;
1.74 kristaps 854:
1.82 kristaps 855: /* Stack overflow! */
856:
857: if (ROFF_ie == tok && r->rstackpos == RSTACK_MAX - 1) {
858: (*r->msg)(MANDOCERR_MEM, r->data, ln, ppos, NULL);
859: return(ROFF_ERR);
860: }
1.74 kristaps 861:
1.88 kristaps 862: /* First, evaluate the conditional. */
1.84 schwarze 863:
1.88 kristaps 864: if (ROFF_el == tok) {
865: /*
866: * An `.el' will get the value of the current rstack
867: * entry set in prior `ie' calls or defaults to DENY.
868: */
869: if (r->rstackpos < 0)
870: rule = ROFFRULE_DENY;
871: else
872: rule = r->rstack[r->rstackpos];
873: } else
874: rule = roff_evalcond(*bufp, &pos);
1.77 kristaps 875:
876: sv = pos;
1.88 kristaps 877:
1.75 kristaps 878: while (' ' == (*bufp)[pos])
879: pos++;
1.74 kristaps 880:
1.77 kristaps 881: /*
882: * Roff is weird. If we have just white-space after the
883: * conditional, it's considered the BODY and we exit without
884: * really doing anything. Warn about this. It's probably
885: * wrong.
886: */
1.88 kristaps 887:
1.77 kristaps 888: if ('\0' == (*bufp)[pos] && sv != pos) {
1.88 kristaps 889: if ((*r->msg)(MANDOCERR_NOARGS, r->data, ln, ppos, NULL))
890: return(ROFF_IGN);
891: return(ROFF_ERR);
1.77 kristaps 892: }
893:
1.98 schwarze 894: roffnode_push(r, tok, ln, ppos);
1.77 kristaps 895:
1.88 kristaps 896: r->last->rule = rule;
897:
898: ROFF_DEBUG("roff: cond: %s -> %s\n", roffs[tok].name,
899: ROFFRULE_ALLOW == rule ? "allow" : "deny");
1.82 kristaps 900:
1.84 schwarze 901: if (ROFF_ie == tok) {
1.82 kristaps 902: /*
903: * An if-else will put the NEGATION of the current
904: * evaluated conditional into the stack.
905: */
906: r->rstackpos++;
907: if (ROFFRULE_DENY == r->last->rule)
908: r->rstack[r->rstackpos] = ROFFRULE_ALLOW;
909: else
910: r->rstack[r->rstackpos] = ROFFRULE_DENY;
911: }
1.88 kristaps 912:
913: /* If the parent has false as its rule, then so do we. */
914:
915: if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule) {
1.84 schwarze 916: r->last->rule = ROFFRULE_DENY;
1.88 kristaps 917: ROFF_DEBUG("roff: cond override: %s -> deny\n",
918: roffs[tok].name);
919: }
920:
921: /*
922: * Determine scope. If we're invoked with "\{" trailing the
923: * conditional, then we're in a multiline scope. Else our scope
924: * expires on the next line.
925: */
1.74 kristaps 926:
1.75 kristaps 927: r->last->endspan = 1;
928:
929: if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) {
930: r->last->endspan = -1;
931: pos += 2;
1.88 kristaps 932: ROFF_DEBUG("roff: cond-scope: %s, multi-line\n",
933: roffs[tok].name);
934: } else
935: ROFF_DEBUG("roff: cond-scope: %s, one-line\n",
936: roffs[tok].name);
1.74 kristaps 937:
1.77 kristaps 938: /*
939: * If there are no arguments on the line, the next-line scope is
940: * assumed.
941: */
942:
1.75 kristaps 943: if ('\0' == (*bufp)[pos])
944: return(ROFF_IGN);
1.77 kristaps 945:
946: /* Otherwise re-run the roff parser after recalculating. */
1.74 kristaps 947:
1.75 kristaps 948: *offs = pos;
949: return(ROFF_RERUN);
1.83 schwarze 950: }
951:
952:
953: /* ARGSUSED */
954: static enum rofferr
1.92 schwarze 955: roff_ds(ROFF_ARGS)
956: {
1.96 kristaps 957: char *name, *string;
958:
959: /*
960: * A symbol is named by the first word following the macro
961: * invocation up to a space. Its value is anything after the
962: * name's trailing whitespace and optional double-quote. Thus,
963: *
964: * [.ds foo "bar " ]
965: *
966: * will have `bar " ' as its value.
967: */
1.92 schwarze 968:
969: name = *bufp + pos;
970: if ('\0' == *name)
971: return(ROFF_IGN);
972:
973: string = name;
1.96 kristaps 974: /* Read until end of name. */
1.92 schwarze 975: while (*string && ' ' != *string)
976: string++;
1.96 kristaps 977:
978: /* Nil-terminate name. */
1.92 schwarze 979: if (*string)
1.96 kristaps 980: *(string++) = '\0';
981:
982: /* Read past spaces. */
983: while (*string && ' ' == *string)
984: string++;
985:
986: /* Read passed initial double-quote. */
1.92 schwarze 987: if (*string && '"' == *string)
988: string++;
989:
1.96 kristaps 990: /* The rest is the value. */
1.94 kristaps 991: roff_setstr(r, name, string);
1.92 schwarze 992: return(ROFF_IGN);
993: }
994:
995:
996: /* ARGSUSED */
997: static enum rofferr
1.89 kristaps 998: roff_nr(ROFF_ARGS)
1.83 schwarze 999: {
1.89 kristaps 1000: const char *key, *val;
1.91 kristaps 1001: struct reg *rg;
1.89 kristaps 1002:
1003: key = &(*bufp)[pos];
1.91 kristaps 1004: rg = r->regs->regs;
1.89 kristaps 1005:
1006: /* Parse register request. */
1007: while ((*bufp)[pos] && ' ' != (*bufp)[pos])
1008: pos++;
1009:
1010: /*
1011: * Set our nil terminator. Because this line is going to be
1012: * ignored anyway, we can munge it as we please.
1013: */
1014: if ((*bufp)[pos])
1015: (*bufp)[pos++] = '\0';
1016:
1017: /* Skip whitespace to register token. */
1018: while ((*bufp)[pos] && ' ' == (*bufp)[pos])
1019: pos++;
1020:
1021: val = &(*bufp)[pos];
1022:
1023: /* Process register token. */
1024:
1025: if (0 == strcmp(key, "nS")) {
1.91 kristaps 1026: rg[(int)REG_nS].set = 1;
1027: if ( ! roff_parse_nat(val, &rg[(int)REG_nS].v.u))
1028: rg[(int)REG_nS].v.u = 0;
1.89 kristaps 1029:
1.91 kristaps 1030: ROFF_DEBUG("roff: register nS: %u\n",
1031: rg[(int)REG_nS].v.u);
1.89 kristaps 1032: } else
1033: ROFF_DEBUG("roff: ignoring register: %s\n", key);
1.83 schwarze 1034:
1035: return(ROFF_IGN);
1.92 schwarze 1036: }
1037:
1038:
1.99 ! kristaps 1039: static char *
! 1040: roff_strdup(const char *name)
! 1041: {
! 1042: char *namecopy, *sv;
! 1043:
! 1044: /*
! 1045: * This isn't a nice simple mandoc_strdup() because we must
! 1046: * handle roff's stupid double-escape rule.
! 1047: */
! 1048: sv = namecopy = mandoc_malloc(strlen(name) + 1);
! 1049: while (*name) {
! 1050: if ('\\' == *name && '\\' == *(name + 1))
! 1051: name++;
! 1052: *namecopy++ = *name++;
! 1053: }
! 1054:
! 1055: *namecopy = '\0';
! 1056: return(sv);
! 1057: }
! 1058:
! 1059:
1.94 kristaps 1060: static void
1061: roff_setstr(struct roff *r, const char *name, const char *string)
1.92 schwarze 1062: {
1063: struct roffstr *n;
1064: char *namecopy;
1065:
1.94 kristaps 1066: n = r->first_string;
1.92 schwarze 1067: while (n && strcmp(name, n->name))
1068: n = n->next;
1.94 kristaps 1069:
1070: if (NULL == n) {
1071: namecopy = mandoc_strdup(name);
1072: n = mandoc_malloc(sizeof(struct roffstr));
1073: n->name = namecopy;
1074: n->next = r->first_string;
1075: r->first_string = n;
1076: } else
1.92 schwarze 1077: free(n->string);
1.94 kristaps 1078:
1.99 ! kristaps 1079: /* Don't use mandoc_strdup: clean out double-escapes. */
! 1080: n->string = string ? roff_strdup(string) : NULL;
! 1081: ROFF_DEBUG("roff: new symbol: [%s] = [%s]\n", name, n->string);
1.92 schwarze 1082: }
1083:
1084:
1.94 kristaps 1085: static const char *
1086: roff_getstrn(const struct roff *r, const char *name, size_t len)
1.92 schwarze 1087: {
1.94 kristaps 1088: const struct roffstr *n;
1.92 schwarze 1089:
1.94 kristaps 1090: n = r->first_string;
1.97 kristaps 1091: while (n && (strncmp(name, n->name, len) || '\0' != n->name[(int)len]))
1.92 schwarze 1092: n = n->next;
1.94 kristaps 1093:
1094: return(n ? n->string : NULL);
1.92 schwarze 1095: }
1096:
1.94 kristaps 1097:
1098: static void
1099: roff_freestr(struct roff *r)
1.92 schwarze 1100: {
1101: struct roffstr *n, *nn;
1102:
1.94 kristaps 1103: for (n = r->first_string; n; n = nn) {
1.92 schwarze 1104: free(n->name);
1105: free(n->string);
1106: nn = n->next;
1107: free(n);
1108: }
1.94 kristaps 1109:
1110: r->first_string = NULL;
1.74 kristaps 1111: }
CVSweb