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