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