1 /* $Id: roff.c,v 1.172 2011/10/24 21:41:45 schwarze Exp $ */
2 /*
3 * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2010, 2011 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 AUTHORS DISCLAIM ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS 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 <ctype.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "mandoc.h"
28 #include "libroff.h"
29 #include "libmandoc.h"
30
31 /* Maximum number of nested if-else conditionals. */
32 #define RSTACK_MAX 128
33
34 /* Maximum number of string expansions per line, to break infinite loops. */
35 #define EXPAND_LIMIT 1000
36
37 enum rofft {
38 ROFF_ad,
39 ROFF_am,
40 ROFF_ami,
41 ROFF_am1,
42 ROFF_de,
43 ROFF_dei,
44 ROFF_de1,
45 ROFF_ds,
46 ROFF_el,
47 ROFF_hy,
48 ROFF_ie,
49 ROFF_if,
50 ROFF_ig,
51 ROFF_it,
52 ROFF_ne,
53 ROFF_nh,
54 ROFF_nr,
55 ROFF_ns,
56 ROFF_ps,
57 ROFF_rm,
58 ROFF_so,
59 ROFF_ta,
60 ROFF_tr,
61 ROFF_TS,
62 ROFF_TE,
63 ROFF_T_,
64 ROFF_EQ,
65 ROFF_EN,
66 ROFF_cblock,
67 ROFF_ccond,
68 ROFF_USERDEF,
69 ROFF_MAX
70 };
71
72 enum roffrule {
73 ROFFRULE_ALLOW,
74 ROFFRULE_DENY
75 };
76
77 /*
78 * A single register entity. If "set" is zero, the value of the
79 * register should be the default one, which is per-register.
80 * Registers are assumed to be unsigned ints for now.
81 */
82 struct reg {
83 int set; /* whether set or not */
84 unsigned int u; /* unsigned integer */
85 };
86
87 /*
88 * An incredibly-simple string buffer.
89 */
90 struct roffstr {
91 char *p; /* nil-terminated buffer */
92 size_t sz; /* saved strlen(p) */
93 };
94
95 /*
96 * A key-value roffstr pair as part of a singly-linked list.
97 */
98 struct roffkv {
99 struct roffstr key;
100 struct roffstr val;
101 struct roffkv *next; /* next in list */
102 };
103
104 struct roff {
105 struct mparse *parse; /* parse point */
106 struct roffnode *last; /* leaf of stack */
107 enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */
108 int rstackpos; /* position in rstack */
109 struct reg regs[REG__MAX];
110 struct roffkv *strtab; /* user-defined strings & macros */
111 struct roffkv *xmbtab; /* multi-byte trans table (`tr') */
112 struct roffstr *xtab; /* single-byte trans table (`tr') */
113 const char *current_string; /* value of last called user macro */
114 struct tbl_node *first_tbl; /* first table parsed */
115 struct tbl_node *last_tbl; /* last table parsed */
116 struct tbl_node *tbl; /* current table being parsed */
117 struct eqn_node *last_eqn; /* last equation parsed */
118 struct eqn_node *first_eqn; /* first equation parsed */
119 struct eqn_node *eqn; /* current equation being parsed */
120 };
121
122 struct roffnode {
123 enum rofft tok; /* type of node */
124 struct roffnode *parent; /* up one in stack */
125 int line; /* parse line */
126 int col; /* parse col */
127 char *name; /* node name, e.g. macro name */
128 char *end; /* end-rules: custom token */
129 int endspan; /* end-rules: next-line or infty */
152 };
153
154 struct predef {
155 const char *name; /* predefined input name */
156 const char *str; /* replacement symbol */
157 };
158
159 #define PREDEF(__name, __str) \
160 { (__name), (__str) },
161
162 static enum rofft roffhash_find(const char *, size_t);
163 static void roffhash_init(void);
164 static void roffnode_cleanscope(struct roff *);
165 static void roffnode_pop(struct roff *);
166 static void roffnode_push(struct roff *, enum rofft,
167 const char *, int, int);
168 static enum rofferr roff_block(ROFF_ARGS);
169 static enum rofferr roff_block_text(ROFF_ARGS);
170 static enum rofferr roff_block_sub(ROFF_ARGS);
171 static enum rofferr roff_cblock(ROFF_ARGS);
172 static enum rofferr roff_ccond(ROFF_ARGS);
173 static enum rofferr roff_cond(ROFF_ARGS);
174 static enum rofferr roff_cond_text(ROFF_ARGS);
175 static enum rofferr roff_cond_sub(ROFF_ARGS);
176 static enum rofferr roff_ds(ROFF_ARGS);
177 static enum roffrule roff_evalcond(const char *, int *);
178 static void roff_free1(struct roff *);
179 static void roff_freestr(struct roffkv *);
180 static char *roff_getname(struct roff *, char **, int, int);
181 static const char *roff_getstrn(const struct roff *,
182 const char *, size_t);
183 static enum rofferr roff_line_ignore(ROFF_ARGS);
184 static enum rofferr roff_nr(ROFF_ARGS);
185 static void roff_openeqn(struct roff *, const char *,
186 int, int, const char *);
187 static enum rofft roff_parse(struct roff *, const char *, int *);
188 static enum rofferr roff_parsetext(char *);
189 static enum rofferr roff_res(struct roff *,
190 char **, size_t *, int, int);
191 static enum rofferr roff_rm(ROFF_ARGS);
192 static void roff_setstr(struct roff *,
193 const char *, const char *, int);
194 static void roff_setstrn(struct roffkv **, const char *,
195 size_t, const char *, size_t, int);
196 static enum rofferr roff_so(ROFF_ARGS);
197 static enum rofferr roff_tr(ROFF_ARGS);
198 static enum rofferr roff_TE(ROFF_ARGS);
199 static enum rofferr roff_TS(ROFF_ARGS);
200 static enum rofferr roff_EQ(ROFF_ARGS);
201 static enum rofferr roff_EN(ROFF_ARGS);
202 static enum rofferr roff_T_(ROFF_ARGS);
203 static enum rofferr roff_userdef(ROFF_ARGS);
204
205 /* See roffhash_find() */
206
207 #define ASCII_HI 126
208 #define ASCII_LO 33
209 #define HASHWIDTH (ASCII_HI - ASCII_LO + 1)
210
211 static struct roffmac *hash[HASHWIDTH];
212
213 static struct roffmac roffs[ROFF_MAX] = {
214 { "ad", roff_line_ignore, NULL, NULL, 0, NULL },
215 { "am", roff_block, roff_block_text, roff_block_sub, 0, NULL },
216 { "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },
217 { "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
218 { "de", roff_block, roff_block_text, roff_block_sub, 0, NULL },
219 { "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },
220 { "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
221 { "ds", roff_ds, NULL, NULL, 0, NULL },
222 { "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
223 { "hy", roff_line_ignore, NULL, NULL, 0, NULL },
224 { "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
225 { "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
226 { "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL },
227 { "it", roff_line_ignore, NULL, NULL, 0, NULL },
228 { "ne", roff_line_ignore, NULL, NULL, 0, NULL },
229 { "nh", roff_line_ignore, NULL, NULL, 0, NULL },
230 { "nr", roff_nr, NULL, NULL, 0, NULL },
231 { "ns", roff_line_ignore, NULL, NULL, 0, NULL },
232 { "ps", roff_line_ignore, NULL, NULL, 0, NULL },
233 { "rm", roff_rm, NULL, NULL, 0, NULL },
234 { "so", roff_so, NULL, NULL, 0, NULL },
235 { "ta", roff_line_ignore, NULL, NULL, 0, NULL },
236 { "tr", roff_tr, NULL, NULL, 0, NULL },
237 { "TS", roff_TS, NULL, NULL, 0, NULL },
238 { "TE", roff_TE, NULL, NULL, 0, NULL },
239 { "T&", roff_T_, NULL, NULL, 0, NULL },
240 { "EQ", roff_EQ, NULL, NULL, 0, NULL },
241 { "EN", roff_EN, NULL, NULL, 0, NULL },
242 { ".", roff_cblock, NULL, NULL, 0, NULL },
243 { "\\}", roff_ccond, NULL, NULL, 0, NULL },
244 { NULL, roff_userdef, NULL, NULL, 0, NULL },
245 };
246
247 /* Array of injected predefined strings. */
248 #define PREDEFS_MAX 38
249 static const struct predef predefs[PREDEFS_MAX] = {
250 #include "predefs.in"
251 };
252
253 /* See roffhash_find() */
254 #define ROFF_HASH(p) (p[0] - ASCII_LO)
255
256 static void
257 roffhash_init(void)
258 {
259 struct roffmac *n;
260 int buc, i;
261
262 for (i = 0; i < (int)ROFF_USERDEF; i++) {
263 assert(roffs[i].name[0] >= ASCII_LO);
264 assert(roffs[i].name[0] <= ASCII_HI);
265
266 buc = ROFF_HASH(roffs[i].name);
267
268 if (NULL != (n = hash[buc])) {
269 for ( ; n->next; n = n->next)
270 /* Do nothing. */ ;
271 n->next = &roffs[i];
272 } else
273 hash[buc] = &roffs[i];
274 }
275 }
334 int line, int col)
335 {
336 struct roffnode *p;
337
338 p = mandoc_calloc(1, sizeof(struct roffnode));
339 p->tok = tok;
340 if (name)
341 p->name = mandoc_strdup(name);
342 p->parent = r->last;
343 p->line = line;
344 p->col = col;
345 p->rule = p->parent ? p->parent->rule : ROFFRULE_DENY;
346
347 r->last = p;
348 }
349
350
351 static void
352 roff_free1(struct roff *r)
353 {
354 struct tbl_node *t;
355 struct eqn_node *e;
356 int i;
357
358 while (NULL != (t = r->first_tbl)) {
359 r->first_tbl = t->next;
360 tbl_free(t);
361 }
362
363 r->first_tbl = r->last_tbl = r->tbl = NULL;
364
365 while (NULL != (e = r->first_eqn)) {
366 r->first_eqn = e->next;
367 eqn_free(e);
368 }
369
370 r->first_eqn = r->last_eqn = r->eqn = NULL;
371
372 while (r->last)
373 roffnode_pop(r);
374
375 roff_freestr(r->strtab);
376 roff_freestr(r->xmbtab);
377
378 r->strtab = r->xmbtab = NULL;
379
380 if (r->xtab)
381 for (i = 0; i < 128; i++)
382 free(r->xtab[i].p);
383
384 free(r->xtab);
385 r->xtab = NULL;
386 }
387
388 void
389 roff_reset(struct roff *r)
390 {
391 int i;
392
393 roff_free1(r);
394
395 memset(&r->regs, 0, sizeof(struct reg) * REG__MAX);
396
397 for (i = 0; i < PREDEFS_MAX; i++)
398 roff_setstr(r, predefs[i].name, predefs[i].str, 0);
399 }
400
401
402 void
403 roff_free(struct roff *r)
404 {
405
406 roff_free1(r);
407 free(r);
408 }
409
410
411 struct roff *
412 roff_alloc(struct mparse *parse)
413 {
414 struct roff *r;
415 int i;
416
417 r = mandoc_calloc(1, sizeof(struct roff));
418 r->parse = parse;
419 r->rstackpos = -1;
420
421 roffhash_init();
422
423 for (i = 0; i < PREDEFS_MAX; i++)
424 roff_setstr(r, predefs[i].name, predefs[i].str, 0);
425
426 return(r);
427 }
428
429 /*
430 * Pre-filter each and every line for reserved words (one beginning with
431 * `\*', e.g., `\*(ab'). These must be handled before the actual line
432 * is processed.
433 * This also checks the syntax of regular escapes.
434 */
435 static enum rofferr
436 roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
437 {
438 enum mandoc_esc esc;
439 const char *stesc; /* start of an escape sequence ('\\') */
440 const char *stnam; /* start of the name, after "[(*" */
441 const char *cp; /* end of the name, e.g. before ']' */
442 const char *res; /* the string to be substituted */
443 int i, maxl, expand_count;
444 size_t nsz;
445 char *n;
446
447 expand_count = 0;
448
449 again:
450 cp = *bufp + pos;
451 while (NULL != (cp = strchr(cp, '\\'))) {
452 stesc = cp++;
453
454 /*
455 * The second character must be an asterisk.
456 * If it isn't, skip it anyway: It is escaped,
457 * so it can't start another escape sequence.
458 */
459
460 if ('\0' == *cp)
461 return(ROFF_CONT);
462
463 if ('*' != *cp) {
464 res = cp;
465 esc = mandoc_escape(&cp, NULL, NULL);
466 if (ESCAPE_ERROR != esc)
467 continue;
468 cp = res;
469 mandoc_msg
470 (MANDOCERR_BADESCAPE, r->parse,
471 ln, (int)(stesc - *bufp), NULL);
472 return(ROFF_CONT);
473 }
474
475 cp++;
476
477 /*
478 * The third character decides the length
479 * of the name of the string.
480 * Save a pointer to the name.
481 */
482
483 switch (*cp) {
484 case ('\0'):
485 return(ROFF_CONT);
486 case ('('):
487 cp++;
488 maxl = 2;
489 break;
490 case ('['):
491 cp++;
492 maxl = 0;
493 break;
494 default:
495 maxl = 1;
496 break;
497 }
498 stnam = cp;
499
500 /* Advance to the end of the name. */
501
502 for (i = 0; 0 == maxl || i < maxl; i++, cp++) {
503 if ('\0' == *cp) {
504 mandoc_msg
505 (MANDOCERR_BADESCAPE,
506 r->parse, ln,
507 (int)(stesc - *bufp), NULL);
508 return(ROFF_CONT);
509 }
510 if (0 == maxl && ']' == *cp)
511 break;
512 }
513
514 /*
515 * Retrieve the replacement string; if it is
516 * undefined, resume searching for escapes.
517 */
518
519 res = roff_getstrn(r, stnam, (size_t)i);
520
521 if (NULL == res) {
522 mandoc_msg
523 (MANDOCERR_BADESCAPE, r->parse,
524 ln, (int)(stesc - *bufp), NULL);
525 res = "";
526 }
527
528 /* Replace the escape sequence by the string. */
529
530 pos = stesc - *bufp;
531
532 nsz = *szp + strlen(res) + 1;
533 n = mandoc_malloc(nsz);
534
535 strlcpy(n, *bufp, (size_t)(stesc - *bufp + 1));
536 strlcat(n, res, nsz);
537 strlcat(n, cp + (maxl ? 0 : 1), nsz);
538
539 free(*bufp);
540
541 *bufp = n;
542 *szp = nsz;
543
544 if (EXPAND_LIMIT >= ++expand_count)
545 goto again;
546
547 /* Just leave the string unexpanded. */
548 mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, ln, pos, NULL);
549 return(ROFF_IGN);
550 }
551 return(ROFF_CONT);
552 }
553
554 /*
555 * Process text streams: convert all breakable hyphens into ASCII_HYPH.
556 */
557 static enum rofferr
558 roff_parsetext(char *p)
559 {
560 size_t sz;
561 const char *start;
562 enum mandoc_esc esc;
563
564 start = p;
565
566 while ('\0' != *p) {
567 sz = strcspn(p, "-\\");
568 p += sz;
569
570 if ('\0' == *p)
571 break;
572
573 if ('\\' == *p) {
574 /* Skip over escapes. */
575 p++;
576 esc = mandoc_escape
577 ((const char **)&p, NULL, NULL);
578 if (ESCAPE_ERROR == esc)
579 break;
580 continue;
581 } else if (p == start) {
582 p++;
583 continue;
584 }
585
586 if (isalpha((unsigned char)p[-1]) &&
587 isalpha((unsigned char)p[1]))
588 *p = ASCII_HYPH;
589 p++;
590 }
591
592 return(ROFF_CONT);
593 }
594
595 enum rofferr
596 roff_parseln(struct roff *r, int ln, char **bufp,
597 size_t *szp, int pos, int *offs)
598 {
599 enum rofft t;
600 enum rofferr e;
601 int ppos, ctl;
602
603 /*
604 * Run the reserved-word filter only if we have some reserved
605 * words to fill in.
606 */
607
608 e = roff_res(r, bufp, szp, ln, pos);
609 if (ROFF_IGN == e)
610 return(e);
611 assert(ROFF_CONT == e);
612
613 ppos = pos;
614 ctl = mandoc_getcontrol(*bufp, &pos);
615
616 /*
617 * First, if a scope is open and we're not a macro, pass the
618 * text through the macro's filter. If a scope isn't open and
619 * we're not a macro, just let it through.
620 * Finally, if there's an equation scope open, divert it into it
621 * no matter our state.
622 */
623
624 if (r->last && ! ctl) {
625 t = r->last->tok;
626 assert(roffs[t].text);
627 e = (*roffs[t].text)
628 (r, t, bufp, szp, ln, pos, pos, offs);
629 assert(ROFF_IGN == e || ROFF_CONT == e);
630 if (ROFF_CONT != e)
631 return(e);
632 if (r->eqn)
633 return(eqn_read(&r->eqn, ln, *bufp, pos, offs));
634 if (r->tbl)
635 return(tbl_read(r->tbl, ln, *bufp, pos));
636 return(roff_parsetext(*bufp + pos));
637 } else if ( ! ctl) {
638 if (r->eqn)
639 return(eqn_read(&r->eqn, ln, *bufp, pos, offs));
640 if (r->tbl)
641 return(tbl_read(r->tbl, ln, *bufp, pos));
642 return(roff_parsetext(*bufp + pos));
643 } else if (r->eqn)
644 return(eqn_read(&r->eqn, ln, *bufp, ppos, offs));
645
646 /*
647 * If a scope is open, go to the child handler for that macro,
648 * as it may want to preprocess before doing anything with it.
649 * Don't do so if an equation is open.
650 */
651
652 if (r->last) {
653 t = r->last->tok;
654 assert(roffs[t].sub);
655 return((*roffs[t].sub)
656 (r, t, bufp, szp,
657 ln, ppos, pos, offs));
658 }
659
660 /*
661 * Lastly, as we've no scope open, try to look up and execute
662 * the new macro. If no macro is found, simply return and let
663 * the compilers handle it.
664 */
761 default:
762 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
763 return(ROFF_IGN);
764 }
765
766 if ((*bufp)[pos])
767 mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
768
769 roffnode_pop(r);
770 roffnode_cleanscope(r);
771 return(ROFF_IGN);
772
773 }
774
775
776 static void
777 roffnode_cleanscope(struct roff *r)
778 {
779
780 while (r->last) {
781 if (--r->last->endspan < 0)
782 break;
783 roffnode_pop(r);
784 }
785 }
786
787
788 /* ARGSUSED */
789 static enum rofferr
790 roff_ccond(ROFF_ARGS)
791 {
792
793 if (NULL == r->last) {
794 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
795 return(ROFF_IGN);
796 }
797
798 switch (r->last->tok) {
799 case (ROFF_el):
800 /* FALLTHROUGH */
801 case (ROFF_ie):
967 roff_block_text(ROFF_ARGS)
968 {
969
970 if (ROFF_de == tok)
971 roff_setstr(r, r->last->name, *bufp + pos, 1);
972
973 return(ROFF_IGN);
974 }
975
976
977 /* ARGSUSED */
978 static enum rofferr
979 roff_cond_sub(ROFF_ARGS)
980 {
981 enum rofft t;
982 enum roffrule rr;
983 char *ep;
984
985 rr = r->last->rule;
986 roffnode_cleanscope(r);
987
988 /*
989 * If the macro is unknown, first check if it contains a closing
990 * delimiter `\}'. If it does, close out our scope and return
991 * the currently-scoped rule (ignore or continue). Else, drop
992 * into the currently-scoped rule.
993 */
994
995 if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos))) {
996 ep = &(*bufp)[pos];
997 for ( ; NULL != (ep = strchr(ep, '\\')); ep++) {
998 ep++;
999 if ('}' != *ep)
1000 continue;
1001
1002 /*
1003 * Make the \} go away.
1004 * This is a little haphazard, as it's not quite
1005 * clear how nroff does this.
1006 * If we're at the end of line, then just chop
1007 * off the \} and resize the buffer.
1008 * If we aren't, then conver it to spaces.
1009 */
1010
1011 if ('\0' == *(ep + 1)) {
1012 *--ep = '\0';
1013 *szp -= 2;
1014 } else
1015 *(ep - 1) = *ep = ' ';
1016
1017 roff_ccond(r, ROFF_ccond, bufp, szp,
1018 ln, pos, pos + 2, offs);
1019 break;
1020 }
1021 return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
1022 }
1023
1024 /*
1025 * A denied conditional must evaluate its children if and only
1026 * if they're either structurally required (such as loops and
1027 * conditionals) or a closing macro.
1028 */
1029
1030 if (ROFFRULE_DENY == rr)
1031 if ( ! (ROFFMAC_STRUCT & roffs[t].flags))
1032 if (ROFF_ccond != t)
1033 return(ROFF_IGN);
1034
1035 assert(roffs[t].proc);
1036 return((*roffs[t].proc)(r, t, bufp, szp,
1037 ln, ppos, pos, offs));
1038 }
1039
1040 /* ARGSUSED */
1041 static enum rofferr
1042 roff_cond_text(ROFF_ARGS)
1043 {
1044 char *ep;
1045 enum roffrule rr;
1046
1047 rr = r->last->rule;
1048 roffnode_cleanscope(r);
1049
1050 ep = &(*bufp)[pos];
1051 for ( ; NULL != (ep = strchr(ep, '\\')); ep++) {
1052 ep++;
1053 if ('}' != *ep)
1054 continue;
1055 *ep = '&';
1056 roff_ccond(r, ROFF_ccond, bufp, szp,
1057 ln, pos, pos + 2, offs);
1058 }
1059 return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
1060 }
1061
1062 static enum roffrule
1063 roff_evalcond(const char *v, int *pos)
1064 {
1065
1066 switch (v[*pos]) {
1067 case ('n'):
1068 (*pos)++;
1069 return(ROFFRULE_ALLOW);
1070 case ('e'):
1071 /* FALLTHROUGH */
1072 case ('o'):
1073 /* FALLTHROUGH */
1074 case ('t'):
1075 (*pos)++;
1076 return(ROFFRULE_DENY);
1077 default:
1078 break;
1079 }
1080
1081 while (v[*pos] && ' ' != v[*pos])
1082 (*pos)++;
1083 return(ROFFRULE_DENY);
1084 }
1085
1086 /* ARGSUSED */
1087 static enum rofferr
1088 roff_line_ignore(ROFF_ARGS)
1089 {
1090
1091 if (ROFF_it == tok)
1092 mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos, "it");
1093
1094 return(ROFF_IGN);
1095 }
1096
1097 /* ARGSUSED */
1098 static enum rofferr
1099 roff_cond(ROFF_ARGS)
1100 {
1101 int sv;
1102 enum roffrule rule;
1103
1104 /*
1105 * An `.el' has no conditional body: it will consume the value
1106 * of the current rstack entry set in prior `ie' calls or
1107 * defaults to DENY.
1108 *
1109 * If we're not an `el', however, then evaluate the conditional.
1110 */
1111
1112 rule = ROFF_el == tok ?
1113 (r->rstackpos < 0 ?
1114 ROFFRULE_DENY : r->rstack[r->rstackpos--]) :
1115 roff_evalcond(*bufp, &pos);
1116
1117 sv = pos;
1118 while (' ' == (*bufp)[pos])
1119 pos++;
1120
1121 /*
1122 * Roff is weird. If we have just white-space after the
1123 * conditional, it's considered the BODY and we exit without
1124 * really doing anything. Warn about this. It's probably
1125 * wrong.
1126 */
1127
1128 if ('\0' == (*bufp)[pos] && sv != pos) {
1129 mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL);
1130 return(ROFF_IGN);
1131 }
1132
1133 roffnode_push(r, tok, NULL, ln, ppos);
1134
1135 r->last->rule = rule;
1136
1137 /*
1138 * An if-else will put the NEGATION of the current evaluated
1139 * conditional into the stack of rules.
1140 */
1141
1142 if (ROFF_ie == tok) {
1143 if (r->rstackpos == RSTACK_MAX - 1) {
1144 mandoc_msg(MANDOCERR_MEM,
1145 r->parse, ln, ppos, NULL);
1146 return(ROFF_ERR);
1147 }
1148 r->rstack[++r->rstackpos] =
1149 ROFFRULE_DENY == r->last->rule ?
1150 ROFFRULE_ALLOW : ROFFRULE_DENY;
1151 }
1152
1153 /* If the parent has false as its rule, then so do we. */
1154
1155 if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule)
1156 r->last->rule = ROFFRULE_DENY;
1157
1158 /*
1159 * Determine scope. If we're invoked with "\{" trailing the
1160 * conditional, then we're in a multiline scope. Else our scope
1161 * expires on the next line.
1162 */
1163
1164 r->last->endspan = 1;
1165
1166 if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) {
1167 r->last->endspan = -1;
1168 pos += 2;
1169 }
1170
1171 /*
1172 * If there are no arguments on the line, the next-line scope is
1173 * assumed.
1174 */
1175
1176 if ('\0' == (*bufp)[pos])
1177 return(ROFF_IGN);
1178
1179 /* Otherwise re-run the roff parser after recalculating. */
1180
1181 *offs = pos;
1182 return(ROFF_RERUN);
1183 }
1184
1185
1186 /* ARGSUSED */
1187 static enum rofferr
1188 roff_ds(ROFF_ARGS)
1189 {
1190 char *name, *string;
1191
1192 /*
1193 * A symbol is named by the first word following the macro
1194 * invocation up to a space. Its value is anything after the
1195 * name's trailing whitespace and optional double-quote. Thus,
1196 *
1197 * [.ds foo "bar " ]
1198 *
1199 * will have `bar " ' as its value.
1200 */
1201
1202 string = *bufp + pos;
1203 name = roff_getname(r, &string, ln, pos);
1204 if ('\0' == *name)
1205 return(ROFF_IGN);
1206
1207 /* Read past initial double-quote. */
1208 if ('"' == *string)
1209 string++;
1210
1211 /* The rest is the value. */
1212 roff_setstr(r, name, string, 0);
1213 return(ROFF_IGN);
1214 }
1215
1216 int
1217 roff_regisset(const struct roff *r, enum regs reg)
1218 {
1219
1220 return(r->regs[(int)reg].set);
1221 }
1222
1223 unsigned int
1224 roff_regget(const struct roff *r, enum regs reg)
1225 {
1226
1227 return(r->regs[(int)reg].u);
1228 }
1229
1230 void
1231 roff_regunset(struct roff *r, enum regs reg)
1232 {
1233
1234 r->regs[(int)reg].set = 0;
1235 }
1236
1237 /* ARGSUSED */
1238 static enum rofferr
1239 roff_nr(ROFF_ARGS)
1240 {
1241 const char *key;
1242 char *val;
1243 int iv;
1244
1245 val = *bufp + pos;
1246 key = roff_getname(r, &val, ln, pos);
1247
1248 if (0 == strcmp(key, "nS")) {
1249 r->regs[(int)REG_nS].set = 1;
1250 if ((iv = mandoc_strntoi(val, strlen(val), 10)) >= 0)
1251 r->regs[(int)REG_nS].u = (unsigned)iv;
1252 else
1253 r->regs[(int)REG_nS].u = 0u;
1254 }
1255
1256 return(ROFF_IGN);
1257 }
1258
1259 /* ARGSUSED */
1260 static enum rofferr
1261 roff_rm(ROFF_ARGS)
1262 {
1263 const char *name;
1264 char *cp;
1265
1266 cp = *bufp + pos;
1267 while ('\0' != *cp) {
1268 name = roff_getname(r, &cp, ln, (int)(cp - *bufp));
1269 if ('\0' != *name)
1270 roff_setstr(r, name, NULL, 0);
1271 }
1272 return(ROFF_IGN);
1273 }
1274
1275 /* ARGSUSED */
1276 static enum rofferr
1277 roff_TE(ROFF_ARGS)
1278 {
1279
1280 if (NULL == r->tbl)
1281 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1282 else
1283 tbl_end(&r->tbl);
1284
1285 return(ROFF_IGN);
1286 }
1287
1288 /* ARGSUSED */
1289 static enum rofferr
1290 roff_T_(ROFF_ARGS)
1291 {
1292
1293 if (NULL == r->tbl)
1294 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1295 else
1296 tbl_restart(ppos, ln, r->tbl);
1335 roff_EQ(ROFF_ARGS)
1336 {
1337
1338 roff_openeqn(r, *bufp + pos, ln, ppos, NULL);
1339 return(ROFF_IGN);
1340 }
1341
1342 /* ARGSUSED */
1343 static enum rofferr
1344 roff_EN(ROFF_ARGS)
1345 {
1346
1347 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1348 return(ROFF_IGN);
1349 }
1350
1351 /* ARGSUSED */
1352 static enum rofferr
1353 roff_TS(ROFF_ARGS)
1354 {
1355 struct tbl_node *t;
1356
1357 if (r->tbl) {
1358 mandoc_msg(MANDOCERR_SCOPEBROKEN, r->parse, ln, ppos, NULL);
1359 tbl_end(&r->tbl);
1360 }
1361
1362 t = tbl_alloc(ppos, ln, r->parse);
1363
1364 if (r->last_tbl)
1365 r->last_tbl->next = t;
1366 else
1367 r->first_tbl = r->last_tbl = t;
1368
1369 r->tbl = r->last_tbl = t;
1370 return(ROFF_IGN);
1371 }
1372
1373 /* ARGSUSED */
1374 static enum rofferr
1375 roff_tr(ROFF_ARGS)
1376 {
1377 const char *p, *first, *second;
1378 size_t fsz, ssz;
1379 enum mandoc_esc esc;
1380
1381 p = *bufp + pos;
1382
1383 if ('\0' == *p) {
1384 mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, ln, ppos, NULL);
1385 return(ROFF_IGN);
1386 }
1387
1388 while ('\0' != *p) {
1389 fsz = ssz = 1;
1390
1391 first = p++;
1392 if ('\\' == *first) {
1393 esc = mandoc_escape(&p, NULL, NULL);
1394 if (ESCAPE_ERROR == esc) {
1453 name = *bufp + pos;
1454 if ('/' == *name || strstr(name, "../") || strstr(name, "/..")) {
1455 mandoc_msg(MANDOCERR_SOPATH, r->parse, ln, pos, NULL);
1456 return(ROFF_ERR);
1457 }
1458
1459 *offs = pos;
1460 return(ROFF_SO);
1461 }
1462
1463 /* ARGSUSED */
1464 static enum rofferr
1465 roff_userdef(ROFF_ARGS)
1466 {
1467 const char *arg[9];
1468 char *cp, *n1, *n2;
1469 int i;
1470
1471 /*
1472 * Collect pointers to macro argument strings
1473 * and null-terminate them.
1474 */
1475 cp = *bufp + pos;
1476 for (i = 0; i < 9; i++)
1477 arg[i] = '\0' == *cp ? "" :
1478 mandoc_getarg(r->parse, &cp, ln, &pos);
1479
1480 /*
1481 * Expand macro arguments.
1482 */
1483 *szp = 0;
1484 n1 = cp = mandoc_strdup(r->current_string);
1485 while (NULL != (cp = strstr(cp, "\\$"))) {
1486 i = cp[2] - '1';
1487 if (0 > i || 8 < i) {
1488 /* Not an argument invocation. */
1489 cp += 2;
1490 continue;
1491 }
1492
1493 *szp = strlen(n1) - 3 + strlen(arg[i]) + 1;
1748 esc = mandoc_escape(&p, NULL, NULL);
1749 if (ESCAPE_ERROR == esc) {
1750 sz = strlen(pp);
1751 res = mandoc_realloc(res, ssz + sz + 1);
1752 memcpy(res + ssz, pp, sz);
1753 break;
1754 }
1755 /*
1756 * We bail out on bad escapes.
1757 * No need to warn: we already did so when
1758 * roff_res() was called.
1759 */
1760 sz = (int)(p - pp);
1761 res = mandoc_realloc(res, ssz + sz + 1);
1762 memcpy(res + ssz, pp, sz);
1763 ssz += sz;
1764 }
1765
1766 res[(int)ssz] = '\0';
1767 return(res);
1768 }
|
1 /* $Id: roff.c,v 1.189 2013/12/30 18:44:06 schwarze Exp $ */
2 /*
3 * Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2010, 2011, 2012, 2013 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 AUTHORS DISCLAIM ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS 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 <ctype.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "mandoc.h"
29 #include "libroff.h"
30 #include "libmandoc.h"
31
32 /* Maximum number of nested if-else conditionals. */
33 #define RSTACK_MAX 128
34
35 /* Maximum number of string expansions per line, to break infinite loops. */
36 #define EXPAND_LIMIT 1000
37
38 enum rofft {
39 ROFF_ad,
40 ROFF_am,
41 ROFF_ami,
42 ROFF_am1,
43 ROFF_cc,
44 ROFF_de,
45 ROFF_dei,
46 ROFF_de1,
47 ROFF_ds,
48 ROFF_el,
49 ROFF_fam,
50 ROFF_hw,
51 ROFF_hy,
52 ROFF_ie,
53 ROFF_if,
54 ROFF_ig,
55 ROFF_it,
56 ROFF_ne,
57 ROFF_nh,
58 ROFF_nr,
59 ROFF_ns,
60 ROFF_ps,
61 ROFF_rm,
62 ROFF_so,
63 ROFF_ta,
64 ROFF_tr,
65 ROFF_Dd,
66 ROFF_TH,
67 ROFF_TS,
68 ROFF_TE,
69 ROFF_T_,
70 ROFF_EQ,
71 ROFF_EN,
72 ROFF_cblock,
73 ROFF_ccond,
74 ROFF_USERDEF,
75 ROFF_MAX
76 };
77
78 enum roffrule {
79 ROFFRULE_DENY,
80 ROFFRULE_ALLOW
81 };
82
83 /*
84 * An incredibly-simple string buffer.
85 */
86 struct roffstr {
87 char *p; /* nil-terminated buffer */
88 size_t sz; /* saved strlen(p) */
89 };
90
91 /*
92 * A key-value roffstr pair as part of a singly-linked list.
93 */
94 struct roffkv {
95 struct roffstr key;
96 struct roffstr val;
97 struct roffkv *next; /* next in list */
98 };
99
100 /*
101 * A single number register as part of a singly-linked list.
102 */
103 struct roffreg {
104 struct roffstr key;
105 int val;
106 struct roffreg *next;
107 };
108
109 struct roff {
110 enum mparset parsetype; /* requested parse type */
111 struct mparse *parse; /* parse point */
112 struct roffnode *last; /* leaf of stack */
113 enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */
114 char control; /* control character */
115 int rstackpos; /* position in rstack */
116 struct roffreg *regtab; /* number registers */
117 struct roffkv *strtab; /* user-defined strings & macros */
118 struct roffkv *xmbtab; /* multi-byte trans table (`tr') */
119 struct roffstr *xtab; /* single-byte trans table (`tr') */
120 const char *current_string; /* value of last called user macro */
121 struct tbl_node *first_tbl; /* first table parsed */
122 struct tbl_node *last_tbl; /* last table parsed */
123 struct tbl_node *tbl; /* current table being parsed */
124 struct eqn_node *last_eqn; /* last equation parsed */
125 struct eqn_node *first_eqn; /* first equation parsed */
126 struct eqn_node *eqn; /* current equation being parsed */
127 };
128
129 struct roffnode {
130 enum rofft tok; /* type of node */
131 struct roffnode *parent; /* up one in stack */
132 int line; /* parse line */
133 int col; /* parse col */
134 char *name; /* node name, e.g. macro name */
135 char *end; /* end-rules: custom token */
136 int endspan; /* end-rules: next-line or infty */
159 };
160
161 struct predef {
162 const char *name; /* predefined input name */
163 const char *str; /* replacement symbol */
164 };
165
166 #define PREDEF(__name, __str) \
167 { (__name), (__str) },
168
169 static enum rofft roffhash_find(const char *, size_t);
170 static void roffhash_init(void);
171 static void roffnode_cleanscope(struct roff *);
172 static void roffnode_pop(struct roff *);
173 static void roffnode_push(struct roff *, enum rofft,
174 const char *, int, int);
175 static enum rofferr roff_block(ROFF_ARGS);
176 static enum rofferr roff_block_text(ROFF_ARGS);
177 static enum rofferr roff_block_sub(ROFF_ARGS);
178 static enum rofferr roff_cblock(ROFF_ARGS);
179 static enum rofferr roff_cc(ROFF_ARGS);
180 static enum rofferr roff_ccond(ROFF_ARGS);
181 static enum rofferr roff_cond(ROFF_ARGS);
182 static enum rofferr roff_cond_text(ROFF_ARGS);
183 static enum rofferr roff_cond_sub(ROFF_ARGS);
184 static enum rofferr roff_ds(ROFF_ARGS);
185 static enum roffrule roff_evalcond(const char *, int *);
186 static void roff_free1(struct roff *);
187 static void roff_freereg(struct roffreg *);
188 static void roff_freestr(struct roffkv *);
189 static char *roff_getname(struct roff *, char **, int, int);
190 static int roff_getnum(const char *, int *, int *);
191 static int roff_getop(const char *, int *, char *);
192 static int roff_getregn(const struct roff *,
193 const char *, size_t);
194 static const char *roff_getstrn(const struct roff *,
195 const char *, size_t);
196 static enum rofferr roff_it(ROFF_ARGS);
197 static enum rofferr roff_line_ignore(ROFF_ARGS);
198 static enum rofferr roff_nr(ROFF_ARGS);
199 static void roff_openeqn(struct roff *, const char *,
200 int, int, const char *);
201 static enum rofft roff_parse(struct roff *, const char *, int *);
202 static enum rofferr roff_parsetext(char **, size_t *, int, int *);
203 static enum rofferr roff_res(struct roff *,
204 char **, size_t *, int, int);
205 static enum rofferr roff_rm(ROFF_ARGS);
206 static void roff_setstr(struct roff *,
207 const char *, const char *, int);
208 static void roff_setstrn(struct roffkv **, const char *,
209 size_t, const char *, size_t, int);
210 static enum rofferr roff_so(ROFF_ARGS);
211 static enum rofferr roff_tr(ROFF_ARGS);
212 static enum rofferr roff_Dd(ROFF_ARGS);
213 static enum rofferr roff_TH(ROFF_ARGS);
214 static enum rofferr roff_TE(ROFF_ARGS);
215 static enum rofferr roff_TS(ROFF_ARGS);
216 static enum rofferr roff_EQ(ROFF_ARGS);
217 static enum rofferr roff_EN(ROFF_ARGS);
218 static enum rofferr roff_T_(ROFF_ARGS);
219 static enum rofferr roff_userdef(ROFF_ARGS);
220
221 /* See roffhash_find() */
222
223 #define ASCII_HI 126
224 #define ASCII_LO 33
225 #define HASHWIDTH (ASCII_HI - ASCII_LO + 1)
226
227 static struct roffmac *hash[HASHWIDTH];
228
229 static struct roffmac roffs[ROFF_MAX] = {
230 { "ad", roff_line_ignore, NULL, NULL, 0, NULL },
231 { "am", roff_block, roff_block_text, roff_block_sub, 0, NULL },
232 { "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },
233 { "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
234 { "cc", roff_cc, NULL, NULL, 0, NULL },
235 { "de", roff_block, roff_block_text, roff_block_sub, 0, NULL },
236 { "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },
237 { "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
238 { "ds", roff_ds, NULL, NULL, 0, NULL },
239 { "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
240 { "fam", roff_line_ignore, NULL, NULL, 0, NULL },
241 { "hw", roff_line_ignore, NULL, NULL, 0, NULL },
242 { "hy", roff_line_ignore, NULL, NULL, 0, NULL },
243 { "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
244 { "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
245 { "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL },
246 { "it", roff_it, NULL, NULL, 0, NULL },
247 { "ne", roff_line_ignore, NULL, NULL, 0, NULL },
248 { "nh", roff_line_ignore, NULL, NULL, 0, NULL },
249 { "nr", roff_nr, NULL, NULL, 0, NULL },
250 { "ns", roff_line_ignore, NULL, NULL, 0, NULL },
251 { "ps", roff_line_ignore, NULL, NULL, 0, NULL },
252 { "rm", roff_rm, NULL, NULL, 0, NULL },
253 { "so", roff_so, NULL, NULL, 0, NULL },
254 { "ta", roff_line_ignore, NULL, NULL, 0, NULL },
255 { "tr", roff_tr, NULL, NULL, 0, NULL },
256 { "Dd", roff_Dd, NULL, NULL, 0, NULL },
257 { "TH", roff_TH, NULL, NULL, 0, NULL },
258 { "TS", roff_TS, NULL, NULL, 0, NULL },
259 { "TE", roff_TE, NULL, NULL, 0, NULL },
260 { "T&", roff_T_, NULL, NULL, 0, NULL },
261 { "EQ", roff_EQ, NULL, NULL, 0, NULL },
262 { "EN", roff_EN, NULL, NULL, 0, NULL },
263 { ".", roff_cblock, NULL, NULL, 0, NULL },
264 { "\\}", roff_ccond, NULL, NULL, 0, NULL },
265 { NULL, roff_userdef, NULL, NULL, 0, NULL },
266 };
267
268 const char *const __mdoc_reserved[] = {
269 "Ac", "Ad", "An", "Ao", "Ap", "Aq", "Ar", "At",
270 "Bc", "Bd", "Bf", "Bk", "Bl", "Bo", "Bq",
271 "Brc", "Bro", "Brq", "Bsx", "Bt", "Bx",
272 "Cd", "Cm", "Db", "Dc", "Dd", "Dl", "Do", "Dq",
273 "Ds", "Dt", "Dv", "Dx", "D1",
274 "Ec", "Ed", "Ef", "Ek", "El", "Em", "em",
275 "En", "Eo", "Eq", "Er", "Es", "Ev", "Ex",
276 "Fa", "Fc", "Fd", "Fl", "Fn", "Fo", "Fr", "Ft", "Fx",
277 "Hf", "Ic", "In", "It", "Lb", "Li", "Lk", "Lp", "LP",
278 "Me", "Ms", "Mt", "Nd", "Nm", "No", "Ns", "Nx",
279 "Oc", "Oo", "Op", "Os", "Ot", "Ox",
280 "Pa", "Pc", "Pf", "Po", "Pp", "PP", "pp", "Pq",
281 "Qc", "Ql", "Qo", "Qq", "Or", "Rd", "Re", "Rs", "Rv",
282 "Sc", "Sf", "Sh", "SH", "Sm", "So", "Sq",
283 "Ss", "St", "Sx", "Sy",
284 "Ta", "Tn", "Ud", "Ux", "Va", "Vt", "Xc", "Xo", "Xr",
285 "%A", "%B", "%D", "%I", "%J", "%N", "%O",
286 "%P", "%Q", "%R", "%T", "%U", "%V",
287 NULL
288 };
289
290 const char *const __man_reserved[] = {
291 "AT", "B", "BI", "BR", "BT", "DE", "DS", "DT",
292 "EE", "EN", "EQ", "EX", "HF", "HP", "I", "IB", "IP", "IR",
293 "LP", "ME", "MT", "OP", "P", "PD", "PP", "PT",
294 "R", "RB", "RE", "RI", "RS", "SB", "SH", "SM", "SS", "SY",
295 "TE", "TH", "TP", "TQ", "TS", "T&", "UC", "UE", "UR", "YS",
296 NULL
297 };
298
299 /* Array of injected predefined strings. */
300 #define PREDEFS_MAX 38
301 static const struct predef predefs[PREDEFS_MAX] = {
302 #include "predefs.in"
303 };
304
305 /* See roffhash_find() */
306 #define ROFF_HASH(p) (p[0] - ASCII_LO)
307
308 static int roffit_lines; /* number of lines to delay */
309 static char *roffit_macro; /* nil-terminated macro line */
310
311 static void
312 roffhash_init(void)
313 {
314 struct roffmac *n;
315 int buc, i;
316
317 for (i = 0; i < (int)ROFF_USERDEF; i++) {
318 assert(roffs[i].name[0] >= ASCII_LO);
319 assert(roffs[i].name[0] <= ASCII_HI);
320
321 buc = ROFF_HASH(roffs[i].name);
322
323 if (NULL != (n = hash[buc])) {
324 for ( ; n->next; n = n->next)
325 /* Do nothing. */ ;
326 n->next = &roffs[i];
327 } else
328 hash[buc] = &roffs[i];
329 }
330 }
389 int line, int col)
390 {
391 struct roffnode *p;
392
393 p = mandoc_calloc(1, sizeof(struct roffnode));
394 p->tok = tok;
395 if (name)
396 p->name = mandoc_strdup(name);
397 p->parent = r->last;
398 p->line = line;
399 p->col = col;
400 p->rule = p->parent ? p->parent->rule : ROFFRULE_DENY;
401
402 r->last = p;
403 }
404
405
406 static void
407 roff_free1(struct roff *r)
408 {
409 struct tbl_node *tbl;
410 struct eqn_node *e;
411 int i;
412
413 while (NULL != (tbl = r->first_tbl)) {
414 r->first_tbl = tbl->next;
415 tbl_free(tbl);
416 }
417
418 r->first_tbl = r->last_tbl = r->tbl = NULL;
419
420 while (NULL != (e = r->first_eqn)) {
421 r->first_eqn = e->next;
422 eqn_free(e);
423 }
424
425 r->first_eqn = r->last_eqn = r->eqn = NULL;
426
427 while (r->last)
428 roffnode_pop(r);
429
430 roff_freestr(r->strtab);
431 roff_freestr(r->xmbtab);
432
433 r->strtab = r->xmbtab = NULL;
434
435 roff_freereg(r->regtab);
436
437 r->regtab = NULL;
438
439 if (r->xtab)
440 for (i = 0; i < 128; i++)
441 free(r->xtab[i].p);
442
443 free(r->xtab);
444 r->xtab = NULL;
445 }
446
447 void
448 roff_reset(struct roff *r)
449 {
450 int i;
451
452 roff_free1(r);
453
454 r->control = 0;
455
456 for (i = 0; i < PREDEFS_MAX; i++)
457 roff_setstr(r, predefs[i].name, predefs[i].str, 0);
458 }
459
460
461 void
462 roff_free(struct roff *r)
463 {
464
465 roff_free1(r);
466 free(r);
467 }
468
469
470 struct roff *
471 roff_alloc(enum mparset type, struct mparse *parse)
472 {
473 struct roff *r;
474 int i;
475
476 r = mandoc_calloc(1, sizeof(struct roff));
477 r->parsetype = type;
478 r->parse = parse;
479 r->rstackpos = -1;
480
481 roffhash_init();
482
483 for (i = 0; i < PREDEFS_MAX; i++)
484 roff_setstr(r, predefs[i].name, predefs[i].str, 0);
485
486 return(r);
487 }
488
489 /*
490 * In the current line, expand user-defined strings ("\*")
491 * and references to number registers ("\n").
492 * Also check the syntax of other escape sequences.
493 */
494 static enum rofferr
495 roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
496 {
497 char ubuf[12]; /* buffer to print the number */
498 const char *stesc; /* start of an escape sequence ('\\') */
499 const char *stnam; /* start of the name, after "[(*" */
500 const char *cp; /* end of the name, e.g. before ']' */
501 const char *res; /* the string to be substituted */
502 char *nbuf; /* new buffer to copy bufp to */
503 size_t nsz; /* size of the new buffer */
504 size_t maxl; /* expected length of the escape name */
505 size_t naml; /* actual length of the escape name */
506 int expand_count; /* to avoid infinite loops */
507
508 expand_count = 0;
509
510 again:
511 cp = *bufp + pos;
512 while (NULL != (cp = strchr(cp, '\\'))) {
513 stesc = cp++;
514
515 /*
516 * The second character must be an asterisk or an n.
517 * If it isn't, skip it anyway: It is escaped,
518 * so it can't start another escape sequence.
519 */
520
521 if ('\0' == *cp)
522 return(ROFF_CONT);
523
524 switch (*cp) {
525 case ('*'):
526 res = NULL;
527 break;
528 case ('n'):
529 res = ubuf;
530 break;
531 default:
532 if (ESCAPE_ERROR != mandoc_escape(&cp, NULL, NULL))
533 continue;
534 mandoc_msg
535 (MANDOCERR_BADESCAPE, r->parse,
536 ln, (int)(stesc - *bufp), NULL);
537 return(ROFF_CONT);
538 }
539
540 cp++;
541
542 /*
543 * The third character decides the length
544 * of the name of the string or register.
545 * Save a pointer to the name.
546 */
547
548 switch (*cp) {
549 case ('\0'):
550 return(ROFF_CONT);
551 case ('('):
552 cp++;
553 maxl = 2;
554 break;
555 case ('['):
556 cp++;
557 maxl = 0;
558 break;
559 default:
560 maxl = 1;
561 break;
562 }
563 stnam = cp;
564
565 /* Advance to the end of the name. */
566
567 for (naml = 0; 0 == maxl || naml < maxl; naml++, cp++) {
568 if ('\0' == *cp) {
569 mandoc_msg
570 (MANDOCERR_BADESCAPE,
571 r->parse, ln,
572 (int)(stesc - *bufp), NULL);
573 return(ROFF_CONT);
574 }
575 if (0 == maxl && ']' == *cp)
576 break;
577 }
578
579 /*
580 * Retrieve the replacement string; if it is
581 * undefined, resume searching for escapes.
582 */
583
584 if (NULL == res)
585 res = roff_getstrn(r, stnam, naml);
586 else
587 snprintf(ubuf, sizeof(ubuf), "%d",
588 roff_getregn(r, stnam, naml));
589
590 if (NULL == res) {
591 mandoc_msg
592 (MANDOCERR_BADESCAPE, r->parse,
593 ln, (int)(stesc - *bufp), NULL);
594 res = "";
595 }
596
597 /* Replace the escape sequence by the string. */
598
599 pos = stesc - *bufp;
600
601 nsz = *szp + strlen(res) + 1;
602 nbuf = mandoc_malloc(nsz);
603
604 strlcpy(nbuf, *bufp, (size_t)(stesc - *bufp + 1));
605 strlcat(nbuf, res, nsz);
606 strlcat(nbuf, cp + (maxl ? 0 : 1), nsz);
607
608 free(*bufp);
609
610 *bufp = nbuf;
611 *szp = nsz;
612
613 if (EXPAND_LIMIT >= ++expand_count)
614 goto again;
615
616 /* Just leave the string unexpanded. */
617 mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, ln, pos, NULL);
618 return(ROFF_IGN);
619 }
620 return(ROFF_CONT);
621 }
622
623 /*
624 * Process text streams:
625 * Convert all breakable hyphens into ASCII_HYPH.
626 * Decrement and spring input line trap.
627 */
628 static enum rofferr
629 roff_parsetext(char **bufp, size_t *szp, int pos, int *offs)
630 {
631 size_t sz;
632 const char *start;
633 char *p;
634 int isz;
635 enum mandoc_esc esc;
636
637 start = p = *bufp + pos;
638
639 while ('\0' != *p) {
640 sz = strcspn(p, "-\\");
641 p += sz;
642
643 if ('\0' == *p)
644 break;
645
646 if ('\\' == *p) {
647 /* Skip over escapes. */
648 p++;
649 esc = mandoc_escape((const char **)&p, NULL, NULL);
650 if (ESCAPE_ERROR == esc)
651 break;
652 continue;
653 } else if (p == start) {
654 p++;
655 continue;
656 }
657
658 if (isalpha((unsigned char)p[-1]) &&
659 isalpha((unsigned char)p[1]))
660 *p = ASCII_HYPH;
661 p++;
662 }
663
664 /* Spring the input line trap. */
665 if (1 == roffit_lines) {
666 isz = asprintf(&p, "%s\n.%s", *bufp, roffit_macro);
667 if (-1 == isz) {
668 perror(NULL);
669 exit((int)MANDOCLEVEL_SYSERR);
670 }
671 free(*bufp);
672 *bufp = p;
673 *szp = isz + 1;
674 *offs = 0;
675 free(roffit_macro);
676 roffit_lines = 0;
677 return(ROFF_REPARSE);
678 } else if (1 < roffit_lines)
679 --roffit_lines;
680 return(ROFF_CONT);
681 }
682
683 enum rofferr
684 roff_parseln(struct roff *r, int ln, char **bufp,
685 size_t *szp, int pos, int *offs)
686 {
687 enum rofft t;
688 enum rofferr e;
689 int ppos, ctl;
690
691 /*
692 * Run the reserved-word filter only if we have some reserved
693 * words to fill in.
694 */
695
696 e = roff_res(r, bufp, szp, ln, pos);
697 if (ROFF_IGN == e)
698 return(e);
699 assert(ROFF_CONT == e);
700
701 ppos = pos;
702 ctl = roff_getcontrol(r, *bufp, &pos);
703
704 /*
705 * First, if a scope is open and we're not a macro, pass the
706 * text through the macro's filter. If a scope isn't open and
707 * we're not a macro, just let it through.
708 * Finally, if there's an equation scope open, divert it into it
709 * no matter our state.
710 */
711
712 if (r->last && ! ctl) {
713 t = r->last->tok;
714 assert(roffs[t].text);
715 e = (*roffs[t].text)
716 (r, t, bufp, szp, ln, pos, pos, offs);
717 assert(ROFF_IGN == e || ROFF_CONT == e);
718 if (ROFF_CONT != e)
719 return(e);
720 }
721 if (r->eqn)
722 return(eqn_read(&r->eqn, ln, *bufp, ppos, offs));
723 if ( ! ctl) {
724 if (r->tbl)
725 return(tbl_read(r->tbl, ln, *bufp, pos));
726 return(roff_parsetext(bufp, szp, pos, offs));
727 }
728
729 /*
730 * If a scope is open, go to the child handler for that macro,
731 * as it may want to preprocess before doing anything with it.
732 * Don't do so if an equation is open.
733 */
734
735 if (r->last) {
736 t = r->last->tok;
737 assert(roffs[t].sub);
738 return((*roffs[t].sub)
739 (r, t, bufp, szp,
740 ln, ppos, pos, offs));
741 }
742
743 /*
744 * Lastly, as we've no scope open, try to look up and execute
745 * the new macro. If no macro is found, simply return and let
746 * the compilers handle it.
747 */
844 default:
845 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
846 return(ROFF_IGN);
847 }
848
849 if ((*bufp)[pos])
850 mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
851
852 roffnode_pop(r);
853 roffnode_cleanscope(r);
854 return(ROFF_IGN);
855
856 }
857
858
859 static void
860 roffnode_cleanscope(struct roff *r)
861 {
862
863 while (r->last) {
864 if (--r->last->endspan != 0)
865 break;
866 roffnode_pop(r);
867 }
868 }
869
870
871 /* ARGSUSED */
872 static enum rofferr
873 roff_ccond(ROFF_ARGS)
874 {
875
876 if (NULL == r->last) {
877 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
878 return(ROFF_IGN);
879 }
880
881 switch (r->last->tok) {
882 case (ROFF_el):
883 /* FALLTHROUGH */
884 case (ROFF_ie):
1050 roff_block_text(ROFF_ARGS)
1051 {
1052
1053 if (ROFF_de == tok)
1054 roff_setstr(r, r->last->name, *bufp + pos, 1);
1055
1056 return(ROFF_IGN);
1057 }
1058
1059
1060 /* ARGSUSED */
1061 static enum rofferr
1062 roff_cond_sub(ROFF_ARGS)
1063 {
1064 enum rofft t;
1065 enum roffrule rr;
1066 char *ep;
1067
1068 rr = r->last->rule;
1069 roffnode_cleanscope(r);
1070 t = roff_parse(r, *bufp, &pos);
1071
1072 /*
1073 * Fully handle known macros when they are structurally
1074 * required or when the conditional evaluated to true.
1075 */
1076
1077 if ((ROFF_MAX != t) &&
1078 (ROFF_ccond == t || ROFFRULE_ALLOW == rr ||
1079 ROFFMAC_STRUCT & roffs[t].flags)) {
1080 assert(roffs[t].proc);
1081 return((*roffs[t].proc)(r, t, bufp, szp,
1082 ln, ppos, pos, offs));
1083 }
1084
1085 /* Always check for the closing delimiter `\}'. */
1086
1087 ep = &(*bufp)[pos];
1088 while (NULL != (ep = strchr(ep, '\\'))) {
1089 if ('}' != *(++ep))
1090 continue;
1091
1092 /*
1093 * If we're at the end of line, then just chop
1094 * off the \} and resize the buffer.
1095 * If we aren't, then convert it to spaces.
1096 */
1097
1098 if ('\0' == *(ep + 1)) {
1099 *--ep = '\0';
1100 *szp -= 2;
1101 } else
1102 *(ep - 1) = *ep = ' ';
1103
1104 roff_ccond(r, ROFF_ccond, bufp, szp,
1105 ln, pos, pos + 2, offs);
1106 break;
1107 }
1108 return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
1109 }
1110
1111 /* ARGSUSED */
1112 static enum rofferr
1113 roff_cond_text(ROFF_ARGS)
1114 {
1115 char *ep;
1116 enum roffrule rr;
1117
1118 rr = r->last->rule;
1119 roffnode_cleanscope(r);
1120
1121 ep = &(*bufp)[pos];
1122 for ( ; NULL != (ep = strchr(ep, '\\')); ep++) {
1123 ep++;
1124 if ('}' != *ep)
1125 continue;
1126 *ep = '&';
1127 roff_ccond(r, ROFF_ccond, bufp, szp,
1128 ln, pos, pos + 2, offs);
1129 }
1130 return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
1131 }
1132
1133 static int
1134 roff_getnum(const char *v, int *pos, int *res)
1135 {
1136 int p, n;
1137
1138 p = *pos;
1139 n = v[p] == '-';
1140 if (n)
1141 p++;
1142
1143 for (*res = 0; isdigit((unsigned char)v[p]); p++)
1144 *res += 10 * *res + v[p] - '0';
1145 if (p == *pos + n)
1146 return 0;
1147
1148 if (n)
1149 *res = -*res;
1150
1151 *pos = p;
1152 return 1;
1153 }
1154
1155 static int
1156 roff_getop(const char *v, int *pos, char *res)
1157 {
1158 int e;
1159
1160 *res = v[*pos];
1161 e = v[*pos + 1] == '=';
1162
1163 switch (*res) {
1164 case '=':
1165 break;
1166 case '>':
1167 if (e)
1168 *res = 'g';
1169 break;
1170 case '<':
1171 if (e)
1172 *res = 'l';
1173 break;
1174 default:
1175 return(0);
1176 }
1177
1178 *pos += 1 + e;
1179
1180 return(*res);
1181 }
1182
1183 static enum roffrule
1184 roff_evalcond(const char *v, int *pos)
1185 {
1186 int not, lh, rh;
1187 char op;
1188
1189 switch (v[*pos]) {
1190 case ('n'):
1191 (*pos)++;
1192 return(ROFFRULE_ALLOW);
1193 case ('e'):
1194 /* FALLTHROUGH */
1195 case ('o'):
1196 /* FALLTHROUGH */
1197 case ('t'):
1198 (*pos)++;
1199 return(ROFFRULE_DENY);
1200 case ('!'):
1201 (*pos)++;
1202 not = 1;
1203 break;
1204 default:
1205 not = 0;
1206 break;
1207 }
1208
1209 if (!roff_getnum(v, pos, &lh))
1210 return ROFFRULE_DENY;
1211 if (!roff_getop(v, pos, &op)) {
1212 if (lh < 0)
1213 lh = 0;
1214 goto out;
1215 }
1216 if (!roff_getnum(v, pos, &rh))
1217 return ROFFRULE_DENY;
1218 switch (op) {
1219 case 'g':
1220 lh = lh >= rh;
1221 break;
1222 case 'l':
1223 lh = lh <= rh;
1224 break;
1225 case '=':
1226 lh = lh == rh;
1227 break;
1228 case '>':
1229 lh = lh > rh;
1230 break;
1231 case '<':
1232 lh = lh < rh;
1233 break;
1234 default:
1235 return ROFFRULE_DENY;
1236 }
1237 out:
1238 if (not)
1239 lh = !lh;
1240 return lh ? ROFFRULE_ALLOW : ROFFRULE_DENY;
1241 }
1242
1243 /* ARGSUSED */
1244 static enum rofferr
1245 roff_line_ignore(ROFF_ARGS)
1246 {
1247
1248 return(ROFF_IGN);
1249 }
1250
1251 /* ARGSUSED */
1252 static enum rofferr
1253 roff_cond(ROFF_ARGS)
1254 {
1255
1256 roffnode_push(r, tok, NULL, ln, ppos);
1257
1258 /*
1259 * An `.el' has no conditional body: it will consume the value
1260 * of the current rstack entry set in prior `ie' calls or
1261 * defaults to DENY.
1262 *
1263 * If we're not an `el', however, then evaluate the conditional.
1264 */
1265
1266 r->last->rule = ROFF_el == tok ?
1267 (r->rstackpos < 0 ?
1268 ROFFRULE_DENY : r->rstack[r->rstackpos--]) :
1269 roff_evalcond(*bufp, &pos);
1270
1271 /*
1272 * An if-else will put the NEGATION of the current evaluated
1273 * conditional into the stack of rules.
1274 */
1275
1276 if (ROFF_ie == tok) {
1277 if (r->rstackpos == RSTACK_MAX - 1) {
1278 mandoc_msg(MANDOCERR_MEM,
1279 r->parse, ln, ppos, NULL);
1280 return(ROFF_ERR);
1281 }
1282 r->rstack[++r->rstackpos] =
1283 ROFFRULE_DENY == r->last->rule ?
1284 ROFFRULE_ALLOW : ROFFRULE_DENY;
1285 }
1286
1287 /* If the parent has false as its rule, then so do we. */
1288
1289 if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule)
1290 r->last->rule = ROFFRULE_DENY;
1291
1292 /*
1293 * Determine scope.
1294 * If there is nothing on the line after the conditional,
1295 * not even whitespace, use next-line scope.
1296 */
1297
1298 if ('\0' == (*bufp)[pos]) {
1299 r->last->endspan = 2;
1300 goto out;
1301 }
1302
1303 while (' ' == (*bufp)[pos])
1304 pos++;
1305
1306 /* An opening brace requests multiline scope. */
1307
1308 if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) {
1309 r->last->endspan = -1;
1310 pos += 2;
1311 goto out;
1312 }
1313
1314 /*
1315 * Anything else following the conditional causes
1316 * single-line scope. Warn if the scope contains
1317 * nothing but trailing whitespace.
1318 */
1319
1320 if ('\0' == (*bufp)[pos])
1321 mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL);
1322
1323 r->last->endspan = 1;
1324
1325 out:
1326 *offs = pos;
1327 return(ROFF_RERUN);
1328 }
1329
1330
1331 /* ARGSUSED */
1332 static enum rofferr
1333 roff_ds(ROFF_ARGS)
1334 {
1335 char *name, *string;
1336
1337 /*
1338 * A symbol is named by the first word following the macro
1339 * invocation up to a space. Its value is anything after the
1340 * name's trailing whitespace and optional double-quote. Thus,
1341 *
1342 * [.ds foo "bar " ]
1343 *
1344 * will have `bar " ' as its value.
1345 */
1346
1347 string = *bufp + pos;
1348 name = roff_getname(r, &string, ln, pos);
1349 if ('\0' == *name)
1350 return(ROFF_IGN);
1351
1352 /* Read past initial double-quote. */
1353 if ('"' == *string)
1354 string++;
1355
1356 /* The rest is the value. */
1357 roff_setstr(r, name, string, 0);
1358 return(ROFF_IGN);
1359 }
1360
1361 void
1362 roff_setreg(struct roff *r, const char *name, int val, char sign)
1363 {
1364 struct roffreg *reg;
1365
1366 /* Search for an existing register with the same name. */
1367 reg = r->regtab;
1368
1369 while (reg && strcmp(name, reg->key.p))
1370 reg = reg->next;
1371
1372 if (NULL == reg) {
1373 /* Create a new register. */
1374 reg = mandoc_malloc(sizeof(struct roffreg));
1375 reg->key.p = mandoc_strdup(name);
1376 reg->key.sz = strlen(name);
1377 reg->val = 0;
1378 reg->next = r->regtab;
1379 r->regtab = reg;
1380 }
1381
1382 if ('+' == sign)
1383 reg->val += val;
1384 else if ('-' == sign)
1385 reg->val -= val;
1386 else
1387 reg->val = val;
1388 }
1389
1390 int
1391 roff_getreg(const struct roff *r, const char *name)
1392 {
1393 struct roffreg *reg;
1394
1395 for (reg = r->regtab; reg; reg = reg->next)
1396 if (0 == strcmp(name, reg->key.p))
1397 return(reg->val);
1398
1399 return(0);
1400 }
1401
1402 static int
1403 roff_getregn(const struct roff *r, const char *name, size_t len)
1404 {
1405 struct roffreg *reg;
1406
1407 for (reg = r->regtab; reg; reg = reg->next)
1408 if (len == reg->key.sz &&
1409 0 == strncmp(name, reg->key.p, len))
1410 return(reg->val);
1411
1412 return(0);
1413 }
1414
1415 static void
1416 roff_freereg(struct roffreg *reg)
1417 {
1418 struct roffreg *old_reg;
1419
1420 while (NULL != reg) {
1421 free(reg->key.p);
1422 old_reg = reg;
1423 reg = reg->next;
1424 free(old_reg);
1425 }
1426 }
1427
1428 /* ARGSUSED */
1429 static enum rofferr
1430 roff_nr(ROFF_ARGS)
1431 {
1432 const char *key;
1433 char *val;
1434 size_t sz;
1435 int iv;
1436 char sign;
1437
1438 val = *bufp + pos;
1439 key = roff_getname(r, &val, ln, pos);
1440
1441 sign = *val;
1442 if ('+' == sign || '-' == sign)
1443 val++;
1444
1445 sz = strspn(val, "0123456789");
1446 iv = sz ? mandoc_strntoi(val, sz, 10) : 0;
1447
1448 roff_setreg(r, key, iv, sign);
1449
1450 return(ROFF_IGN);
1451 }
1452
1453 /* ARGSUSED */
1454 static enum rofferr
1455 roff_rm(ROFF_ARGS)
1456 {
1457 const char *name;
1458 char *cp;
1459
1460 cp = *bufp + pos;
1461 while ('\0' != *cp) {
1462 name = roff_getname(r, &cp, ln, (int)(cp - *bufp));
1463 if ('\0' != *name)
1464 roff_setstr(r, name, NULL, 0);
1465 }
1466 return(ROFF_IGN);
1467 }
1468
1469 /* ARGSUSED */
1470 static enum rofferr
1471 roff_it(ROFF_ARGS)
1472 {
1473 char *cp;
1474 size_t len;
1475 int iv;
1476
1477 /* Parse the number of lines. */
1478 cp = *bufp + pos;
1479 len = strcspn(cp, " \t");
1480 cp[len] = '\0';
1481 if ((iv = mandoc_strntoi(cp, len, 10)) <= 0) {
1482 mandoc_msg(MANDOCERR_NUMERIC, r->parse,
1483 ln, ppos, *bufp + 1);
1484 return(ROFF_IGN);
1485 }
1486 cp += len + 1;
1487
1488 /* Arm the input line trap. */
1489 roffit_lines = iv;
1490 roffit_macro = mandoc_strdup(cp);
1491 return(ROFF_IGN);
1492 }
1493
1494 /* ARGSUSED */
1495 static enum rofferr
1496 roff_Dd(ROFF_ARGS)
1497 {
1498 const char *const *cp;
1499
1500 if (MPARSE_MDOC != r->parsetype)
1501 for (cp = __mdoc_reserved; *cp; cp++)
1502 roff_setstr(r, *cp, NULL, 0);
1503
1504 return(ROFF_CONT);
1505 }
1506
1507 /* ARGSUSED */
1508 static enum rofferr
1509 roff_TH(ROFF_ARGS)
1510 {
1511 const char *const *cp;
1512
1513 if (MPARSE_MDOC != r->parsetype)
1514 for (cp = __man_reserved; *cp; cp++)
1515 roff_setstr(r, *cp, NULL, 0);
1516
1517 return(ROFF_CONT);
1518 }
1519
1520 /* ARGSUSED */
1521 static enum rofferr
1522 roff_TE(ROFF_ARGS)
1523 {
1524
1525 if (NULL == r->tbl)
1526 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1527 else
1528 tbl_end(&r->tbl);
1529
1530 return(ROFF_IGN);
1531 }
1532
1533 /* ARGSUSED */
1534 static enum rofferr
1535 roff_T_(ROFF_ARGS)
1536 {
1537
1538 if (NULL == r->tbl)
1539 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1540 else
1541 tbl_restart(ppos, ln, r->tbl);
1580 roff_EQ(ROFF_ARGS)
1581 {
1582
1583 roff_openeqn(r, *bufp + pos, ln, ppos, NULL);
1584 return(ROFF_IGN);
1585 }
1586
1587 /* ARGSUSED */
1588 static enum rofferr
1589 roff_EN(ROFF_ARGS)
1590 {
1591
1592 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1593 return(ROFF_IGN);
1594 }
1595
1596 /* ARGSUSED */
1597 static enum rofferr
1598 roff_TS(ROFF_ARGS)
1599 {
1600 struct tbl_node *tbl;
1601
1602 if (r->tbl) {
1603 mandoc_msg(MANDOCERR_SCOPEBROKEN, r->parse, ln, ppos, NULL);
1604 tbl_end(&r->tbl);
1605 }
1606
1607 tbl = tbl_alloc(ppos, ln, r->parse);
1608
1609 if (r->last_tbl)
1610 r->last_tbl->next = tbl;
1611 else
1612 r->first_tbl = r->last_tbl = tbl;
1613
1614 r->tbl = r->last_tbl = tbl;
1615 return(ROFF_IGN);
1616 }
1617
1618 /* ARGSUSED */
1619 static enum rofferr
1620 roff_cc(ROFF_ARGS)
1621 {
1622 const char *p;
1623
1624 p = *bufp + pos;
1625
1626 if ('\0' == *p || '.' == (r->control = *p++))
1627 r->control = 0;
1628
1629 if ('\0' != *p)
1630 mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, ln, ppos, NULL);
1631
1632 return(ROFF_IGN);
1633 }
1634
1635 /* ARGSUSED */
1636 static enum rofferr
1637 roff_tr(ROFF_ARGS)
1638 {
1639 const char *p, *first, *second;
1640 size_t fsz, ssz;
1641 enum mandoc_esc esc;
1642
1643 p = *bufp + pos;
1644
1645 if ('\0' == *p) {
1646 mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, ln, ppos, NULL);
1647 return(ROFF_IGN);
1648 }
1649
1650 while ('\0' != *p) {
1651 fsz = ssz = 1;
1652
1653 first = p++;
1654 if ('\\' == *first) {
1655 esc = mandoc_escape(&p, NULL, NULL);
1656 if (ESCAPE_ERROR == esc) {
1715 name = *bufp + pos;
1716 if ('/' == *name || strstr(name, "../") || strstr(name, "/..")) {
1717 mandoc_msg(MANDOCERR_SOPATH, r->parse, ln, pos, NULL);
1718 return(ROFF_ERR);
1719 }
1720
1721 *offs = pos;
1722 return(ROFF_SO);
1723 }
1724
1725 /* ARGSUSED */
1726 static enum rofferr
1727 roff_userdef(ROFF_ARGS)
1728 {
1729 const char *arg[9];
1730 char *cp, *n1, *n2;
1731 int i;
1732
1733 /*
1734 * Collect pointers to macro argument strings
1735 * and NUL-terminate them.
1736 */
1737 cp = *bufp + pos;
1738 for (i = 0; i < 9; i++)
1739 arg[i] = '\0' == *cp ? "" :
1740 mandoc_getarg(r->parse, &cp, ln, &pos);
1741
1742 /*
1743 * Expand macro arguments.
1744 */
1745 *szp = 0;
1746 n1 = cp = mandoc_strdup(r->current_string);
1747 while (NULL != (cp = strstr(cp, "\\$"))) {
1748 i = cp[2] - '1';
1749 if (0 > i || 8 < i) {
1750 /* Not an argument invocation. */
1751 cp += 2;
1752 continue;
1753 }
1754
1755 *szp = strlen(n1) - 3 + strlen(arg[i]) + 1;
2010 esc = mandoc_escape(&p, NULL, NULL);
2011 if (ESCAPE_ERROR == esc) {
2012 sz = strlen(pp);
2013 res = mandoc_realloc(res, ssz + sz + 1);
2014 memcpy(res + ssz, pp, sz);
2015 break;
2016 }
2017 /*
2018 * We bail out on bad escapes.
2019 * No need to warn: we already did so when
2020 * roff_res() was called.
2021 */
2022 sz = (int)(p - pp);
2023 res = mandoc_realloc(res, ssz + sz + 1);
2024 memcpy(res + ssz, pp, sz);
2025 ssz += sz;
2026 }
2027
2028 res[(int)ssz] = '\0';
2029 return(res);
2030 }
2031
2032 /*
2033 * Find out whether a line is a macro line or not.
2034 * If it is, adjust the current position and return one; if it isn't,
2035 * return zero and don't change the current position.
2036 * If the control character has been set with `.cc', then let that grain
2037 * precedence.
2038 * This is slighly contrary to groff, where using the non-breaking
2039 * control character when `cc' has been invoked will cause the
2040 * non-breaking macro contents to be printed verbatim.
2041 */
2042 int
2043 roff_getcontrol(const struct roff *r, const char *cp, int *ppos)
2044 {
2045 int pos;
2046
2047 pos = *ppos;
2048
2049 if (0 != r->control && cp[pos] == r->control)
2050 pos++;
2051 else if (0 != r->control)
2052 return(0);
2053 else if ('\\' == cp[pos] && '.' == cp[pos + 1])
2054 pos += 2;
2055 else if ('.' == cp[pos] || '\'' == cp[pos])
2056 pos++;
2057 else
2058 return(0);
2059
2060 while (' ' == cp[pos] || '\t' == cp[pos])
2061 pos++;
2062
2063 *ppos = pos;
2064 return(1);
2065 }
|