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