Merge branch 'vendor/LDNS'
[dragonfly.git] / contrib / mdocml / roff.c
1 /*      $Id: roff.c,v 1.130 2011/03/29 09:00:48 kristaps Exp $ */
2 /*
3  * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4  * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS 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.
17  */
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include <assert.h>
23 #include <errno.h>
24 #include <ctype.h>
25 #include <limits.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdio.h>
29
30 #include "mandoc.h"
31 #include "libroff.h"
32 #include "libmandoc.h"
33
34 #define RSTACK_MAX      128
35
36 enum    rofft {
37         ROFF_ad,
38         ROFF_am,
39         ROFF_ami,
40         ROFF_am1,
41         ROFF_de,
42         ROFF_dei,
43         ROFF_de1,
44         ROFF_ds,
45         ROFF_el,
46         ROFF_hy,
47         ROFF_ie,
48         ROFF_if,
49         ROFF_ig,
50         ROFF_it,
51         ROFF_ne,
52         ROFF_nh,
53         ROFF_nr,
54         ROFF_ns,
55         ROFF_ps,
56         ROFF_rm,
57         ROFF_so,
58         ROFF_ta,
59         ROFF_tr,
60         ROFF_TS,
61         ROFF_TE,
62         ROFF_T_,
63         ROFF_EQ,
64         ROFF_EN,
65         ROFF_cblock,
66         ROFF_ccond, /* FIXME: remove this. */
67         ROFF_USERDEF,
68         ROFF_MAX
69 };
70
71 enum    roffrule {
72         ROFFRULE_ALLOW,
73         ROFFRULE_DENY
74 };
75
76 struct  roffstr {
77         char            *name; /* key of symbol */
78         char            *string; /* current value */
79         struct roffstr  *next; /* next in list */
80 };
81
82 struct  roff {
83         struct mparse   *parse; /* parse point */
84         struct roffnode *last; /* leaf of stack */
85         enum roffrule    rstack[RSTACK_MAX]; /* stack of !`ie' rules */
86         int              rstackpos; /* position in rstack */
87         struct regset   *regs; /* read/writable registers */
88         struct roffstr  *first_string; /* user-defined strings & macros */
89         const char      *current_string; /* value of last called user macro */
90         struct tbl_node *first_tbl; /* first table parsed */
91         struct tbl_node *last_tbl; /* last table parsed */
92         struct tbl_node *tbl; /* current table being parsed */
93         struct eqn_node *last_eqn; /* last equation parsed */
94         struct eqn_node *first_eqn; /* first equation parsed */
95         struct eqn_node *eqn; /* current equation being parsed */
96 };
97
98 struct  roffnode {
99         enum rofft       tok; /* type of node */
100         struct roffnode *parent; /* up one in stack */
101         int              line; /* parse line */
102         int              col; /* parse col */
103         char            *name; /* node name, e.g. macro name */
104         char            *end; /* end-rules: custom token */
105         int              endspan; /* end-rules: next-line or infty */
106         enum roffrule    rule; /* current evaluation rule */
107 };
108
109 #define ROFF_ARGS        struct roff *r, /* parse ctx */ \
110                          enum rofft tok, /* tok of macro */ \
111                          char **bufp, /* input buffer */ \
112                          size_t *szp, /* size of input buffer */ \
113                          int ln, /* parse line */ \
114                          int ppos, /* original pos in buffer */ \
115                          int pos, /* current pos in buffer */ \
116                          int *offs /* reset offset of buffer data */
117
118 typedef enum rofferr (*roffproc)(ROFF_ARGS);
119
120 struct  roffmac {
121         const char      *name; /* macro name */
122         roffproc         proc; /* process new macro */
123         roffproc         text; /* process as child text of macro */
124         roffproc         sub; /* process as child of macro */
125         int              flags;
126 #define ROFFMAC_STRUCT  (1 << 0) /* always interpret */
127         struct roffmac  *next;
128 };
129
130 static  enum rofferr     roff_block(ROFF_ARGS);
131 static  enum rofferr     roff_block_text(ROFF_ARGS);
132 static  enum rofferr     roff_block_sub(ROFF_ARGS);
133 static  enum rofferr     roff_cblock(ROFF_ARGS);
134 static  enum rofferr     roff_ccond(ROFF_ARGS);
135 static  enum rofferr     roff_cond(ROFF_ARGS);
136 static  enum rofferr     roff_cond_text(ROFF_ARGS);
137 static  enum rofferr     roff_cond_sub(ROFF_ARGS);
138 static  enum rofferr     roff_ds(ROFF_ARGS);
139 static  enum roffrule    roff_evalcond(const char *, int *);
140 static  void             roff_freestr(struct roff *);
141 static  char            *roff_getname(struct roff *, char **, int, int);
142 static  const char      *roff_getstrn(const struct roff *, 
143                                 const char *, size_t);
144 static  enum rofferr     roff_line_ignore(ROFF_ARGS);
145 static  enum rofferr     roff_nr(ROFF_ARGS);
146 static  int              roff_res(struct roff *, 
147                                 char **, size_t *, int);
148 static  enum rofferr     roff_rm(ROFF_ARGS);
149 static  void             roff_setstr(struct roff *,
150                                 const char *, const char *, int);
151 static  enum rofferr     roff_so(ROFF_ARGS);
152 static  enum rofferr     roff_TE(ROFF_ARGS);
153 static  enum rofferr     roff_TS(ROFF_ARGS);
154 static  enum rofferr     roff_EQ(ROFF_ARGS);
155 static  enum rofferr     roff_EN(ROFF_ARGS);
156 static  enum rofferr     roff_T_(ROFF_ARGS);
157 static  enum rofferr     roff_userdef(ROFF_ARGS);
158
159 /* See roff_hash_find() */
160
161 #define ASCII_HI         126
162 #define ASCII_LO         33
163 #define HASHWIDTH       (ASCII_HI - ASCII_LO + 1)
164
165 static  struct roffmac  *hash[HASHWIDTH];
166
167 static  struct roffmac   roffs[ROFF_MAX] = {
168         { "ad", roff_line_ignore, NULL, NULL, 0, NULL },
169         { "am", roff_block, roff_block_text, roff_block_sub, 0, NULL },
170         { "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },
171         { "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
172         { "de", roff_block, roff_block_text, roff_block_sub, 0, NULL },
173         { "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },
174         { "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
175         { "ds", roff_ds, NULL, NULL, 0, NULL },
176         { "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
177         { "hy", roff_line_ignore, NULL, NULL, 0, NULL },
178         { "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
179         { "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
180         { "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL },
181         { "it", roff_line_ignore, NULL, NULL, 0, NULL },
182         { "ne", roff_line_ignore, NULL, NULL, 0, NULL },
183         { "nh", roff_line_ignore, NULL, NULL, 0, NULL },
184         { "nr", roff_nr, NULL, NULL, 0, NULL },
185         { "ns", roff_line_ignore, NULL, NULL, 0, NULL },
186         { "ps", roff_line_ignore, NULL, NULL, 0, NULL },
187         { "rm", roff_rm, NULL, NULL, 0, NULL },
188         { "so", roff_so, NULL, NULL, 0, NULL },
189         { "ta", roff_line_ignore, NULL, NULL, 0, NULL },
190         { "tr", roff_line_ignore, NULL, NULL, 0, NULL },
191         { "TS", roff_TS, NULL, NULL, 0, NULL },
192         { "TE", roff_TE, NULL, NULL, 0, NULL },
193         { "T&", roff_T_, NULL, NULL, 0, NULL },
194         { "EQ", roff_EQ, NULL, NULL, 0, NULL },
195         { "EN", roff_EN, NULL, NULL, 0, NULL },
196         { ".", roff_cblock, NULL, NULL, 0, NULL },
197         { "\\}", roff_ccond, NULL, NULL, 0, NULL },
198         { NULL, roff_userdef, NULL, NULL, 0, NULL },
199 };
200
201 static  void             roff_free1(struct roff *);
202 static  enum rofft       roff_hash_find(const char *, size_t);
203 static  void             roff_hash_init(void);
204 static  void             roffnode_cleanscope(struct roff *);
205 static  void             roffnode_push(struct roff *, enum rofft,
206                                 const char *, int, int);
207 static  void             roffnode_pop(struct roff *);
208 static  enum rofft       roff_parse(struct roff *, const char *, int *);
209 static  int              roff_parse_nat(const char *, unsigned int *);
210
211 /* See roff_hash_find() */
212 #define ROFF_HASH(p)    (p[0] - ASCII_LO)
213
214 static void
215 roff_hash_init(void)
216 {
217         struct roffmac   *n;
218         int               buc, i;
219
220         for (i = 0; i < (int)ROFF_USERDEF; i++) {
221                 assert(roffs[i].name[0] >= ASCII_LO);
222                 assert(roffs[i].name[0] <= ASCII_HI);
223
224                 buc = ROFF_HASH(roffs[i].name);
225
226                 if (NULL != (n = hash[buc])) {
227                         for ( ; n->next; n = n->next)
228                                 /* Do nothing. */ ;
229                         n->next = &roffs[i];
230                 } else
231                         hash[buc] = &roffs[i];
232         }
233 }
234
235
236 /*
237  * Look up a roff token by its name.  Returns ROFF_MAX if no macro by
238  * the nil-terminated string name could be found.
239  */
240 static enum rofft
241 roff_hash_find(const char *p, size_t s)
242 {
243         int              buc;
244         struct roffmac  *n;
245
246         /*
247          * libroff has an extremely simple hashtable, for the time
248          * being, which simply keys on the first character, which must
249          * be printable, then walks a chain.  It works well enough until
250          * optimised.
251          */
252
253         if (p[0] < ASCII_LO || p[0] > ASCII_HI)
254                 return(ROFF_MAX);
255
256         buc = ROFF_HASH(p);
257
258         if (NULL == (n = hash[buc]))
259                 return(ROFF_MAX);
260         for ( ; n; n = n->next)
261                 if (0 == strncmp(n->name, p, s) && '\0' == n->name[(int)s])
262                         return((enum rofft)(n - roffs));
263
264         return(ROFF_MAX);
265 }
266
267
268 /*
269  * Pop the current node off of the stack of roff instructions currently
270  * pending.
271  */
272 static void
273 roffnode_pop(struct roff *r)
274 {
275         struct roffnode *p;
276
277         assert(r->last);
278         p = r->last; 
279
280         if (ROFF_el == p->tok)
281                 if (r->rstackpos > -1)
282                         r->rstackpos--;
283
284         r->last = r->last->parent;
285         free(p->name);
286         free(p->end);
287         free(p);
288 }
289
290
291 /*
292  * Push a roff node onto the instruction stack.  This must later be
293  * removed with roffnode_pop().
294  */
295 static void
296 roffnode_push(struct roff *r, enum rofft tok, const char *name,
297                 int line, int col)
298 {
299         struct roffnode *p;
300
301         p = mandoc_calloc(1, sizeof(struct roffnode));
302         p->tok = tok;
303         if (name)
304                 p->name = mandoc_strdup(name);
305         p->parent = r->last;
306         p->line = line;
307         p->col = col;
308         p->rule = p->parent ? p->parent->rule : ROFFRULE_DENY;
309
310         r->last = p;
311 }
312
313
314 static void
315 roff_free1(struct roff *r)
316 {
317         struct tbl_node *t;
318         struct eqn_node *e;
319
320         while (NULL != (t = r->first_tbl)) {
321                 r->first_tbl = t->next;
322                 tbl_free(t);
323         }
324
325         r->first_tbl = r->last_tbl = r->tbl = NULL;
326
327         while (NULL != (e = r->first_eqn)) {
328                 r->first_eqn = e->next;
329                 eqn_free(e);
330         }
331
332         r->first_eqn = r->last_eqn = r->eqn = NULL;
333
334         while (r->last)
335                 roffnode_pop(r);
336
337         roff_freestr(r);
338 }
339
340
341 void
342 roff_reset(struct roff *r)
343 {
344
345         roff_free1(r);
346 }
347
348
349 void
350 roff_free(struct roff *r)
351 {
352
353         roff_free1(r);
354         free(r);
355 }
356
357
358 struct roff *
359 roff_alloc(struct regset *regs, struct mparse *parse)
360 {
361         struct roff     *r;
362
363         r = mandoc_calloc(1, sizeof(struct roff));
364         r->regs = regs;
365         r->parse = parse;
366         r->rstackpos = -1;
367         
368         roff_hash_init();
369         return(r);
370 }
371
372
373 /*
374  * Pre-filter each and every line for reserved words (one beginning with
375  * `\*', e.g., `\*(ab').  These must be handled before the actual line
376  * is processed. 
377  */
378 static int
379 roff_res(struct roff *r, char **bufp, size_t *szp, int pos)
380 {
381         const char      *stesc; /* start of an escape sequence ('\\') */
382         const char      *stnam; /* start of the name, after "[(*" */
383         const char      *cp;    /* end of the name, e.g. before ']' */
384         const char      *res;   /* the string to be substituted */
385         int              i, maxl;
386         size_t           nsz;
387         char            *n;
388
389         /* Search for a leading backslash and save a pointer to it. */
390
391         cp = *bufp + pos;
392         while (NULL != (cp = strchr(cp, '\\'))) {
393                 stesc = cp++;
394
395                 /*
396                  * The second character must be an asterisk.
397                  * If it isn't, skip it anyway:  It is escaped,
398                  * so it can't start another escape sequence.
399                  */
400
401                 if ('\0' == *cp)
402                         return(1);
403                 if ('*' != *cp++)
404                         continue;
405
406                 /*
407                  * The third character decides the length
408                  * of the name of the string.
409                  * Save a pointer to the name.
410                  */
411
412                 switch (*cp) {
413                 case ('\0'):
414                         return(1);
415                 case ('('):
416                         cp++;
417                         maxl = 2;
418                         break;
419                 case ('['):
420                         cp++;
421                         maxl = 0;
422                         break;
423                 default:
424                         maxl = 1;
425                         break;
426                 }
427                 stnam = cp;
428
429                 /* Advance to the end of the name. */
430
431                 for (i = 0; 0 == maxl || i < maxl; i++, cp++) {
432                         if ('\0' == *cp)
433                                 return(1); /* Error. */
434                         if (0 == maxl && ']' == *cp)
435                                 break;
436                 }
437
438                 /*
439                  * Retrieve the replacement string; if it is
440                  * undefined, resume searching for escapes.
441                  */
442
443                 res = roff_getstrn(r, stnam, (size_t)i);
444
445                 if (NULL == res) {
446                         cp -= maxl ? 1 : 0;
447                         continue;
448                 }
449
450                 /* Replace the escape sequence by the string. */
451
452                 nsz = *szp + strlen(res) + 1;
453                 n = mandoc_malloc(nsz);
454
455                 strlcpy(n, *bufp, (size_t)(stesc - *bufp + 1));
456                 strlcat(n, res, nsz);
457                 strlcat(n, cp + (maxl ? 0 : 1), nsz);
458
459                 free(*bufp);
460
461                 *bufp = n;
462                 *szp = nsz;
463                 return(0);
464         }
465
466         return(1);
467 }
468
469
470 enum rofferr
471 roff_parseln(struct roff *r, int ln, char **bufp, 
472                 size_t *szp, int pos, int *offs)
473 {
474         enum rofft       t;
475         enum rofferr     e;
476         int              ppos, ctl;
477
478         /*
479          * Run the reserved-word filter only if we have some reserved
480          * words to fill in.
481          */
482
483         if (r->first_string && ! roff_res(r, bufp, szp, pos))
484                 return(ROFF_REPARSE);
485
486         ppos = pos;
487         ctl = mandoc_getcontrol(*bufp, &pos);
488
489         /*
490          * First, if a scope is open and we're not a macro, pass the
491          * text through the macro's filter.  If a scope isn't open and
492          * we're not a macro, just let it through.
493          * Finally, if there's an equation scope open, divert it into it
494          * no matter our state.
495          */
496
497         if (r->last && ! ctl) {
498                 t = r->last->tok;
499                 assert(roffs[t].text);
500                 e = (*roffs[t].text)
501                         (r, t, bufp, szp, ln, pos, pos, offs);
502                 assert(ROFF_IGN == e || ROFF_CONT == e);
503                 if (ROFF_CONT != e)
504                         return(e);
505                 if (r->eqn)
506                         return(eqn_read(&r->eqn, ln, *bufp, pos));
507                 if (r->tbl)
508                         return(tbl_read(r->tbl, ln, *bufp, pos));
509                 return(ROFF_CONT);
510         } else if ( ! ctl) {
511                 if (r->eqn)
512                         return(eqn_read(&r->eqn, ln, *bufp, pos));
513                 if (r->tbl)
514                         return(tbl_read(r->tbl, ln, *bufp, pos));
515                 return(ROFF_CONT);
516         } else if (r->eqn)
517                 return(eqn_read(&r->eqn, ln, *bufp, ppos));
518
519         /*
520          * If a scope is open, go to the child handler for that macro,
521          * as it may want to preprocess before doing anything with it.
522          * Don't do so if an equation is open.
523          */
524
525         if (r->last) {
526                 t = r->last->tok;
527                 assert(roffs[t].sub);
528                 return((*roffs[t].sub)
529                                 (r, t, bufp, szp, 
530                                  ln, ppos, pos, offs));
531         }
532
533         /*
534          * Lastly, as we've no scope open, try to look up and execute
535          * the new macro.  If no macro is found, simply return and let
536          * the compilers handle it.
537          */
538
539         if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos)))
540                 return(ROFF_CONT);
541
542         assert(roffs[t].proc);
543         return((*roffs[t].proc)
544                         (r, t, bufp, szp, 
545                          ln, ppos, pos, offs));
546 }
547
548
549 void
550 roff_endparse(struct roff *r)
551 {
552
553         if (r->last)
554                 mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
555                                 r->last->line, r->last->col, NULL);
556
557         if (r->eqn) {
558                 mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse, 
559                                 r->eqn->eqn.line, r->eqn->eqn.pos, NULL);
560                 eqn_end(r->eqn);
561                 r->eqn = NULL;
562         }
563
564         if (r->tbl) {
565                 mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse, 
566                                 r->tbl->line, r->tbl->pos, NULL);
567                 tbl_end(r->tbl);
568                 r->tbl = NULL;
569         }
570 }
571
572 /*
573  * Parse a roff node's type from the input buffer.  This must be in the
574  * form of ".foo xxx" in the usual way.
575  */
576 static enum rofft
577 roff_parse(struct roff *r, const char *buf, int *pos)
578 {
579         const char      *mac;
580         size_t           maclen;
581         enum rofft       t;
582
583         if ('\0' == buf[*pos] || '"' == buf[*pos])
584                 return(ROFF_MAX);
585
586         mac = buf + *pos;
587         maclen = strcspn(mac, " \\\t\0");
588
589         t = (r->current_string = roff_getstrn(r, mac, maclen))
590             ? ROFF_USERDEF : roff_hash_find(mac, maclen);
591
592         *pos += (int)maclen;
593
594         while (buf[*pos] && ' ' == buf[*pos])
595                 (*pos)++;
596
597         return(t);
598 }
599
600
601 static int
602 roff_parse_nat(const char *buf, unsigned int *res)
603 {
604         char            *ep;
605         long             lval;
606
607         errno = 0;
608         lval = strtol(buf, &ep, 10);
609         if (buf[0] == '\0' || *ep != '\0')
610                 return(0);
611         if ((errno == ERANGE && 
612                         (lval == LONG_MAX || lval == LONG_MIN)) ||
613                         (lval > INT_MAX || lval < 0))
614                 return(0);
615
616         *res = (unsigned int)lval;
617         return(1);
618 }
619
620
621 /* ARGSUSED */
622 static enum rofferr
623 roff_cblock(ROFF_ARGS)
624 {
625
626         /*
627          * A block-close `..' should only be invoked as a child of an
628          * ignore macro, otherwise raise a warning and just ignore it.
629          */
630
631         if (NULL == r->last) {
632                 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
633                 return(ROFF_IGN);
634         }
635
636         switch (r->last->tok) {
637         case (ROFF_am):
638                 /* FALLTHROUGH */
639         case (ROFF_ami):
640                 /* FALLTHROUGH */
641         case (ROFF_am1):
642                 /* FALLTHROUGH */
643         case (ROFF_de):
644                 /* ROFF_de1 is remapped to ROFF_de in roff_block(). */
645                 /* FALLTHROUGH */
646         case (ROFF_dei):
647                 /* FALLTHROUGH */
648         case (ROFF_ig):
649                 break;
650         default:
651                 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
652                 return(ROFF_IGN);
653         }
654
655         if ((*bufp)[pos])
656                 mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
657
658         roffnode_pop(r);
659         roffnode_cleanscope(r);
660         return(ROFF_IGN);
661
662 }
663
664
665 static void
666 roffnode_cleanscope(struct roff *r)
667 {
668
669         while (r->last) {
670                 if (--r->last->endspan < 0)
671                         break;
672                 roffnode_pop(r);
673         }
674 }
675
676
677 /* ARGSUSED */
678 static enum rofferr
679 roff_ccond(ROFF_ARGS)
680 {
681
682         if (NULL == r->last) {
683                 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
684                 return(ROFF_IGN);
685         }
686
687         switch (r->last->tok) {
688         case (ROFF_el):
689                 /* FALLTHROUGH */
690         case (ROFF_ie):
691                 /* FALLTHROUGH */
692         case (ROFF_if):
693                 break;
694         default:
695                 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
696                 return(ROFF_IGN);
697         }
698
699         if (r->last->endspan > -1) {
700                 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
701                 return(ROFF_IGN);
702         }
703
704         if ((*bufp)[pos])
705                 mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
706
707         roffnode_pop(r);
708         roffnode_cleanscope(r);
709         return(ROFF_IGN);
710 }
711
712
713 /* ARGSUSED */
714 static enum rofferr
715 roff_block(ROFF_ARGS)
716 {
717         int             sv;
718         size_t          sz;
719         char            *name;
720
721         name = NULL;
722
723         if (ROFF_ig != tok) {
724                 if ('\0' == (*bufp)[pos]) {
725                         mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL);
726                         return(ROFF_IGN);
727                 }
728
729                 /*
730                  * Re-write `de1', since we don't really care about
731                  * groff's strange compatibility mode, into `de'.
732                  */
733
734                 if (ROFF_de1 == tok)
735                         tok = ROFF_de;
736                 if (ROFF_de == tok)
737                         name = *bufp + pos;
738                 else
739                         mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos,
740                             roffs[tok].name);
741
742                 while ((*bufp)[pos] && ' ' != (*bufp)[pos])
743                         pos++;
744
745                 while (' ' == (*bufp)[pos])
746                         (*bufp)[pos++] = '\0';
747         }
748
749         roffnode_push(r, tok, name, ln, ppos);
750
751         /*
752          * At the beginning of a `de' macro, clear the existing string
753          * with the same name, if there is one.  New content will be
754          * added from roff_block_text() in multiline mode.
755          */
756
757         if (ROFF_de == tok)
758                 roff_setstr(r, name, "", 0);
759
760         if ('\0' == (*bufp)[pos])
761                 return(ROFF_IGN);
762
763         /* If present, process the custom end-of-line marker. */
764
765         sv = pos;
766         while ((*bufp)[pos] &&
767                         ' ' != (*bufp)[pos] && 
768                         '\t' != (*bufp)[pos])
769                 pos++;
770
771         /*
772          * Note: groff does NOT like escape characters in the input.
773          * Instead of detecting this, we're just going to let it fly and
774          * to hell with it.
775          */
776
777         assert(pos > sv);
778         sz = (size_t)(pos - sv);
779
780         if (1 == sz && '.' == (*bufp)[sv])
781                 return(ROFF_IGN);
782
783         r->last->end = mandoc_malloc(sz + 1);
784
785         memcpy(r->last->end, *bufp + sv, sz);
786         r->last->end[(int)sz] = '\0';
787
788         if ((*bufp)[pos])
789                 mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
790
791         return(ROFF_IGN);
792 }
793
794
795 /* ARGSUSED */
796 static enum rofferr
797 roff_block_sub(ROFF_ARGS)
798 {
799         enum rofft      t;
800         int             i, j;
801
802         /*
803          * First check whether a custom macro exists at this level.  If
804          * it does, then check against it.  This is some of groff's
805          * stranger behaviours.  If we encountered a custom end-scope
806          * tag and that tag also happens to be a "real" macro, then we
807          * need to try interpreting it again as a real macro.  If it's
808          * not, then return ignore.  Else continue.
809          */
810
811         if (r->last->end) {
812                 for (i = pos, j = 0; r->last->end[j]; j++, i++)
813                         if ((*bufp)[i] != r->last->end[j])
814                                 break;
815
816                 if ('\0' == r->last->end[j] && 
817                                 ('\0' == (*bufp)[i] ||
818                                  ' ' == (*bufp)[i] ||
819                                  '\t' == (*bufp)[i])) {
820                         roffnode_pop(r);
821                         roffnode_cleanscope(r);
822
823                         while (' ' == (*bufp)[i] || '\t' == (*bufp)[i])
824                                 i++;
825
826                         pos = i;
827                         if (ROFF_MAX != roff_parse(r, *bufp, &pos))
828                                 return(ROFF_RERUN);
829                         return(ROFF_IGN);
830                 }
831         }
832
833         /*
834          * If we have no custom end-query or lookup failed, then try
835          * pulling it out of the hashtable.
836          */
837
838         if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos)))
839                 return(ROFF_IGN);
840
841         /*
842          * Macros other than block-end are only significant
843          * in `de' blocks; elsewhere, simply throw them away.
844          */
845         if (ROFF_cblock != t) {
846                 if (ROFF_de == tok)
847                         roff_setstr(r, r->last->name, *bufp + ppos, 1);
848                 return(ROFF_IGN);
849         }
850
851         assert(roffs[t].proc);
852         return((*roffs[t].proc)(r, t, bufp, szp, 
853                                 ln, ppos, pos, offs));
854 }
855
856
857 /* ARGSUSED */
858 static enum rofferr
859 roff_block_text(ROFF_ARGS)
860 {
861
862         if (ROFF_de == tok)
863                 roff_setstr(r, r->last->name, *bufp + pos, 1);
864
865         return(ROFF_IGN);
866 }
867
868
869 /* ARGSUSED */
870 static enum rofferr
871 roff_cond_sub(ROFF_ARGS)
872 {
873         enum rofft       t;
874         enum roffrule    rr;
875
876         rr = r->last->rule;
877
878         /* 
879          * Clean out scope.  If we've closed ourselves, then don't
880          * continue. 
881          */
882
883         roffnode_cleanscope(r);
884
885         if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos))) {
886                 if ('\\' == (*bufp)[pos] && '}' == (*bufp)[pos + 1])
887                         return(roff_ccond
888                                 (r, ROFF_ccond, bufp, szp,
889                                  ln, pos, pos + 2, offs));
890                 return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
891         }
892
893         /*
894          * A denied conditional must evaluate its children if and only
895          * if they're either structurally required (such as loops and
896          * conditionals) or a closing macro.
897          */
898         if (ROFFRULE_DENY == rr)
899                 if ( ! (ROFFMAC_STRUCT & roffs[t].flags))
900                         if (ROFF_ccond != t)
901                                 return(ROFF_IGN);
902
903         assert(roffs[t].proc);
904         return((*roffs[t].proc)(r, t, bufp, szp, 
905                                 ln, ppos, pos, offs));
906 }
907
908
909 /* ARGSUSED */
910 static enum rofferr
911 roff_cond_text(ROFF_ARGS)
912 {
913         char            *ep, *st;
914         enum roffrule    rr;
915
916         rr = r->last->rule;
917
918         /*
919          * We display the value of the text if out current evaluation
920          * scope permits us to do so.
921          */
922
923         /* FIXME: use roff_ccond? */
924
925         st = &(*bufp)[pos];
926         if (NULL == (ep = strstr(st, "\\}"))) {
927                 roffnode_cleanscope(r);
928                 return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
929         }
930
931         if (ep == st || (ep > st && '\\' != *(ep - 1)))
932                 roffnode_pop(r);
933
934         roffnode_cleanscope(r);
935         return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
936 }
937
938
939 static enum roffrule
940 roff_evalcond(const char *v, int *pos)
941 {
942
943         switch (v[*pos]) {
944         case ('n'):
945                 (*pos)++;
946                 return(ROFFRULE_ALLOW);
947         case ('e'):
948                 /* FALLTHROUGH */
949         case ('o'):
950                 /* FALLTHROUGH */
951         case ('t'):
952                 (*pos)++;
953                 return(ROFFRULE_DENY);
954         default:
955                 break;
956         }
957
958         while (v[*pos] && ' ' != v[*pos])
959                 (*pos)++;
960         return(ROFFRULE_DENY);
961 }
962
963 /* ARGSUSED */
964 static enum rofferr
965 roff_line_ignore(ROFF_ARGS)
966 {
967
968         if (ROFF_it == tok)
969                 mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos, "it");
970
971         return(ROFF_IGN);
972 }
973
974 /* ARGSUSED */
975 static enum rofferr
976 roff_cond(ROFF_ARGS)
977 {
978         int              sv;
979         enum roffrule    rule;
980
981         /* Stack overflow! */
982
983         if (ROFF_ie == tok && r->rstackpos == RSTACK_MAX - 1) {
984                 mandoc_msg(MANDOCERR_MEM, r->parse, ln, ppos, NULL);
985                 return(ROFF_ERR);
986         }
987
988         /* First, evaluate the conditional. */
989
990         if (ROFF_el == tok) {
991                 /* 
992                  * An `.el' will get the value of the current rstack
993                  * entry set in prior `ie' calls or defaults to DENY.
994                  */
995                 if (r->rstackpos < 0)
996                         rule = ROFFRULE_DENY;
997                 else
998                         rule = r->rstack[r->rstackpos];
999         } else
1000                 rule = roff_evalcond(*bufp, &pos);
1001
1002         sv = pos;
1003
1004         while (' ' == (*bufp)[pos])
1005                 pos++;
1006
1007         /*
1008          * Roff is weird.  If we have just white-space after the
1009          * conditional, it's considered the BODY and we exit without
1010          * really doing anything.  Warn about this.  It's probably
1011          * wrong.
1012          */
1013
1014         if ('\0' == (*bufp)[pos] && sv != pos) {
1015                 mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL);
1016                 return(ROFF_IGN);
1017         }
1018
1019         roffnode_push(r, tok, NULL, ln, ppos);
1020
1021         r->last->rule = rule;
1022
1023         if (ROFF_ie == tok) {
1024                 /*
1025                  * An if-else will put the NEGATION of the current
1026                  * evaluated conditional into the stack.
1027                  */
1028                 r->rstackpos++;
1029                 if (ROFFRULE_DENY == r->last->rule)
1030                         r->rstack[r->rstackpos] = ROFFRULE_ALLOW;
1031                 else
1032                         r->rstack[r->rstackpos] = ROFFRULE_DENY;
1033         }
1034
1035         /* If the parent has false as its rule, then so do we. */
1036
1037         if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule)
1038                 r->last->rule = ROFFRULE_DENY;
1039
1040         /*
1041          * Determine scope.  If we're invoked with "\{" trailing the
1042          * conditional, then we're in a multiline scope.  Else our scope
1043          * expires on the next line.
1044          */
1045
1046         r->last->endspan = 1;
1047
1048         if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) {
1049                 r->last->endspan = -1;
1050                 pos += 2;
1051         } 
1052
1053         /*
1054          * If there are no arguments on the line, the next-line scope is
1055          * assumed.
1056          */
1057
1058         if ('\0' == (*bufp)[pos])
1059                 return(ROFF_IGN);
1060
1061         /* Otherwise re-run the roff parser after recalculating. */
1062
1063         *offs = pos;
1064         return(ROFF_RERUN);
1065 }
1066
1067
1068 /* ARGSUSED */
1069 static enum rofferr
1070 roff_ds(ROFF_ARGS)
1071 {
1072         char            *name, *string;
1073
1074         /*
1075          * A symbol is named by the first word following the macro
1076          * invocation up to a space.  Its value is anything after the
1077          * name's trailing whitespace and optional double-quote.  Thus,
1078          *
1079          *  [.ds foo "bar  "     ]
1080          *
1081          * will have `bar  "     ' as its value.
1082          */
1083
1084         string = *bufp + pos;
1085         name = roff_getname(r, &string, ln, pos);
1086         if ('\0' == *name)
1087                 return(ROFF_IGN);
1088
1089         /* Read past initial double-quote. */
1090         if ('"' == *string)
1091                 string++;
1092
1093         /* The rest is the value. */
1094         roff_setstr(r, name, string, 0);
1095         return(ROFF_IGN);
1096 }
1097
1098
1099 /* ARGSUSED */
1100 static enum rofferr
1101 roff_nr(ROFF_ARGS)
1102 {
1103         const char      *key;
1104         char            *val;
1105         struct reg      *rg;
1106
1107         val = *bufp + pos;
1108         key = roff_getname(r, &val, ln, pos);
1109         rg = r->regs->regs;
1110
1111         if (0 == strcmp(key, "nS")) {
1112                 rg[(int)REG_nS].set = 1;
1113                 if ( ! roff_parse_nat(val, &rg[(int)REG_nS].v.u))
1114                         rg[(int)REG_nS].v.u = 0;
1115         }
1116
1117         return(ROFF_IGN);
1118 }
1119
1120 /* ARGSUSED */
1121 static enum rofferr
1122 roff_rm(ROFF_ARGS)
1123 {
1124         const char       *name;
1125         char             *cp;
1126
1127         cp = *bufp + pos;
1128         while ('\0' != *cp) {
1129                 name = roff_getname(r, &cp, ln, (int)(cp - *bufp));
1130                 if ('\0' != *name)
1131                         roff_setstr(r, name, NULL, 0);
1132         }
1133         return(ROFF_IGN);
1134 }
1135
1136 /* ARGSUSED */
1137 static enum rofferr
1138 roff_TE(ROFF_ARGS)
1139 {
1140
1141         if (NULL == r->tbl)
1142                 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1143         else
1144                 tbl_end(r->tbl);
1145
1146         r->tbl = NULL;
1147         return(ROFF_IGN);
1148 }
1149
1150 /* ARGSUSED */
1151 static enum rofferr
1152 roff_T_(ROFF_ARGS)
1153 {
1154
1155         if (NULL == r->tbl)
1156                 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1157         else
1158                 tbl_restart(ppos, ln, r->tbl);
1159
1160         return(ROFF_IGN);
1161 }
1162
1163 /* ARGSUSED */
1164 static enum rofferr
1165 roff_EQ(ROFF_ARGS)
1166 {
1167         struct eqn_node *e;
1168
1169         assert(NULL == r->eqn);
1170         e = eqn_alloc(ppos, ln);
1171
1172         if (r->last_eqn)
1173                 r->last_eqn->next = e;
1174         else
1175                 r->first_eqn = r->last_eqn = e;
1176
1177         r->eqn = r->last_eqn = e;
1178         return(ROFF_IGN);
1179 }
1180
1181 /* ARGSUSED */
1182 static enum rofferr
1183 roff_EN(ROFF_ARGS)
1184 {
1185
1186         mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1187         return(ROFF_IGN);
1188 }
1189
1190 /* ARGSUSED */
1191 static enum rofferr
1192 roff_TS(ROFF_ARGS)
1193 {
1194         struct tbl_node *t;
1195
1196         if (r->tbl) {
1197                 mandoc_msg(MANDOCERR_SCOPEBROKEN, r->parse, ln, ppos, NULL);
1198                 tbl_end(r->tbl);
1199         }
1200
1201         t = tbl_alloc(ppos, ln, r->parse);
1202
1203         if (r->last_tbl)
1204                 r->last_tbl->next = t;
1205         else
1206                 r->first_tbl = r->last_tbl = t;
1207
1208         r->tbl = r->last_tbl = t;
1209         return(ROFF_IGN);
1210 }
1211
1212 /* ARGSUSED */
1213 static enum rofferr
1214 roff_so(ROFF_ARGS)
1215 {
1216         char *name;
1217
1218         mandoc_msg(MANDOCERR_SO, r->parse, ln, ppos, NULL);
1219
1220         /*
1221          * Handle `so'.  Be EXTREMELY careful, as we shouldn't be
1222          * opening anything that's not in our cwd or anything beneath
1223          * it.  Thus, explicitly disallow traversing up the file-system
1224          * or using absolute paths.
1225          */
1226
1227         name = *bufp + pos;
1228         if ('/' == *name || strstr(name, "../") || strstr(name, "/..")) {
1229                 mandoc_msg(MANDOCERR_SOPATH, r->parse, ln, pos, NULL);
1230                 return(ROFF_ERR);
1231         }
1232
1233         *offs = pos;
1234         return(ROFF_SO);
1235 }
1236
1237 /* ARGSUSED */
1238 static enum rofferr
1239 roff_userdef(ROFF_ARGS)
1240 {
1241         const char       *arg[9];
1242         char             *cp, *n1, *n2;
1243         int               i;
1244
1245         /*
1246          * Collect pointers to macro argument strings
1247          * and null-terminate them.
1248          */
1249         cp = *bufp + pos;
1250         for (i = 0; i < 9; i++)
1251                 arg[i] = '\0' == *cp ? "" :
1252                     mandoc_getarg(r->parse, &cp, ln, &pos);
1253
1254         /*
1255          * Expand macro arguments.
1256          */
1257         *szp = 0;
1258         n1 = cp = mandoc_strdup(r->current_string);
1259         while (NULL != (cp = strstr(cp, "\\$"))) {
1260                 i = cp[2] - '1';
1261                 if (0 > i || 8 < i) {
1262                         /* Not an argument invocation. */
1263                         cp += 2;
1264                         continue;
1265                 }
1266
1267                 *szp = strlen(n1) - 3 + strlen(arg[i]) + 1;
1268                 n2 = mandoc_malloc(*szp);
1269
1270                 strlcpy(n2, n1, (size_t)(cp - n1 + 1));
1271                 strlcat(n2, arg[i], *szp);
1272                 strlcat(n2, cp + 3, *szp);
1273
1274                 cp = n2 + (cp - n1);
1275                 free(n1);
1276                 n1 = n2;
1277         }
1278
1279         /*
1280          * Replace the macro invocation
1281          * by the expanded macro.
1282          */
1283         free(*bufp);
1284         *bufp = n1;
1285         if (0 == *szp)
1286                 *szp = strlen(*bufp) + 1;
1287
1288         return(*szp > 1 && '\n' == (*bufp)[(int)*szp - 2] ?
1289            ROFF_REPARSE : ROFF_APPEND);
1290 }
1291
1292 static char *
1293 roff_getname(struct roff *r, char **cpp, int ln, int pos)
1294 {
1295         char     *name, *cp;
1296
1297         name = *cpp;
1298         if ('\0' == *name)
1299                 return(name);
1300
1301         /* Read until end of name. */
1302         for (cp = name; '\0' != *cp && ' ' != *cp; cp++) {
1303                 if ('\\' != *cp)
1304                         continue;
1305                 cp++;
1306                 if ('\\' == *cp)
1307                         continue;
1308                 mandoc_msg(MANDOCERR_NAMESC, r->parse, ln, pos, NULL);
1309                 *cp = '\0';
1310                 name = cp;
1311         }
1312
1313         /* Nil-terminate name. */
1314         if ('\0' != *cp)
1315                 *(cp++) = '\0';
1316
1317         /* Read past spaces. */
1318         while (' ' == *cp)
1319                 cp++;
1320
1321         *cpp = cp;
1322         return(name);
1323 }
1324
1325 /*
1326  * Store *string into the user-defined string called *name.
1327  * In multiline mode, append to an existing entry and append '\n';
1328  * else replace the existing entry, if there is one.
1329  * To clear an existing entry, call with (*r, *name, NULL, 0).
1330  */
1331 static void
1332 roff_setstr(struct roff *r, const char *name, const char *string,
1333         int multiline)
1334 {
1335         struct roffstr   *n;
1336         char             *c;
1337         size_t            oldch, newch;
1338
1339         /* Search for an existing string with the same name. */
1340         n = r->first_string;
1341         while (n && strcmp(name, n->name))
1342                 n = n->next;
1343
1344         if (NULL == n) {
1345                 /* Create a new string table entry. */
1346                 n = mandoc_malloc(sizeof(struct roffstr));
1347                 n->name = mandoc_strdup(name);
1348                 n->string = NULL;
1349                 n->next = r->first_string;
1350                 r->first_string = n;
1351         } else if (0 == multiline) {
1352                 /* In multiline mode, append; else replace. */
1353                 free(n->string);
1354                 n->string = NULL;
1355         }
1356
1357         if (NULL == string)
1358                 return;
1359
1360         /*
1361          * One additional byte for the '\n' in multiline mode,
1362          * and one for the terminating '\0'.
1363          */
1364         newch = strlen(string) + (multiline ? 2u : 1u);
1365         if (NULL == n->string) {
1366                 n->string = mandoc_malloc(newch);
1367                 *n->string = '\0';
1368                 oldch = 0;
1369         } else {
1370                 oldch = strlen(n->string);
1371                 n->string = mandoc_realloc(n->string, oldch + newch);
1372         }
1373
1374         /* Skip existing content in the destination buffer. */
1375         c = n->string + (int)oldch;
1376
1377         /* Append new content to the destination buffer. */
1378         while (*string) {
1379                 /*
1380                  * Rudimentary roff copy mode:
1381                  * Handle escaped backslashes.
1382                  */
1383                 if ('\\' == *string && '\\' == *(string + 1))
1384                         string++;
1385                 *c++ = *string++;
1386         }
1387
1388         /* Append terminating bytes. */
1389         if (multiline)
1390                 *c++ = '\n';
1391         *c = '\0';
1392 }
1393
1394 static const char *
1395 roff_getstrn(const struct roff *r, const char *name, size_t len)
1396 {
1397         const struct roffstr *n;
1398
1399         n = r->first_string;
1400         while (n && (strncmp(name, n->name, len) || '\0' != n->name[(int)len]))
1401                 n = n->next;
1402
1403         return(n ? n->string : NULL);
1404 }
1405
1406 static void
1407 roff_freestr(struct roff *r)
1408 {
1409         struct roffstr   *n, *nn;
1410
1411         for (n = r->first_string; n; n = nn) {
1412                 free(n->name);
1413                 free(n->string);
1414                 nn = n->next;
1415                 free(n);
1416         }
1417
1418         r->first_string = NULL;
1419 }
1420
1421 const struct tbl_span *
1422 roff_span(const struct roff *r)
1423 {
1424         
1425         return(r->tbl ? tbl_span(r->tbl) : NULL);
1426 }
1427
1428 const struct eqn *
1429 roff_eqn(const struct roff *r)
1430 {
1431         
1432         return(r->last_eqn ? &r->last_eqn->eqn : NULL);
1433 }