]> git.cameronkatri.com Git - mandoc.git/blob - roff.c
a644bc851c5eee4f15c6e57fa2f2fb51db886bbe
[mandoc.git] / roff.c
1 /* $Id: roff.c,v 1.92 2010/07/03 16:02:12 schwarze Exp $ */
2 /*
3 * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include <assert.h>
22 #include <errno.h>
23 #include <ctype.h>
24 #include <limits.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdio.h>
28
29 #include "mandoc.h"
30 #include "regs.h"
31 #include "roff.h"
32
33 #define RSTACK_MAX 128
34
35 #define ROFF_CTL(c) \
36 ('.' == (c) || '\'' == (c))
37
38 #if 1
39 #define ROFF_DEBUG(fmt, args...) \
40 do { /* Nothing. */ } while (/*CONSTCOND*/ 0)
41 #else
42 #define ROFF_DEBUG(fmt, args...) \
43 do { fprintf(stderr, fmt , ##args); } while (/*CONSTCOND*/ 0)
44 #endif
45
46 enum rofft {
47 ROFF_am,
48 ROFF_ami,
49 ROFF_am1,
50 ROFF_de,
51 ROFF_dei,
52 ROFF_de1,
53 ROFF_ds,
54 ROFF_el,
55 ROFF_ie,
56 ROFF_if,
57 ROFF_ig,
58 ROFF_rm,
59 ROFF_tr,
60 ROFF_cblock,
61 ROFF_ccond,
62 ROFF_nr,
63 ROFF_MAX
64 };
65
66 enum roffrule {
67 ROFFRULE_ALLOW,
68 ROFFRULE_DENY
69 };
70
71 struct roff {
72 struct roffnode *last; /* leaf of stack */
73 mandocmsg msg; /* err/warn/fatal messages */
74 void *data; /* privdata for messages */
75 enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */
76 int rstackpos; /* position in rstack */
77 struct regset *regs; /* read/writable registers */
78 };
79
80 struct roffnode {
81 enum rofft tok; /* type of node */
82 struct roffnode *parent; /* up one in stack */
83 int line; /* parse line */
84 int col; /* parse col */
85 char *end; /* end-rules: custom token */
86 int endspan; /* end-rules: next-line or infty */
87 enum roffrule rule; /* current evaluation rule */
88 };
89
90 #define ROFF_ARGS struct roff *r, /* parse ctx */ \
91 enum rofft tok, /* tok of macro */ \
92 char **bufp, /* input buffer */ \
93 size_t *szp, /* size of input buffer */ \
94 int ln, /* parse line */ \
95 int ppos, /* original pos in buffer */ \
96 int pos, /* current pos in buffer */ \
97 int *offs /* reset offset of buffer data */
98
99 typedef enum rofferr (*roffproc)(ROFF_ARGS);
100
101 struct roffmac {
102 const char *name; /* macro name */
103 roffproc proc; /* process new macro */
104 roffproc text; /* process as child text of macro */
105 roffproc sub; /* process as child of macro */
106 int flags;
107 #define ROFFMAC_STRUCT (1 << 0) /* always interpret */
108 struct roffmac *next;
109 };
110
111 struct roffstr {
112 char *name;
113 char *string;
114 struct roffstr *next;
115 } *first_string;
116
117 static enum rofferr roff_block(ROFF_ARGS);
118 static enum rofferr roff_block_text(ROFF_ARGS);
119 static enum rofferr roff_block_sub(ROFF_ARGS);
120 static enum rofferr roff_cblock(ROFF_ARGS);
121 static enum rofferr roff_ccond(ROFF_ARGS);
122 static enum rofferr roff_cond(ROFF_ARGS);
123 static enum rofferr roff_cond_text(ROFF_ARGS);
124 static enum rofferr roff_cond_sub(ROFF_ARGS);
125 static enum rofferr roff_ds(ROFF_ARGS);
126 static enum rofferr roff_line(ROFF_ARGS);
127 static enum rofferr roff_nr(ROFF_ARGS);
128 static enum roffrule roff_evalcond(const char *, int *);
129
130 /* See roff_hash_find() */
131
132 #define ASCII_HI 126
133 #define ASCII_LO 33
134 #define HASHWIDTH (ASCII_HI - ASCII_LO + 1)
135
136 static struct roffmac *hash[HASHWIDTH];
137
138 static struct roffmac roffs[ROFF_MAX] = {
139 { "am", roff_block, roff_block_text, roff_block_sub, 0, NULL },
140 { "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },
141 { "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
142 { "de", roff_block, roff_block_text, roff_block_sub, 0, NULL },
143 { "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },
144 { "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
145 { "ds", roff_ds, NULL, NULL, 0, NULL },
146 { "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
147 { "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
148 { "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
149 { "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL },
150 { "rm", roff_line, NULL, NULL, 0, NULL },
151 { "tr", roff_line, NULL, NULL, 0, NULL },
152 { ".", roff_cblock, NULL, NULL, 0, NULL },
153 { "\\}", roff_ccond, NULL, NULL, 0, NULL },
154 { "nr", roff_nr, NULL, NULL, 0, NULL },
155 };
156
157 static void roff_free1(struct roff *);
158 static enum rofft roff_hash_find(const char *);
159 static void roff_hash_init(void);
160 static void roffnode_cleanscope(struct roff *);
161 static int roffnode_push(struct roff *,
162 enum rofft, int, int);
163 static void roffnode_pop(struct roff *);
164 static enum rofft roff_parse(const char *, int *);
165 static int roff_parse_nat(const char *, unsigned int *);
166
167 /* See roff_hash_find() */
168 #define ROFF_HASH(p) (p[0] - ASCII_LO)
169
170 static void
171 roff_hash_init(void)
172 {
173 struct roffmac *n;
174 int buc, i;
175
176 for (i = 0; i < (int)ROFF_MAX; i++) {
177 assert(roffs[i].name[0] >= ASCII_LO);
178 assert(roffs[i].name[0] <= ASCII_HI);
179
180 buc = ROFF_HASH(roffs[i].name);
181
182 if (NULL != (n = hash[buc])) {
183 for ( ; n->next; n = n->next)
184 /* Do nothing. */ ;
185 n->next = &roffs[i];
186 } else
187 hash[buc] = &roffs[i];
188 }
189 }
190
191
192 /*
193 * Look up a roff token by its name. Returns ROFF_MAX if no macro by
194 * the nil-terminated string name could be found.
195 */
196 static enum rofft
197 roff_hash_find(const char *p)
198 {
199 int buc;
200 struct roffmac *n;
201
202 /*
203 * libroff has an extremely simple hashtable, for the time
204 * being, which simply keys on the first character, which must
205 * be printable, then walks a chain. It works well enough until
206 * optimised.
207 */
208
209 if (p[0] < ASCII_LO || p[0] > ASCII_HI)
210 return(ROFF_MAX);
211
212 buc = ROFF_HASH(p);
213
214 if (NULL == (n = hash[buc]))
215 return(ROFF_MAX);
216 for ( ; n; n = n->next)
217 if (0 == strcmp(n->name, p))
218 return((enum rofft)(n - roffs));
219
220 return(ROFF_MAX);
221 }
222
223
224 /*
225 * Pop the current node off of the stack of roff instructions currently
226 * pending.
227 */
228 static void
229 roffnode_pop(struct roff *r)
230 {
231 struct roffnode *p;
232
233 assert(r->last);
234 p = r->last;
235
236 if (ROFF_el == p->tok)
237 if (r->rstackpos > -1)
238 r->rstackpos--;
239
240 r->last = r->last->parent;
241 if (p->end)
242 free(p->end);
243 free(p);
244 }
245
246
247 /*
248 * Push a roff node onto the instruction stack. This must later be
249 * removed with roffnode_pop().
250 */
251 static int
252 roffnode_push(struct roff *r, enum rofft tok, int line, int col)
253 {
254 struct roffnode *p;
255
256 if (NULL == (p = calloc(1, sizeof(struct roffnode)))) {
257 (*r->msg)(MANDOCERR_MEM, r->data, line, col, NULL);
258 return(0);
259 }
260
261 p->tok = tok;
262 p->parent = r->last;
263 p->line = line;
264 p->col = col;
265 p->rule = p->parent ? p->parent->rule : ROFFRULE_DENY;
266
267 r->last = p;
268 return(1);
269 }
270
271
272 static void
273 roff_free1(struct roff *r)
274 {
275
276 while (r->last)
277 roffnode_pop(r);
278 roff_freestr();
279 }
280
281
282 void
283 roff_reset(struct roff *r)
284 {
285
286 roff_free1(r);
287 }
288
289
290 void
291 roff_free(struct roff *r)
292 {
293
294 roff_free1(r);
295 free(r);
296 }
297
298
299 struct roff *
300 roff_alloc(struct regset *regs, const mandocmsg msg, void *data)
301 {
302 struct roff *r;
303
304 if (NULL == (r = calloc(1, sizeof(struct roff)))) {
305 (*msg)(MANDOCERR_MEM, data, 0, 0, NULL);
306 return(0);
307 }
308
309 r->regs = regs;
310 r->msg = msg;
311 r->data = data;
312 r->rstackpos = -1;
313
314 roff_hash_init();
315 return(r);
316 }
317
318
319 enum rofferr
320 roff_parseln(struct roff *r, int ln, char **bufp,
321 size_t *szp, int pos, int *offs)
322 {
323 enum rofft t;
324 int ppos;
325
326 /*
327 * First, if a scope is open and we're not a macro, pass the
328 * text through the macro's filter. If a scope isn't open and
329 * we're not a macro, just let it through.
330 */
331
332 if (r->last && ! ROFF_CTL((*bufp)[pos])) {
333 t = r->last->tok;
334 assert(roffs[t].text);
335 ROFF_DEBUG("roff: intercept scoped text: %s, [%s]\n",
336 roffs[t].name, &(*bufp)[pos]);
337 return((*roffs[t].text)
338 (r, t, bufp, szp,
339 ln, pos, pos, offs));
340 } else if ( ! ROFF_CTL((*bufp)[pos])) {
341 ROFF_DEBUG("roff: pass non-scoped text: [%s]\n",
342 &(*bufp)[pos]);
343 return(ROFF_CONT);
344 }
345
346 /*
347 * If a scope is open, go to the child handler for that macro,
348 * as it may want to preprocess before doing anything with it.
349 */
350
351 if (r->last) {
352 t = r->last->tok;
353 assert(roffs[t].sub);
354 ROFF_DEBUG("roff: intercept scoped context: %s\n",
355 roffs[t].name);
356 return((*roffs[t].sub)
357 (r, t, bufp, szp,
358 ln, pos, pos, offs));
359 }
360
361 /*
362 * Lastly, as we've no scope open, try to look up and execute
363 * the new macro. If no macro is found, simply return and let
364 * the compilers handle it.
365 */
366
367 ppos = pos;
368 if (ROFF_MAX == (t = roff_parse(*bufp, &pos))) {
369 ROFF_DEBUG("roff: pass non-scoped non-macro: [%s]\n",
370 &(*bufp)[pos]);
371 return(ROFF_CONT);
372 }
373
374 ROFF_DEBUG("roff: intercept new-scope: %s, [%s]\n",
375 roffs[t].name, &(*bufp)[pos]);
376 assert(roffs[t].proc);
377 return((*roffs[t].proc)
378 (r, t, bufp, szp,
379 ln, ppos, pos, offs));
380 }
381
382
383 int
384 roff_endparse(struct roff *r)
385 {
386
387 if (NULL == r->last)
388 return(1);
389 return((*r->msg)(MANDOCERR_SCOPEEXIT, r->data, r->last->line,
390 r->last->col, NULL));
391 }
392
393
394 /*
395 * Parse a roff node's type from the input buffer. This must be in the
396 * form of ".foo xxx" in the usual way.
397 */
398 static enum rofft
399 roff_parse(const char *buf, int *pos)
400 {
401 int j;
402 char mac[5];
403 enum rofft t;
404
405 assert(ROFF_CTL(buf[*pos]));
406 (*pos)++;
407
408 while (buf[*pos] && (' ' == buf[*pos] || '\t' == buf[*pos]))
409 (*pos)++;
410
411 if ('\0' == buf[*pos])
412 return(ROFF_MAX);
413
414 for (j = 0; j < 4; j++, (*pos)++)
415 if ('\0' == (mac[j] = buf[*pos]))
416 break;
417 else if (' ' == buf[*pos] || (j && '\\' == buf[*pos]))
418 break;
419
420 if (j == 4 || j < 1)
421 return(ROFF_MAX);
422
423 mac[j] = '\0';
424
425 if (ROFF_MAX == (t = roff_hash_find(mac)))
426 return(t);
427
428 while (buf[*pos] && ' ' == buf[*pos])
429 (*pos)++;
430
431 return(t);
432 }
433
434
435 static int
436 roff_parse_nat(const char *buf, unsigned int *res)
437 {
438 char *ep;
439 long lval;
440
441 errno = 0;
442 lval = strtol(buf, &ep, 10);
443 if (buf[0] == '\0' || *ep != '\0')
444 return(0);
445 if ((errno == ERANGE &&
446 (lval == LONG_MAX || lval == LONG_MIN)) ||
447 (lval > INT_MAX || lval < 0))
448 return(0);
449
450 *res = (unsigned int)lval;
451 return(1);
452 }
453
454
455 /* ARGSUSED */
456 static enum rofferr
457 roff_cblock(ROFF_ARGS)
458 {
459
460 /*
461 * A block-close `..' should only be invoked as a child of an
462 * ignore macro, otherwise raise a warning and just ignore it.
463 */
464
465 if (NULL == r->last) {
466 if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL))
467 return(ROFF_ERR);
468 return(ROFF_IGN);
469 }
470
471 switch (r->last->tok) {
472 case (ROFF_am):
473 /* FALLTHROUGH */
474 case (ROFF_ami):
475 /* FALLTHROUGH */
476 case (ROFF_am1):
477 /* FALLTHROUGH */
478 case (ROFF_de):
479 /* FALLTHROUGH */
480 case (ROFF_dei):
481 /* FALLTHROUGH */
482 case (ROFF_de1):
483 /* FALLTHROUGH */
484 case (ROFF_ig):
485 break;
486 default:
487 if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL))
488 return(ROFF_ERR);
489 return(ROFF_IGN);
490 }
491
492 if ((*bufp)[pos])
493 if ( ! (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL))
494 return(ROFF_ERR);
495
496 roffnode_pop(r);
497 roffnode_cleanscope(r);
498 return(ROFF_IGN);
499
500 }
501
502
503 static void
504 roffnode_cleanscope(struct roff *r)
505 {
506
507 while (r->last) {
508 if (--r->last->endspan < 0)
509 break;
510 roffnode_pop(r);
511 }
512 }
513
514
515 /* ARGSUSED */
516 static enum rofferr
517 roff_ccond(ROFF_ARGS)
518 {
519
520 if (NULL == r->last) {
521 if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL))
522 return(ROFF_ERR);
523 return(ROFF_IGN);
524 }
525
526 switch (r->last->tok) {
527 case (ROFF_el):
528 /* FALLTHROUGH */
529 case (ROFF_ie):
530 /* FALLTHROUGH */
531 case (ROFF_if):
532 break;
533 default:
534 if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL))
535 return(ROFF_ERR);
536 return(ROFF_IGN);
537 }
538
539 if (r->last->endspan > -1) {
540 if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL))
541 return(ROFF_ERR);
542 return(ROFF_IGN);
543 }
544
545 if ((*bufp)[pos])
546 if ( ! (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL))
547 return(ROFF_ERR);
548
549 roffnode_pop(r);
550 roffnode_cleanscope(r);
551 return(ROFF_IGN);
552 }
553
554
555 /* ARGSUSED */
556 static enum rofferr
557 roff_block(ROFF_ARGS)
558 {
559 int sv;
560 size_t sz;
561
562 if (ROFF_ig != tok && '\0' == (*bufp)[pos]) {
563 if ( ! (*r->msg)(MANDOCERR_NOARGS, r->data, ln, ppos, NULL))
564 return(ROFF_ERR);
565 return(ROFF_IGN);
566 } else if (ROFF_ig != tok) {
567 while ((*bufp)[pos] && ' ' != (*bufp)[pos])
568 pos++;
569 while (' ' == (*bufp)[pos])
570 pos++;
571 }
572
573 if ( ! roffnode_push(r, tok, ln, ppos))
574 return(ROFF_ERR);
575
576 if ('\0' == (*bufp)[pos])
577 return(ROFF_IGN);
578
579 sv = pos;
580 while ((*bufp)[pos] && ' ' != (*bufp)[pos] &&
581 '\t' != (*bufp)[pos])
582 pos++;
583
584 /*
585 * Note: groff does NOT like escape characters in the input.
586 * Instead of detecting this, we're just going to let it fly and
587 * to hell with it.
588 */
589
590 assert(pos > sv);
591 sz = (size_t)(pos - sv);
592
593 if (1 == sz && '.' == (*bufp)[sv])
594 return(ROFF_IGN);
595
596 r->last->end = malloc(sz + 1);
597
598 if (NULL == r->last->end) {
599 (*r->msg)(MANDOCERR_MEM, r->data, ln, pos, NULL);
600 return(ROFF_ERR);
601 }
602
603 memcpy(r->last->end, *bufp + sv, sz);
604 r->last->end[(int)sz] = '\0';
605
606 if ((*bufp)[pos])
607 if ( ! (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL))
608 return(ROFF_ERR);
609
610 return(ROFF_IGN);
611 }
612
613
614 /* ARGSUSED */
615 static enum rofferr
616 roff_block_sub(ROFF_ARGS)
617 {
618 enum rofft t;
619 int i, j;
620
621 /*
622 * First check whether a custom macro exists at this level. If
623 * it does, then check against it. This is some of groff's
624 * stranger behaviours. If we encountered a custom end-scope
625 * tag and that tag also happens to be a "real" macro, then we
626 * need to try interpreting it again as a real macro. If it's
627 * not, then return ignore. Else continue.
628 */
629
630 if (r->last->end) {
631 i = pos + 1;
632 while (' ' == (*bufp)[i] || '\t' == (*bufp)[i])
633 i++;
634
635 for (j = 0; r->last->end[j]; j++, i++)
636 if ((*bufp)[i] != r->last->end[j])
637 break;
638
639 if ('\0' == r->last->end[j] &&
640 ('\0' == (*bufp)[i] ||
641 ' ' == (*bufp)[i] ||
642 '\t' == (*bufp)[i])) {
643 roffnode_pop(r);
644 roffnode_cleanscope(r);
645
646 if (ROFF_MAX != roff_parse(*bufp, &pos))
647 return(ROFF_RERUN);
648 return(ROFF_IGN);
649 }
650 }
651
652 /*
653 * If we have no custom end-query or lookup failed, then try
654 * pulling it out of the hashtable.
655 */
656
657 ppos = pos;
658 t = roff_parse(*bufp, &pos);
659
660 /* If we're not a comment-end, then throw it away. */
661 if (ROFF_cblock != t)
662 return(ROFF_IGN);
663
664 assert(roffs[t].proc);
665 return((*roffs[t].proc)(r, t, bufp, szp,
666 ln, ppos, pos, offs));
667 }
668
669
670 /* ARGSUSED */
671 static enum rofferr
672 roff_block_text(ROFF_ARGS)
673 {
674
675 return(ROFF_IGN);
676 }
677
678
679 /* ARGSUSED */
680 static enum rofferr
681 roff_cond_sub(ROFF_ARGS)
682 {
683 enum rofft t;
684 enum roffrule rr;
685 struct roffnode *l;
686
687 ppos = pos;
688 rr = r->last->rule;
689
690 /*
691 * Clean out scope. If we've closed ourselves, then don't
692 * continue.
693 */
694
695 l = r->last;
696 roffnode_cleanscope(r);
697
698 if (l != r->last)
699 return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
700
701 if (ROFF_MAX == (t = roff_parse(*bufp, &pos)))
702 return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
703
704 /*
705 * A denied conditional must evaluate its children if and only
706 * if they're either structurally required (such as loops and
707 * conditionals) or a closing macro.
708 */
709 if (ROFFRULE_DENY == rr)
710 if ( ! (ROFFMAC_STRUCT & roffs[t].flags))
711 if (ROFF_ccond != t)
712 return(ROFF_IGN);
713
714 assert(roffs[t].proc);
715 return((*roffs[t].proc)(r, t, bufp, szp,
716 ln, ppos, pos, offs));
717 }
718
719
720 /* ARGSUSED */
721 static enum rofferr
722 roff_cond_text(ROFF_ARGS)
723 {
724 char *ep, *st;
725 enum roffrule rr;
726
727 rr = r->last->rule;
728
729 /*
730 * We display the value of the text if out current evaluation
731 * scope permits us to do so.
732 */
733
734 st = &(*bufp)[pos];
735 if (NULL == (ep = strstr(st, "\\}"))) {
736 roffnode_cleanscope(r);
737 return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
738 }
739
740 if (ep == st || (ep > st && '\\' != *(ep - 1)))
741 roffnode_pop(r);
742
743 roffnode_cleanscope(r);
744 return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
745 }
746
747
748 static enum roffrule
749 roff_evalcond(const char *v, int *pos)
750 {
751
752 switch (v[*pos]) {
753 case ('n'):
754 (*pos)++;
755 return(ROFFRULE_ALLOW);
756 case ('e'):
757 /* FALLTHROUGH */
758 case ('o'):
759 /* FALLTHROUGH */
760 case ('t'):
761 (*pos)++;
762 return(ROFFRULE_DENY);
763 default:
764 break;
765 }
766
767 while (v[*pos] && ' ' != v[*pos])
768 (*pos)++;
769 return(ROFFRULE_DENY);
770 }
771
772
773 /* ARGSUSED */
774 static enum rofferr
775 roff_line(ROFF_ARGS)
776 {
777
778 return(ROFF_IGN);
779 }
780
781
782 /* ARGSUSED */
783 static enum rofferr
784 roff_cond(ROFF_ARGS)
785 {
786 int sv;
787 enum roffrule rule;
788
789 /* Stack overflow! */
790
791 if (ROFF_ie == tok && r->rstackpos == RSTACK_MAX - 1) {
792 (*r->msg)(MANDOCERR_MEM, r->data, ln, ppos, NULL);
793 return(ROFF_ERR);
794 }
795
796 /* First, evaluate the conditional. */
797
798 if (ROFF_el == tok) {
799 /*
800 * An `.el' will get the value of the current rstack
801 * entry set in prior `ie' calls or defaults to DENY.
802 */
803 if (r->rstackpos < 0)
804 rule = ROFFRULE_DENY;
805 else
806 rule = r->rstack[r->rstackpos];
807 } else
808 rule = roff_evalcond(*bufp, &pos);
809
810 sv = pos;
811
812 while (' ' == (*bufp)[pos])
813 pos++;
814
815 /*
816 * Roff is weird. If we have just white-space after the
817 * conditional, it's considered the BODY and we exit without
818 * really doing anything. Warn about this. It's probably
819 * wrong.
820 */
821
822 if ('\0' == (*bufp)[pos] && sv != pos) {
823 if ((*r->msg)(MANDOCERR_NOARGS, r->data, ln, ppos, NULL))
824 return(ROFF_IGN);
825 return(ROFF_ERR);
826 }
827
828 if ( ! roffnode_push(r, tok, ln, ppos))
829 return(ROFF_ERR);
830
831 r->last->rule = rule;
832
833 ROFF_DEBUG("roff: cond: %s -> %s\n", roffs[tok].name,
834 ROFFRULE_ALLOW == rule ? "allow" : "deny");
835
836 if (ROFF_ie == tok) {
837 /*
838 * An if-else will put the NEGATION of the current
839 * evaluated conditional into the stack.
840 */
841 r->rstackpos++;
842 if (ROFFRULE_DENY == r->last->rule)
843 r->rstack[r->rstackpos] = ROFFRULE_ALLOW;
844 else
845 r->rstack[r->rstackpos] = ROFFRULE_DENY;
846 }
847
848 /* If the parent has false as its rule, then so do we. */
849
850 if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule) {
851 r->last->rule = ROFFRULE_DENY;
852 ROFF_DEBUG("roff: cond override: %s -> deny\n",
853 roffs[tok].name);
854 }
855
856 /*
857 * Determine scope. If we're invoked with "\{" trailing the
858 * conditional, then we're in a multiline scope. Else our scope
859 * expires on the next line.
860 */
861
862 r->last->endspan = 1;
863
864 if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) {
865 r->last->endspan = -1;
866 pos += 2;
867 ROFF_DEBUG("roff: cond-scope: %s, multi-line\n",
868 roffs[tok].name);
869 } else
870 ROFF_DEBUG("roff: cond-scope: %s, one-line\n",
871 roffs[tok].name);
872
873 /*
874 * If there are no arguments on the line, the next-line scope is
875 * assumed.
876 */
877
878 if ('\0' == (*bufp)[pos])
879 return(ROFF_IGN);
880
881 /* Otherwise re-run the roff parser after recalculating. */
882
883 *offs = pos;
884 return(ROFF_RERUN);
885 }
886
887
888 /* ARGSUSED */
889 static enum rofferr
890 roff_ds(ROFF_ARGS)
891 {
892 char *name, *string, *end;
893
894 name = *bufp + pos;
895 if ('\0' == *name)
896 return(ROFF_IGN);
897
898 string = name;
899 while (*string && ' ' != *string)
900 string++;
901 if (*string)
902 *(string++) = NULL;
903 if (*string && '"' == *string)
904 string++;
905 while (*string && ' ' == *string)
906 string++;
907 end = string;
908 while (*end)
909 end++;
910 if (string < end) {
911 end--;
912 if (*end == '"')
913 *end = '\0';
914 }
915
916 roff_setstr(name, string);
917 return(ROFF_IGN);
918 }
919
920
921 /* ARGSUSED */
922 static enum rofferr
923 roff_nr(ROFF_ARGS)
924 {
925 const char *key, *val;
926 struct reg *rg;
927
928 key = &(*bufp)[pos];
929 rg = r->regs->regs;
930
931 /* Parse register request. */
932 while ((*bufp)[pos] && ' ' != (*bufp)[pos])
933 pos++;
934
935 /*
936 * Set our nil terminator. Because this line is going to be
937 * ignored anyway, we can munge it as we please.
938 */
939 if ((*bufp)[pos])
940 (*bufp)[pos++] = '\0';
941
942 /* Skip whitespace to register token. */
943 while ((*bufp)[pos] && ' ' == (*bufp)[pos])
944 pos++;
945
946 val = &(*bufp)[pos];
947
948 /* Process register token. */
949
950 if (0 == strcmp(key, "nS")) {
951 rg[(int)REG_nS].set = 1;
952 if ( ! roff_parse_nat(val, &rg[(int)REG_nS].v.u))
953 rg[(int)REG_nS].v.u = 0;
954
955 ROFF_DEBUG("roff: register nS: %u\n",
956 rg[(int)REG_nS].v.u);
957 } else
958 ROFF_DEBUG("roff: ignoring register: %s\n", key);
959
960 return(ROFF_IGN);
961 }
962
963
964 char *
965 roff_setstr(const char *name, const char *string)
966 {
967 struct roffstr *n;
968 char *namecopy;
969
970 n = first_string;
971 while (n && strcmp(name, n->name))
972 n = n->next;
973 if (n) {
974 free(n->string);
975 } else {
976 if (NULL == (namecopy = strdup(name)))
977 return(NULL);
978 if (NULL == (n = malloc(sizeof(struct roffstr)))) {
979 free(n);
980 return(NULL);
981 }
982 n->name = namecopy;
983 n->next = first_string;
984 first_string = n;
985 }
986 if (string)
987 n->string = strdup(string);
988 else
989 n->string = NULL;
990 return(n->string);
991 }
992
993 char *
994 roff_getstr(const char *name)
995 {
996 struct roffstr *n;
997
998 n = first_string;
999 while (n && strcmp(name, n->name))
1000 n = n->next;
1001 if (n)
1002 return(n->string);
1003 else
1004 return(NULL);
1005 }
1006
1007 char *
1008 roff_getstrn(const char *name, size_t len)
1009 {
1010 struct roffstr *n;
1011
1012 n = first_string;
1013 while (n && (strncmp(name, n->name, len) || '\0' != n->name[len]))
1014 n = n->next;
1015 if (n)
1016 return(n->string);
1017 else
1018 return(NULL);
1019 }
1020
1021 void
1022 roff_freestr(void)
1023 {
1024 struct roffstr *n, *nn;
1025
1026 for (n = first_string; n; n = nn) {
1027 free(n->name);
1028 free(n->string);
1029 nn = n->next;
1030 free(n);
1031 }
1032 first_string = NULL;
1033 }