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