]> git.cameronkatri.com Git - mandoc.git/blob - roff.c
"sys/param.h is for kernel interface programs.
[mandoc.git] / roff.c
1 /* $Id: roff.c,v 1.99 2010/08/24 12:48:43 kristaps Exp $ */
2 /*
3 * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2010 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 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.
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 "roff.h"
32 #include "libmandoc.h"
33
34 #define RSTACK_MAX 128
35
36 #define ROFF_CTL(c) \
37 ('.' == (c) || '\'' == (c))
38
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
47 enum rofft {
48 ROFF_am,
49 ROFF_ami,
50 ROFF_am1,
51 ROFF_de,
52 ROFF_dei,
53 ROFF_de1,
54 ROFF_ds,
55 ROFF_el,
56 ROFF_ie,
57 ROFF_if,
58 ROFF_ig,
59 ROFF_rm,
60 ROFF_tr,
61 ROFF_cblock,
62 ROFF_ccond,
63 ROFF_nr,
64 ROFF_MAX
65 };
66
67 enum roffrule {
68 ROFFRULE_ALLOW,
69 ROFFRULE_DENY
70 };
71
72
73 struct roffstr {
74 char *name; /* key of symbol */
75 char *string; /* current value */
76 struct roffstr *next; /* next in list */
77 };
78
79 struct roff {
80 struct roffnode *last; /* leaf of stack */
81 mandocmsg msg; /* err/warn/fatal messages */
82 void *data; /* privdata for messages */
83 enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */
84 int rstackpos; /* position in rstack */
85 struct regset *regs; /* read/writable registers */
86 struct roffstr *first_string;
87 };
88
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 */
94 char *end; /* end-rules: custom token */
95 int endspan; /* end-rules: next-line or infty */
96 enum roffrule rule; /* current evaluation rule */
97 };
98
99 #define ROFF_ARGS struct roff *r, /* parse ctx */ \
100 enum rofft tok, /* tok of macro */ \
101 char **bufp, /* input buffer */ \
102 size_t *szp, /* size of input buffer */ \
103 int ln, /* parse line */ \
104 int ppos, /* original pos in buffer */ \
105 int pos, /* current pos in buffer */ \
106 int *offs /* reset offset of buffer data */
107
108 typedef enum rofferr (*roffproc)(ROFF_ARGS);
109
110 struct roffmac {
111 const char *name; /* macro name */
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 */
117 struct roffmac *next;
118 };
119
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);
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);
128 static enum rofferr roff_ds(ROFF_ARGS);
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);
133 static enum rofferr roff_line(ROFF_ARGS);
134 static enum rofferr roff_nr(ROFF_ARGS);
135 static int roff_res(struct roff *,
136 char **, size_t *, int);
137 static void roff_setstr(struct roff *,
138 const char *, const char *);
139 static char *roff_strdup(const char *);
140
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 },
156 { "ds", roff_ds, NULL, NULL, 0, NULL },
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 },
165 { "nr", roff_nr, NULL, NULL, 0, NULL },
166 };
167
168 static void roff_free1(struct roff *);
169 static enum rofft roff_hash_find(const char *);
170 static void roff_hash_init(void);
171 static void roffnode_cleanscope(struct roff *);
172 static void roffnode_push(struct roff *,
173 enum rofft, int, int);
174 static void roffnode_pop(struct roff *);
175 static enum rofft roff_parse(const char *, int *);
176 static int roff_parse_nat(const char *, unsigned int *);
177
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
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 {
210 int buc;
211 struct roffmac *n;
212
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));
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
244 assert(r->last);
245 p = r->last;
246
247 if (ROFF_el == p->tok)
248 if (r->rstackpos > -1)
249 r->rstackpos--;
250
251 r->last = r->last->parent;
252 if (p->end)
253 free(p->end);
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 */
262 static void
263 roffnode_push(struct roff *r, enum rofft tok, int line, int col)
264 {
265 struct roffnode *p;
266
267 p = mandoc_calloc(1, sizeof(struct roffnode));
268 p->tok = tok;
269 p->parent = r->last;
270 p->line = line;
271 p->col = col;
272 p->rule = p->parent ? p->parent->rule : ROFFRULE_DENY;
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);
284 roff_freestr(r);
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 *
306 roff_alloc(struct regset *regs, void *data, const mandocmsg msg)
307 {
308 struct roff *r;
309
310 r = mandoc_calloc(1, sizeof(struct roff));
311 r->regs = regs;
312 r->msg = msg;
313 r->data = data;
314 r->rstackpos = -1;
315
316 roff_hash_init();
317 return(r);
318 }
319
320
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
327 roff_res(struct roff *r, char **bufp, size_t *szp, int pos)
328 {
329 const char *cp, *cpp, *st, *res;
330 int i, maxl;
331 size_t nsz;
332 char *n;
333
334 /* LINTED */
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
389 enum rofferr
390 roff_parseln(struct roff *r, int ln, char **bufp,
391 size_t *szp, int pos, int *offs)
392 {
393 enum rofft t;
394 int ppos;
395
396 /*
397 * Run the reserved-word filter only if we have some reserved
398 * words to fill in.
399 */
400
401 if (r->first_string && ! roff_res(r, bufp, szp, pos))
402 return(ROFF_RERUN);
403
404 /*
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 */
409
410 if (r->last && ! ROFF_CTL((*bufp)[pos])) {
411 t = r->last->tok;
412 assert(roffs[t].text);
413 ROFF_DEBUG("roff: intercept scoped text: %s, [%s]\n",
414 roffs[t].name, &(*bufp)[pos]);
415 return((*roffs[t].text)
416 (r, t, bufp, szp,
417 ln, pos, pos, offs));
418 } else if ( ! ROFF_CTL((*bufp)[pos]))
419 return(ROFF_CONT);
420
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 */
425
426 if (r->last) {
427 t = r->last->tok;
428 assert(roffs[t].sub);
429 ROFF_DEBUG("roff: intercept scoped context: %s\n",
430 roffs[t].name);
431 return((*roffs[t].sub)
432 (r, t, bufp, szp,
433 ln, pos, pos, offs));
434 }
435
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 */
441
442 ppos = pos;
443 if (ROFF_MAX == (t = roff_parse(*bufp, &pos)))
444 return(ROFF_CONT);
445
446 ROFF_DEBUG("roff: intercept new-scope: %s, [%s]\n",
447 roffs[t].name, &(*bufp)[pos]);
448 assert(roffs[t].proc);
449 return((*roffs[t].proc)
450 (r, t, bufp, szp,
451 ln, ppos, pos, offs));
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));
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
477 assert(ROFF_CTL(buf[*pos]));
478 (*pos)++;
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;
489 else if (' ' == buf[*pos] || (j && '\\' == buf[*pos]))
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
507 static int
508 roff_parse_nat(const char *buf, unsigned int *res)
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)) ||
519 (lval > INT_MAX || lval < 0))
520 return(0);
521
522 *res = (unsigned int)lval;
523 return(1);
524 }
525
526
527 /* ARGSUSED */
528 static enum rofferr
529 roff_cblock(ROFF_ARGS)
530 {
531
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
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 }
542
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:
559 if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL))
560 return(ROFF_ERR);
561 return(ROFF_IGN);
562 }
563
564 if ((*bufp)[pos])
565 if ( ! (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL))
566 return(ROFF_ERR);
567
568 roffnode_pop(r);
569 roffnode_cleanscope(r);
570 return(ROFF_IGN);
571
572 }
573
574
575 static void
576 roffnode_cleanscope(struct roff *r)
577 {
578
579 while (r->last) {
580 if (--r->last->endspan < 0)
581 break;
582 roffnode_pop(r);
583 }
584 }
585
586
587 /* ARGSUSED */
588 static enum rofferr
589 roff_ccond(ROFF_ARGS)
590 {
591
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
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:
606 if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL))
607 return(ROFF_ERR);
608 return(ROFF_IGN);
609 }
610
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
621 roffnode_pop(r);
622 roffnode_cleanscope(r);
623 return(ROFF_IGN);
624 }
625
626
627 /* ARGSUSED */
628 static enum rofferr
629 roff_block(ROFF_ARGS)
630 {
631 int sv;
632 size_t sz;
633
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
645 roffnode_push(r, tok, ln, ppos);
646
647 if ('\0' == (*bufp)[pos])
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
664 if (1 == sz && '.' == (*bufp)[sv])
665 return(ROFF_IGN);
666
667 r->last->end = mandoc_malloc(sz + 1);
668
669 memcpy(r->last->end, *bufp + sv, sz);
670 r->last->end[(int)sz] = '\0';
671
672 if ((*bufp)[pos])
673 if ( ! (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL))
674 return(ROFF_ERR);
675
676 return(ROFF_IGN);
677 }
678
679
680 /* ARGSUSED */
681 static enum rofferr
682 roff_block_sub(ROFF_ARGS)
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);
731 return((*roffs[t].proc)(r, t, bufp, szp,
732 ln, ppos, pos, offs));
733 }
734
735
736 /* ARGSUSED */
737 static enum rofferr
738 roff_block_text(ROFF_ARGS)
739 {
740
741 return(ROFF_IGN);
742 }
743
744
745 /* ARGSUSED */
746 static enum rofferr
747 roff_cond_sub(ROFF_ARGS)
748 {
749 enum rofft t;
750 enum roffrule rr;
751 struct roffnode *l;
752
753 ppos = pos;
754 rr = r->last->rule;
755
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);
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);
781 return((*roffs[t].proc)(r, t, bufp, szp,
782 ln, ppos, pos, offs));
783 }
784
785
786 /* ARGSUSED */
787 static enum rofferr
788 roff_cond_text(ROFF_ARGS)
789 {
790 char *ep, *st;
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 */
799
800 st = &(*bufp)[pos];
801 if (NULL == (ep = strstr(st, "\\}"))) {
802 roffnode_cleanscope(r);
803 return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
804 }
805
806 if (ep == st || (ep > st && '\\' != *(ep - 1)))
807 roffnode_pop(r);
808
809 roffnode_cleanscope(r);
810 return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
811 }
812
813
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
839 /* ARGSUSED */
840 static enum rofferr
841 roff_line(ROFF_ARGS)
842 {
843
844 return(ROFF_IGN);
845 }
846
847
848 /* ARGSUSED */
849 static enum rofferr
850 roff_cond(ROFF_ARGS)
851 {
852 int sv;
853 enum roffrule rule;
854
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 }
861
862 /* First, evaluate the conditional. */
863
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);
875
876 sv = pos;
877
878 while (' ' == (*bufp)[pos])
879 pos++;
880
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 */
887
888 if ('\0' == (*bufp)[pos] && sv != pos) {
889 if ((*r->msg)(MANDOCERR_NOARGS, r->data, ln, ppos, NULL))
890 return(ROFF_IGN);
891 return(ROFF_ERR);
892 }
893
894 roffnode_push(r, tok, ln, ppos);
895
896 r->last->rule = rule;
897
898 ROFF_DEBUG("roff: cond: %s -> %s\n", roffs[tok].name,
899 ROFFRULE_ALLOW == rule ? "allow" : "deny");
900
901 if (ROFF_ie == tok) {
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 }
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) {
916 r->last->rule = ROFFRULE_DENY;
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 */
926
927 r->last->endspan = 1;
928
929 if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) {
930 r->last->endspan = -1;
931 pos += 2;
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);
937
938 /*
939 * If there are no arguments on the line, the next-line scope is
940 * assumed.
941 */
942
943 if ('\0' == (*bufp)[pos])
944 return(ROFF_IGN);
945
946 /* Otherwise re-run the roff parser after recalculating. */
947
948 *offs = pos;
949 return(ROFF_RERUN);
950 }
951
952
953 /* ARGSUSED */
954 static enum rofferr
955 roff_ds(ROFF_ARGS)
956 {
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 */
968
969 name = *bufp + pos;
970 if ('\0' == *name)
971 return(ROFF_IGN);
972
973 string = name;
974 /* Read until end of name. */
975 while (*string && ' ' != *string)
976 string++;
977
978 /* Nil-terminate name. */
979 if (*string)
980 *(string++) = '\0';
981
982 /* Read past spaces. */
983 while (*string && ' ' == *string)
984 string++;
985
986 /* Read passed initial double-quote. */
987 if (*string && '"' == *string)
988 string++;
989
990 /* The rest is the value. */
991 roff_setstr(r, name, string);
992 return(ROFF_IGN);
993 }
994
995
996 /* ARGSUSED */
997 static enum rofferr
998 roff_nr(ROFF_ARGS)
999 {
1000 const char *key, *val;
1001 struct reg *rg;
1002
1003 key = &(*bufp)[pos];
1004 rg = r->regs->regs;
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")) {
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;
1029
1030 ROFF_DEBUG("roff: register nS: %u\n",
1031 rg[(int)REG_nS].v.u);
1032 } else
1033 ROFF_DEBUG("roff: ignoring register: %s\n", key);
1034
1035 return(ROFF_IGN);
1036 }
1037
1038
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
1060 static void
1061 roff_setstr(struct roff *r, const char *name, const char *string)
1062 {
1063 struct roffstr *n;
1064 char *namecopy;
1065
1066 n = r->first_string;
1067 while (n && strcmp(name, n->name))
1068 n = n->next;
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
1077 free(n->string);
1078
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);
1082 }
1083
1084
1085 static const char *
1086 roff_getstrn(const struct roff *r, const char *name, size_t len)
1087 {
1088 const struct roffstr *n;
1089
1090 n = r->first_string;
1091 while (n && (strncmp(name, n->name, len) || '\0' != n->name[(int)len]))
1092 n = n->next;
1093
1094 return(n ? n->string : NULL);
1095 }
1096
1097
1098 static void
1099 roff_freestr(struct roff *r)
1100 {
1101 struct roffstr *n, *nn;
1102
1103 for (n = r->first_string; n; n = nn) {
1104 free(n->name);
1105 free(n->string);
1106 nn = n->next;
1107 free(n);
1108 }
1109
1110 r->first_string = NULL;
1111 }