]>
git.cameronkatri.com Git - mandoc.git/blob - roff.c
1 /* $Id: roff.c,v 1.229 2014/09/07 00:21:53 schwarze Exp $ */
3 * Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
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.
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.
20 #include <sys/types.h>
29 #include "mandoc_aux.h"
30 #include "libmandoc.h"
33 /* Maximum number of nested if-else conditionals. */
34 #define RSTACK_MAX 128
36 /* Maximum number of string expansions per line, to break infinite loops. */
37 #define EXPAND_LIMIT 1000
83 * An incredibly-simple string buffer.
86 char *p
; /* nil-terminated buffer */
87 size_t sz
; /* saved strlen(p) */
91 * A key-value roffstr pair as part of a singly-linked list.
96 struct roffkv
*next
; /* next in list */
100 * A single number register as part of a singly-linked list.
105 struct roffreg
*next
;
109 struct mparse
*parse
; /* parse point */
110 struct roffnode
*last
; /* leaf of stack */
111 int *rstack
; /* stack of inverted `ie' values */
112 struct roffreg
*regtab
; /* number registers */
113 struct roffkv
*strtab
; /* user-defined strings & macros */
114 struct roffkv
*xmbtab
; /* multi-byte trans table (`tr') */
115 struct roffstr
*xtab
; /* single-byte trans table (`tr') */
116 const char *current_string
; /* value of last called user macro */
117 struct tbl_node
*first_tbl
; /* first table parsed */
118 struct tbl_node
*last_tbl
; /* last table parsed */
119 struct tbl_node
*tbl
; /* current table being parsed */
120 struct eqn_node
*last_eqn
; /* last equation parsed */
121 struct eqn_node
*first_eqn
; /* first equation parsed */
122 struct eqn_node
*eqn
; /* current equation being parsed */
123 int options
; /* parse options */
124 int rstacksz
; /* current size limit of rstack */
125 int rstackpos
; /* position in rstack */
126 int format
; /* current file in mdoc or man format */
127 char control
; /* control character */
131 enum rofft tok
; /* type of node */
132 struct roffnode
*parent
; /* up one in stack */
133 int line
; /* parse line */
134 int col
; /* parse col */
135 char *name
; /* node name, e.g. macro name */
136 char *end
; /* end-rules: custom token */
137 int endspan
; /* end-rules: next-line or infty */
138 int rule
; /* current evaluation rule */
141 #define ROFF_ARGS struct roff *r, /* parse ctx */ \
142 enum rofft tok, /* tok of macro */ \
143 char **bufp, /* input buffer */ \
144 size_t *szp, /* size of input buffer */ \
145 int ln, /* parse line */ \
146 int ppos, /* original pos in buffer */ \
147 int pos, /* current pos in buffer */ \
148 int *offs /* reset offset of buffer data */
150 typedef enum rofferr (*roffproc
)(ROFF_ARGS
);
153 const char *name
; /* macro name */
154 roffproc proc
; /* process new macro */
155 roffproc text
; /* process as child text of macro */
156 roffproc sub
; /* process as child of macro */
158 #define ROFFMAC_STRUCT (1 << 0) /* always interpret */
159 struct roffmac
*next
;
163 const char *name
; /* predefined input name */
164 const char *str
; /* replacement symbol */
167 #define PREDEF(__name, __str) \
168 { (__name), (__str) },
170 static enum rofft
roffhash_find(const char *, size_t);
171 static void roffhash_init(void);
172 static void roffnode_cleanscope(struct roff
*);
173 static void roffnode_pop(struct roff
*);
174 static void roffnode_push(struct roff
*, enum rofft
,
175 const char *, int, int);
176 static enum rofferr
roff_block(ROFF_ARGS
);
177 static enum rofferr
roff_block_text(ROFF_ARGS
);
178 static enum rofferr
roff_block_sub(ROFF_ARGS
);
179 static enum rofferr
roff_cblock(ROFF_ARGS
);
180 static enum rofferr
roff_cc(ROFF_ARGS
);
181 static void roff_ccond(struct roff
*, int, int);
182 static enum rofferr
roff_cond(ROFF_ARGS
);
183 static enum rofferr
roff_cond_text(ROFF_ARGS
);
184 static enum rofferr
roff_cond_sub(ROFF_ARGS
);
185 static enum rofferr
roff_ds(ROFF_ARGS
);
186 static int roff_evalcond(const char *, int *);
187 static int roff_evalnum(const char *, int *, int *, int);
188 static int roff_evalpar(const char *, int *, int *);
189 static int roff_evalstrcond(const char *, int *);
190 static void roff_free1(struct roff
*);
191 static void roff_freereg(struct roffreg
*);
192 static void roff_freestr(struct roffkv
*);
193 static size_t roff_getname(struct roff
*, char **, int, int);
194 static int roff_getnum(const char *, int *, int *);
195 static int roff_getop(const char *, int *, char *);
196 static int roff_getregn(const struct roff
*,
197 const char *, size_t);
198 static int roff_getregro(const char *name
);
199 static const char *roff_getstrn(const struct roff
*,
200 const char *, size_t);
201 static enum rofferr
roff_it(ROFF_ARGS
);
202 static enum rofferr
roff_line_ignore(ROFF_ARGS
);
203 static enum rofferr
roff_nr(ROFF_ARGS
);
204 static void roff_openeqn(struct roff
*, const char *,
205 int, int, const char *);
206 static enum rofft
roff_parse(struct roff
*, char *, int *,
208 static enum rofferr
roff_parsetext(char **, size_t *, int, int *);
209 static enum rofferr
roff_res(struct roff
*,
210 char **, size_t *, int, int);
211 static enum rofferr
roff_rm(ROFF_ARGS
);
212 static enum rofferr
roff_rr(ROFF_ARGS
);
213 static void roff_setstr(struct roff
*,
214 const char *, const char *, int);
215 static void roff_setstrn(struct roffkv
**, const char *,
216 size_t, const char *, size_t, int);
217 static enum rofferr
roff_so(ROFF_ARGS
);
218 static enum rofferr
roff_tr(ROFF_ARGS
);
219 static enum rofferr
roff_Dd(ROFF_ARGS
);
220 static enum rofferr
roff_TH(ROFF_ARGS
);
221 static enum rofferr
roff_TE(ROFF_ARGS
);
222 static enum rofferr
roff_TS(ROFF_ARGS
);
223 static enum rofferr
roff_EQ(ROFF_ARGS
);
224 static enum rofferr
roff_EN(ROFF_ARGS
);
225 static enum rofferr
roff_T_(ROFF_ARGS
);
226 static enum rofferr
roff_userdef(ROFF_ARGS
);
228 /* See roffhash_find() */
232 #define HASHWIDTH (ASCII_HI - ASCII_LO + 1)
234 static struct roffmac
*hash
[HASHWIDTH
];
236 static struct roffmac roffs
[ROFF_MAX
] = {
237 { "ad", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
238 { "am", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
239 { "ami", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
240 { "am1", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
241 { "as", roff_ds
, NULL
, NULL
, 0, NULL
},
242 { "cc", roff_cc
, NULL
, NULL
, 0, NULL
},
243 { "ce", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
244 { "de", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
245 { "dei", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
246 { "de1", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
247 { "ds", roff_ds
, NULL
, NULL
, 0, NULL
},
248 { "el", roff_cond
, roff_cond_text
, roff_cond_sub
, ROFFMAC_STRUCT
, NULL
},
249 { "fam", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
250 { "hw", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
251 { "hy", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
252 { "ie", roff_cond
, roff_cond_text
, roff_cond_sub
, ROFFMAC_STRUCT
, NULL
},
253 { "if", roff_cond
, roff_cond_text
, roff_cond_sub
, ROFFMAC_STRUCT
, NULL
},
254 { "ig", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
255 { "it", roff_it
, NULL
, NULL
, 0, NULL
},
256 { "ne", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
257 { "nh", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
258 { "nr", roff_nr
, NULL
, NULL
, 0, NULL
},
259 { "ns", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
260 { "pl", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
261 { "ps", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
262 { "rm", roff_rm
, NULL
, NULL
, 0, NULL
},
263 { "rr", roff_rr
, NULL
, NULL
, 0, NULL
},
264 { "so", roff_so
, NULL
, NULL
, 0, NULL
},
265 { "ta", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
266 { "tr", roff_tr
, NULL
, NULL
, 0, NULL
},
267 { "Dd", roff_Dd
, NULL
, NULL
, 0, NULL
},
268 { "TH", roff_TH
, NULL
, NULL
, 0, NULL
},
269 { "TS", roff_TS
, NULL
, NULL
, 0, NULL
},
270 { "TE", roff_TE
, NULL
, NULL
, 0, NULL
},
271 { "T&", roff_T_
, NULL
, NULL
, 0, NULL
},
272 { "EQ", roff_EQ
, NULL
, NULL
, 0, NULL
},
273 { "EN", roff_EN
, NULL
, NULL
, 0, NULL
},
274 { ".", roff_cblock
, NULL
, NULL
, 0, NULL
},
275 { NULL
, roff_userdef
, NULL
, NULL
, 0, NULL
},
278 /* not currently implemented: Ds em Eq LP Me PP pp Or Rd Sf SH */
279 const char *const __mdoc_reserved
[] = {
280 "Ac", "Ad", "An", "Ao", "Ap", "Aq", "Ar", "At",
281 "Bc", "Bd", "Bf", "Bk", "Bl", "Bo", "Bq",
282 "Brc", "Bro", "Brq", "Bsx", "Bt", "Bx",
283 "Cd", "Cm", "Db", "Dc", "Dd", "Dl", "Do", "Dq",
284 "Dt", "Dv", "Dx", "D1",
285 "Ec", "Ed", "Ef", "Ek", "El", "Em",
286 "En", "Eo", "Er", "Es", "Ev", "Ex",
287 "Fa", "Fc", "Fd", "Fl", "Fn", "Fo", "Fr", "Ft", "Fx",
288 "Hf", "Ic", "In", "It", "Lb", "Li", "Lk", "Lp",
289 "Ms", "Mt", "Nd", "Nm", "No", "Ns", "Nx",
290 "Oc", "Oo", "Op", "Os", "Ot", "Ox",
291 "Pa", "Pc", "Pf", "Po", "Pp", "Pq",
292 "Qc", "Ql", "Qo", "Qq", "Re", "Rs", "Rv",
293 "Sc", "Sh", "Sm", "So", "Sq",
294 "Ss", "St", "Sx", "Sy",
295 "Ta", "Tn", "Ud", "Ux", "Va", "Vt", "Xc", "Xo", "Xr",
296 "%A", "%B", "%C", "%D", "%I", "%J", "%N", "%O",
297 "%P", "%Q", "%R", "%T", "%U", "%V",
301 /* not currently implemented: BT DE DS ME MT PT SY TQ YS */
302 const char *const __man_reserved
[] = {
303 "AT", "B", "BI", "BR", "DT",
304 "EE", "EN", "EQ", "EX", "HP", "I", "IB", "IP", "IR",
305 "LP", "OP", "P", "PD", "PP",
306 "R", "RB", "RE", "RI", "RS", "SB", "SH", "SM", "SS",
307 "TE", "TH", "TP", "TS", "T&", "UC", "UE", "UR",
311 /* Array of injected predefined strings. */
312 #define PREDEFS_MAX 38
313 static const struct predef predefs
[PREDEFS_MAX
] = {
314 #include "predefs.in"
317 /* See roffhash_find() */
318 #define ROFF_HASH(p) (p[0] - ASCII_LO)
320 static int roffit_lines
; /* number of lines to delay */
321 static char *roffit_macro
; /* nil-terminated macro line */
330 for (i
= 0; i
< (int)ROFF_USERDEF
; i
++) {
331 assert(roffs
[i
].name
[0] >= ASCII_LO
);
332 assert(roffs
[i
].name
[0] <= ASCII_HI
);
334 buc
= ROFF_HASH(roffs
[i
].name
);
336 if (NULL
!= (n
= hash
[buc
])) {
337 for ( ; n
->next
; n
= n
->next
)
341 hash
[buc
] = &roffs
[i
];
346 * Look up a roff token by its name. Returns ROFF_MAX if no macro by
347 * the nil-terminated string name could be found.
350 roffhash_find(const char *p
, size_t s
)
356 * libroff has an extremely simple hashtable, for the time
357 * being, which simply keys on the first character, which must
358 * be printable, then walks a chain. It works well enough until
362 if (p
[0] < ASCII_LO
|| p
[0] > ASCII_HI
)
367 if (NULL
== (n
= hash
[buc
]))
369 for ( ; n
; n
= n
->next
)
370 if (0 == strncmp(n
->name
, p
, s
) && '\0' == n
->name
[(int)s
])
371 return((enum rofft
)(n
- roffs
));
377 * Pop the current node off of the stack of roff instructions currently
381 roffnode_pop(struct roff
*r
)
388 r
->last
= r
->last
->parent
;
395 * Push a roff node onto the instruction stack. This must later be
396 * removed with roffnode_pop().
399 roffnode_push(struct roff
*r
, enum rofft tok
, const char *name
,
404 p
= mandoc_calloc(1, sizeof(struct roffnode
));
407 p
->name
= mandoc_strdup(name
);
411 p
->rule
= p
->parent
? p
->parent
->rule
: 0;
417 roff_free1(struct roff
*r
)
419 struct tbl_node
*tbl
;
423 while (NULL
!= (tbl
= r
->first_tbl
)) {
424 r
->first_tbl
= tbl
->next
;
427 r
->first_tbl
= r
->last_tbl
= r
->tbl
= NULL
;
429 while (NULL
!= (e
= r
->first_eqn
)) {
430 r
->first_eqn
= e
->next
;
433 r
->first_eqn
= r
->last_eqn
= r
->eqn
= NULL
;
443 roff_freereg(r
->regtab
);
446 roff_freestr(r
->strtab
);
447 roff_freestr(r
->xmbtab
);
448 r
->strtab
= r
->xmbtab
= NULL
;
451 for (i
= 0; i
< 128; i
++)
458 roff_reset(struct roff
*r
)
462 r
->format
= r
->options
& (MPARSE_MDOC
| MPARSE_MAN
);
467 roff_free(struct roff
*r
)
475 roff_alloc(struct mparse
*parse
, int options
)
479 r
= mandoc_calloc(1, sizeof(struct roff
));
481 r
->options
= options
;
482 r
->format
= options
& (MPARSE_MDOC
| MPARSE_MAN
);
491 * In the current line, expand escape sequences that tend to get
492 * used in numerical expressions and conditional requests.
493 * Also check the syntax of the remaining escape sequences.
496 roff_res(struct roff
*r
, char **bufp
, size_t *szp
, int ln
, int pos
)
498 char ubuf
[24]; /* buffer to print the number */
499 const char *start
; /* start of the string to process */
500 char *stesc
; /* start of an escape sequence ('\\') */
501 const char *stnam
; /* start of the name, after "[(*" */
502 const char *cp
; /* end of the name, e.g. before ']' */
503 const char *res
; /* the string to be substituted */
504 char *nbuf
; /* new buffer to copy bufp to */
505 size_t maxl
; /* expected length of the escape name */
506 size_t naml
; /* actual length of the escape name */
507 int expand_count
; /* to avoid infinite loops */
508 int npos
; /* position in numeric expression */
509 int arg_complete
; /* argument not interrupted by eol */
510 char term
; /* character terminating the escape */
514 stesc
= strchr(start
, '\0') - 1;
515 while (stesc
-- > start
) {
517 /* Search backwards for the next backslash. */
522 /* If it is escaped, skip it. */
524 for (cp
= stesc
- 1; cp
>= start
; cp
--)
528 if (0 == (stesc
- cp
) % 2) {
533 /* Decide whether to expand or to check only. */
550 if (ESCAPE_ERROR
== mandoc_escape(&cp
, NULL
, NULL
))
551 mandoc_vmsg(MANDOCERR_ESC_BAD
,
552 r
->parse
, ln
, (int)(stesc
- *bufp
),
553 "%.*s", (int)(cp
- stesc
), stesc
);
557 if (EXPAND_LIMIT
< ++expand_count
) {
558 mandoc_msg(MANDOCERR_ROFFLOOP
, r
->parse
,
559 ln
, (int)(stesc
- *bufp
), NULL
);
564 * The third character decides the length
565 * of the name of the string or register.
566 * Save a pointer to the name.
593 /* Advance to the end of the name. */
596 for (naml
= 0; 0 == maxl
|| naml
< maxl
; naml
++, cp
++) {
598 mandoc_msg(MANDOCERR_ESC_BAD
, r
->parse
,
599 ln
, (int)(stesc
- *bufp
), stesc
);
603 if (0 == maxl
&& *cp
== term
) {
610 * Retrieve the replacement string; if it is
611 * undefined, resume searching for escapes.
617 res
= roff_getstrn(r
, stnam
, naml
);
621 ubuf
[0] = arg_complete
&&
622 roff_evalnum(stnam
, &npos
, NULL
, 0) &&
623 stnam
+ npos
+ 1 == cp
? '1' : '0';
628 (void)snprintf(ubuf
, sizeof(ubuf
), "%d",
629 roff_getregn(r
, stnam
, naml
));
634 /* use even incomplete args */
635 (void)snprintf(ubuf
, sizeof(ubuf
), "%d",
641 mandoc_vmsg(MANDOCERR_STR_UNDEF
,
642 r
->parse
, ln
, (int)(stesc
- *bufp
),
643 "%.*s", (int)naml
, stnam
);
647 /* Replace the escape sequence by the string. */
650 *szp
= mandoc_asprintf(&nbuf
, "%s%s%s",
653 /* Prepare for the next replacement. */
656 stesc
= nbuf
+ (stesc
- *bufp
) + strlen(res
);
664 * Process text streams:
665 * Convert all breakable hyphens into ASCII_HYPH.
666 * Decrement and spring input line trap.
669 roff_parsetext(char **bufp
, size_t *szp
, int pos
, int *offs
)
677 start
= p
= *bufp
+ pos
;
680 sz
= strcspn(p
, "-\\");
687 /* Skip over escapes. */
689 esc
= mandoc_escape((const char **)&p
, NULL
, NULL
);
690 if (ESCAPE_ERROR
== esc
)
693 } else if (p
== start
) {
698 if (isalpha((unsigned char)p
[-1]) &&
699 isalpha((unsigned char)p
[1]))
704 /* Spring the input line trap. */
705 if (1 == roffit_lines
) {
706 isz
= mandoc_asprintf(&p
, "%s\n.%s", *bufp
, roffit_macro
);
713 return(ROFF_REPARSE
);
714 } else if (1 < roffit_lines
)
720 roff_parseln(struct roff
*r
, int ln
, char **bufp
,
721 size_t *szp
, int pos
, int *offs
)
728 * Run the reserved-word filter only if we have some reserved
732 e
= roff_res(r
, bufp
, szp
, ln
, pos
);
735 assert(ROFF_CONT
== e
);
738 ctl
= roff_getcontrol(r
, *bufp
, &pos
);
741 * First, if a scope is open and we're not a macro, pass the
742 * text through the macro's filter. If a scope isn't open and
743 * we're not a macro, just let it through.
744 * Finally, if there's an equation scope open, divert it into it
745 * no matter our state.
748 if (r
->last
&& ! ctl
) {
750 assert(roffs
[t
].text
);
751 e
= (*roffs
[t
].text
)(r
, t
, bufp
, szp
, ln
, pos
, pos
, offs
);
752 assert(ROFF_IGN
== e
|| ROFF_CONT
== e
);
757 return(eqn_read(&r
->eqn
, ln
, *bufp
, ppos
, offs
));
760 return(tbl_read(r
->tbl
, ln
, *bufp
, pos
));
761 return(roff_parsetext(bufp
, szp
, pos
, offs
));
764 /* Skip empty request lines. */
766 if ((*bufp
)[pos
] == '"') {
767 mandoc_msg(MANDOCERR_COMMENT_BAD
, r
->parse
,
770 } else if ((*bufp
)[pos
] == '\0')
774 * If a scope is open, go to the child handler for that macro,
775 * as it may want to preprocess before doing anything with it.
776 * Don't do so if an equation is open.
781 assert(roffs
[t
].sub
);
782 return((*roffs
[t
].sub
)(r
, t
, bufp
, szp
,
783 ln
, ppos
, pos
, offs
));
787 * Lastly, as we've no scope open, try to look up and execute
788 * the new macro. If no macro is found, simply return and let
789 * the compilers handle it.
792 if (ROFF_MAX
== (t
= roff_parse(r
, *bufp
, &pos
, ln
, ppos
)))
795 assert(roffs
[t
].proc
);
796 return((*roffs
[t
].proc
)(r
, t
, bufp
, szp
, ln
, ppos
, pos
, offs
));
800 roff_endparse(struct roff
*r
)
804 mandoc_msg(MANDOCERR_BLK_NOEND
, r
->parse
,
805 r
->last
->line
, r
->last
->col
,
806 roffs
[r
->last
->tok
].name
);
809 mandoc_msg(MANDOCERR_BLK_NOEND
, r
->parse
,
810 r
->eqn
->eqn
.ln
, r
->eqn
->eqn
.pos
, "EQ");
815 mandoc_msg(MANDOCERR_BLK_NOEND
, r
->parse
,
816 r
->tbl
->line
, r
->tbl
->pos
, "TS");
822 * Parse a roff node's type from the input buffer. This must be in the
823 * form of ".foo xxx" in the usual way.
826 roff_parse(struct roff
*r
, char *buf
, int *pos
, int ln
, int ppos
)
835 if ('\0' == *cp
|| '"' == *cp
|| '\t' == *cp
|| ' ' == *cp
)
839 maclen
= roff_getname(r
, &cp
, ln
, ppos
);
841 t
= (r
->current_string
= roff_getstrn(r
, mac
, maclen
))
842 ? ROFF_USERDEF
: roffhash_find(mac
, maclen
);
851 roff_cblock(ROFF_ARGS
)
855 * A block-close `..' should only be invoked as a child of an
856 * ignore macro, otherwise raise a warning and just ignore it.
859 if (NULL
== r
->last
) {
860 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
,
865 switch (r
->last
->tok
) {
867 /* ROFF_am1 is remapped to ROFF_am in roff_block(). */
872 /* ROFF_de1 is remapped to ROFF_de in roff_block(). */
879 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
,
885 mandoc_vmsg(MANDOCERR_ARG_SKIP
, r
->parse
, ln
, pos
,
886 ".. %s", *bufp
+ pos
);
889 roffnode_cleanscope(r
);
895 roffnode_cleanscope(struct roff
*r
)
899 if (--r
->last
->endspan
!= 0)
906 roff_ccond(struct roff
*r
, int ln
, int ppos
)
909 if (NULL
== r
->last
) {
910 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
,
915 switch (r
->last
->tok
) {
923 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
,
928 if (r
->last
->endspan
> -1) {
929 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
,
935 roffnode_cleanscope(r
);
940 roff_block(ROFF_ARGS
)
946 /* Ignore groff compatibility mode for now. */
950 else if (ROFF_am1
== tok
)
953 /* Parse the macro name argument. */
956 if (ROFF_ig
== tok
) {
961 namesz
= roff_getname(r
, &cp
, ln
, ppos
);
962 iname
[namesz
] = '\0';
965 /* Resolve the macro name argument if it is indirect. */
967 if (namesz
&& (ROFF_dei
== tok
|| ROFF_ami
== tok
)) {
968 if (NULL
== (name
= roff_getstrn(r
, iname
, namesz
))) {
969 mandoc_vmsg(MANDOCERR_STR_UNDEF
,
970 r
->parse
, ln
, (int)(iname
- *bufp
),
971 "%.*s", (int)namesz
, iname
);
974 namesz
= strlen(name
);
978 if (0 == namesz
&& ROFF_ig
!= tok
) {
979 mandoc_msg(MANDOCERR_REQ_EMPTY
, r
->parse
,
980 ln
, ppos
, roffs
[tok
].name
);
984 roffnode_push(r
, tok
, name
, ln
, ppos
);
987 * At the beginning of a `de' macro, clear the existing string
988 * with the same name, if there is one. New content will be
989 * appended from roff_block_text() in multiline mode.
992 if (ROFF_de
== tok
|| ROFF_dei
== tok
)
993 roff_setstrn(&r
->strtab
, name
, namesz
, "", 0, 0);
998 /* Get the custom end marker. */
1001 namesz
= roff_getname(r
, &cp
, ln
, ppos
);
1003 /* Resolve the end marker if it is indirect. */
1005 if (namesz
&& (ROFF_dei
== tok
|| ROFF_ami
== tok
)) {
1006 if (NULL
== (name
= roff_getstrn(r
, iname
, namesz
))) {
1007 mandoc_vmsg(MANDOCERR_STR_UNDEF
,
1008 r
->parse
, ln
, (int)(iname
- *bufp
),
1009 "%.*s", (int)namesz
, iname
);
1012 namesz
= strlen(name
);
1017 r
->last
->end
= mandoc_strndup(name
, namesz
);
1020 mandoc_vmsg(MANDOCERR_ARG_EXCESS
, r
->parse
,
1021 ln
, pos
, ".%s ... %s", roffs
[tok
].name
, cp
);
1027 roff_block_sub(ROFF_ARGS
)
1033 * First check whether a custom macro exists at this level. If
1034 * it does, then check against it. This is some of groff's
1035 * stranger behaviours. If we encountered a custom end-scope
1036 * tag and that tag also happens to be a "real" macro, then we
1037 * need to try interpreting it again as a real macro. If it's
1038 * not, then return ignore. Else continue.
1042 for (i
= pos
, j
= 0; r
->last
->end
[j
]; j
++, i
++)
1043 if ((*bufp
)[i
] != r
->last
->end
[j
])
1046 if ('\0' == r
->last
->end
[j
] &&
1047 ('\0' == (*bufp
)[i
] ||
1048 ' ' == (*bufp
)[i
] ||
1049 '\t' == (*bufp
)[i
])) {
1051 roffnode_cleanscope(r
);
1053 while (' ' == (*bufp
)[i
] || '\t' == (*bufp
)[i
])
1057 if (ROFF_MAX
!= roff_parse(r
, *bufp
, &pos
, ln
, ppos
))
1064 * If we have no custom end-query or lookup failed, then try
1065 * pulling it out of the hashtable.
1068 t
= roff_parse(r
, *bufp
, &pos
, ln
, ppos
);
1070 if (ROFF_cblock
!= t
) {
1072 roff_setstr(r
, r
->last
->name
, *bufp
+ ppos
, 2);
1076 assert(roffs
[t
].proc
);
1077 return((*roffs
[t
].proc
)(r
, t
, bufp
, szp
, ln
, ppos
, pos
, offs
));
1081 roff_block_text(ROFF_ARGS
)
1085 roff_setstr(r
, r
->last
->name
, *bufp
+ pos
, 2);
1091 roff_cond_sub(ROFF_ARGS
)
1098 roffnode_cleanscope(r
);
1099 t
= roff_parse(r
, *bufp
, &pos
, ln
, ppos
);
1102 * Fully handle known macros when they are structurally
1103 * required or when the conditional evaluated to true.
1106 if ((ROFF_MAX
!= t
) &&
1107 (rr
|| ROFFMAC_STRUCT
& roffs
[t
].flags
)) {
1108 assert(roffs
[t
].proc
);
1109 return((*roffs
[t
].proc
)(r
, t
, bufp
, szp
,
1110 ln
, ppos
, pos
, offs
));
1114 * If `\}' occurs on a macro line without a preceding macro,
1115 * drop the line completely.
1119 if ('\\' == ep
[0] && '}' == ep
[1])
1122 /* Always check for the closing delimiter `\}'. */
1124 while (NULL
!= (ep
= strchr(ep
, '\\'))) {
1125 if ('}' == *(++ep
)) {
1127 roff_ccond(r
, ln
, ep
- *bufp
- 1);
1131 return(rr
? ROFF_CONT
: ROFF_IGN
);
1135 roff_cond_text(ROFF_ARGS
)
1141 roffnode_cleanscope(r
);
1144 while (NULL
!= (ep
= strchr(ep
, '\\'))) {
1145 if ('}' == *(++ep
)) {
1147 roff_ccond(r
, ln
, ep
- *bufp
- 1);
1151 return(rr
? ROFF_CONT
: ROFF_IGN
);
1155 * Parse a single signed integer number. Stop at the first non-digit.
1156 * If there is at least one digit, return success and advance the
1157 * parse point, else return failure and let the parse point unchanged.
1158 * Ignore overflows, treat them just like the C language.
1161 roff_getnum(const char *v
, int *pos
, int *res
)
1173 for (*res
= 0; isdigit((unsigned char)v
[p
]); p
++)
1174 *res
= 10 * *res
+ v
[p
] - '0';
1186 * Evaluate a string comparison condition.
1187 * The first character is the delimiter.
1188 * Succeed if the string up to its second occurrence
1189 * matches the string up to its third occurence.
1190 * Advance the cursor after the third occurrence
1191 * or lacking that, to the end of the line.
1194 roff_evalstrcond(const char *v
, int *pos
)
1196 const char *s1
, *s2
, *s3
;
1200 s1
= v
+ *pos
; /* initial delimiter */
1201 s2
= s1
+ 1; /* for scanning the first string */
1202 s3
= strchr(s2
, *s1
); /* for scanning the second string */
1204 if (NULL
== s3
) /* found no middle delimiter */
1207 while ('\0' != *++s3
) {
1208 if (*s2
!= *s3
) { /* mismatch */
1209 s3
= strchr(s3
, *s1
);
1212 if (*s3
== *s1
) { /* found the final delimiter */
1221 s3
= strchr(s2
, '\0');
1229 * Evaluate an optionally negated single character, numerical,
1230 * or string condition.
1233 roff_evalcond(const char *v
, int *pos
)
1235 int wanttrue
, number
;
1237 if ('!' == v
[*pos
]) {
1264 if (roff_evalnum(v
, pos
, &number
, 0))
1265 return((number
> 0) == wanttrue
);
1267 return(roff_evalstrcond(v
, pos
) == wanttrue
);
1271 roff_line_ignore(ROFF_ARGS
)
1278 roff_cond(ROFF_ARGS
)
1281 roffnode_push(r
, tok
, NULL
, ln
, ppos
);
1284 * An `.el' has no conditional body: it will consume the value
1285 * of the current rstack entry set in prior `ie' calls or
1288 * If we're not an `el', however, then evaluate the conditional.
1291 r
->last
->rule
= ROFF_el
== tok
?
1292 (r
->rstackpos
< 0 ? 0 : r
->rstack
[r
->rstackpos
--]) :
1293 roff_evalcond(*bufp
, &pos
);
1296 * An if-else will put the NEGATION of the current evaluated
1297 * conditional into the stack of rules.
1300 if (ROFF_ie
== tok
) {
1301 if (r
->rstackpos
+ 1 == r
->rstacksz
) {
1303 r
->rstack
= mandoc_reallocarray(r
->rstack
,
1304 r
->rstacksz
, sizeof(int));
1306 r
->rstack
[++r
->rstackpos
] = !r
->last
->rule
;
1309 /* If the parent has false as its rule, then so do we. */
1311 if (r
->last
->parent
&& !r
->last
->parent
->rule
)
1316 * If there is nothing on the line after the conditional,
1317 * not even whitespace, use next-line scope.
1320 if ('\0' == (*bufp
)[pos
]) {
1321 r
->last
->endspan
= 2;
1325 while (' ' == (*bufp
)[pos
])
1328 /* An opening brace requests multiline scope. */
1330 if ('\\' == (*bufp
)[pos
] && '{' == (*bufp
)[pos
+ 1]) {
1331 r
->last
->endspan
= -1;
1337 * Anything else following the conditional causes
1338 * single-line scope. Warn if the scope contains
1339 * nothing but trailing whitespace.
1342 if ('\0' == (*bufp
)[pos
])
1343 mandoc_msg(MANDOCERR_COND_EMPTY
, r
->parse
,
1344 ln
, ppos
, roffs
[tok
].name
);
1346 r
->last
->endspan
= 1;
1361 * The first word is the name of the string.
1362 * If it is empty or terminated by an escape sequence,
1363 * abort the `ds' request without defining anything.
1366 name
= string
= *bufp
+ pos
;
1370 namesz
= roff_getname(r
, &string
, ln
, pos
);
1371 if ('\\' == name
[namesz
])
1374 /* Read past the initial double-quote, if any. */
1378 /* The rest is the value. */
1379 roff_setstrn(&r
->strtab
, name
, namesz
, string
, strlen(string
),
1385 * Parse a single operator, one or two characters long.
1386 * If the operator is recognized, return success and advance the
1387 * parse point, else return failure and let the parse point unchanged.
1390 roff_getop(const char *v
, int *pos
, char *res
)
1411 switch (v
[*pos
+ 1]) {
1429 switch (v
[*pos
+ 1]) {
1443 if ('=' == v
[*pos
+ 1])
1455 * Evaluate either a parenthesized numeric expression
1456 * or a single signed integer number.
1459 roff_evalpar(const char *v
, int *pos
, int *res
)
1463 return(roff_getnum(v
, pos
, res
));
1466 if ( ! roff_evalnum(v
, pos
, res
, 1))
1470 * Omission of the closing parenthesis
1471 * is an error in validation mode,
1472 * but ignored in evaluation mode.
1477 else if (NULL
== res
)
1484 * Evaluate a complete numeric expression.
1485 * Proceed left to right, there is no concept of precedence.
1488 roff_evalnum(const char *v
, int *pos
, int *res
, int skipwhite
)
1490 int mypos
, operand2
;
1499 while (isspace((unsigned char)v
[*pos
]))
1502 if ( ! roff_evalpar(v
, pos
, res
))
1507 while (isspace((unsigned char)v
[*pos
]))
1510 if ( ! roff_getop(v
, pos
, &operator))
1514 while (isspace((unsigned char)v
[*pos
]))
1517 if ( ! roff_evalpar(v
, pos
, &operand2
))
1521 while (isspace((unsigned char)v
[*pos
]))
1544 *res
= *res
< operand2
;
1547 *res
= *res
> operand2
;
1550 *res
= *res
<= operand2
;
1553 *res
= *res
>= operand2
;
1556 *res
= *res
== operand2
;
1559 *res
= *res
!= operand2
;
1562 *res
= *res
&& operand2
;
1565 *res
= *res
|| operand2
;
1568 if (operand2
< *res
)
1572 if (operand2
> *res
)
1583 roff_setreg(struct roff
*r
, const char *name
, int val
, char sign
)
1585 struct roffreg
*reg
;
1587 /* Search for an existing register with the same name. */
1590 while (reg
&& strcmp(name
, reg
->key
.p
))
1594 /* Create a new register. */
1595 reg
= mandoc_malloc(sizeof(struct roffreg
));
1596 reg
->key
.p
= mandoc_strdup(name
);
1597 reg
->key
.sz
= strlen(name
);
1599 reg
->next
= r
->regtab
;
1605 else if ('-' == sign
)
1612 * Handle some predefined read-only number registers.
1613 * For now, return -1 if the requested register is not predefined;
1614 * in case a predefined read-only register having the value -1
1615 * were to turn up, another special value would have to be chosen.
1618 roff_getregro(const char *name
)
1622 case 'A': /* ASCII approximation mode is always off. */
1624 case 'g': /* Groff compatibility mode is always on. */
1626 case 'H': /* Fixed horizontal resolution. */
1628 case 'j': /* Always adjust left margin only. */
1630 case 'T': /* Some output device is always defined. */
1632 case 'V': /* Fixed vertical resolution. */
1640 roff_getreg(const struct roff
*r
, const char *name
)
1642 struct roffreg
*reg
;
1645 if ('.' == name
[0] && '\0' != name
[1] && '\0' == name
[2]) {
1646 val
= roff_getregro(name
+ 1);
1651 for (reg
= r
->regtab
; reg
; reg
= reg
->next
)
1652 if (0 == strcmp(name
, reg
->key
.p
))
1659 roff_getregn(const struct roff
*r
, const char *name
, size_t len
)
1661 struct roffreg
*reg
;
1664 if ('.' == name
[0] && 2 == len
) {
1665 val
= roff_getregro(name
+ 1);
1670 for (reg
= r
->regtab
; reg
; reg
= reg
->next
)
1671 if (len
== reg
->key
.sz
&&
1672 0 == strncmp(name
, reg
->key
.p
, len
))
1679 roff_freereg(struct roffreg
*reg
)
1681 struct roffreg
*old_reg
;
1683 while (NULL
!= reg
) {
1699 key
= val
= *bufp
+ pos
;
1703 keysz
= roff_getname(r
, &val
, ln
, pos
);
1704 if ('\\' == key
[keysz
])
1709 if ('+' == sign
|| '-' == sign
)
1712 if (roff_evalnum(val
, NULL
, &iv
, 0))
1713 roff_setreg(r
, key
, iv
, sign
);
1721 struct roffreg
*reg
, **prev
;
1725 name
= cp
= *bufp
+ pos
;
1728 namesz
= roff_getname(r
, &cp
, ln
, pos
);
1729 name
[namesz
] = '\0';
1734 if (NULL
== reg
|| !strcmp(name
, reg
->key
.p
))
1754 while ('\0' != *cp
) {
1756 namesz
= roff_getname(r
, &cp
, ln
, (int)(cp
- *bufp
));
1757 roff_setstrn(&r
->strtab
, name
, namesz
, NULL
, 0, 0);
1758 if ('\\' == name
[namesz
])
1771 /* Parse the number of lines. */
1773 len
= strcspn(cp
, " \t");
1775 if ((iv
= mandoc_strntoi(cp
, len
, 10)) <= 0) {
1776 mandoc_msg(MANDOCERR_IT_NONUM
, r
->parse
,
1777 ln
, ppos
, *bufp
+ 1);
1782 /* Arm the input line trap. */
1784 roffit_macro
= mandoc_strdup(cp
);
1791 const char *const *cp
;
1793 if ((r
->options
& (MPARSE_MDOC
| MPARSE_QUICK
)) == 0)
1794 for (cp
= __mdoc_reserved
; *cp
; cp
++)
1795 roff_setstr(r
, *cp
, NULL
, 0);
1798 r
->format
= MPARSE_MDOC
;
1806 const char *const *cp
;
1808 if ((r
->options
& MPARSE_QUICK
) == 0)
1809 for (cp
= __man_reserved
; *cp
; cp
++)
1810 roff_setstr(r
, *cp
, NULL
, 0);
1813 r
->format
= MPARSE_MAN
;
1823 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
,
1836 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
,
1839 tbl_restart(ppos
, ln
, r
->tbl
);
1846 roff_closeeqn(struct roff
*r
)
1849 return(r
->eqn
&& ROFF_EQN
== eqn_end(&r
->eqn
) ? 1 : 0);
1854 roff_openeqn(struct roff
*r
, const char *name
, int line
,
1855 int offs
, const char *buf
)
1860 assert(NULL
== r
->eqn
);
1861 e
= eqn_alloc(name
, offs
, line
, r
->parse
);
1864 r
->last_eqn
->next
= e
;
1866 r
->first_eqn
= r
->last_eqn
= e
;
1868 r
->eqn
= r
->last_eqn
= e
;
1872 eqn_read(&r
->eqn
, line
, buf
, offs
, &poff
);
1880 roff_openeqn(r
, *bufp
+ pos
, ln
, ppos
, NULL
);
1888 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
, ln
, ppos
, "EN");
1895 struct tbl_node
*tbl
;
1898 mandoc_msg(MANDOCERR_BLK_BROKEN
, r
->parse
,
1899 ln
, ppos
, "TS breaks TS");
1903 tbl
= tbl_alloc(ppos
, ln
, r
->parse
);
1906 r
->last_tbl
->next
= tbl
;
1908 r
->first_tbl
= r
->last_tbl
= tbl
;
1910 r
->tbl
= r
->last_tbl
= tbl
;
1921 if ('\0' == *p
|| '.' == (r
->control
= *p
++))
1925 mandoc_msg(MANDOCERR_ARGCOUNT
, r
->parse
, ln
, ppos
, NULL
);
1933 const char *p
, *first
, *second
;
1935 enum mandoc_esc esc
;
1940 mandoc_msg(MANDOCERR_ARGCOUNT
, r
->parse
, ln
, ppos
, NULL
);
1944 while ('\0' != *p
) {
1948 if ('\\' == *first
) {
1949 esc
= mandoc_escape(&p
, NULL
, NULL
);
1950 if (ESCAPE_ERROR
== esc
) {
1951 mandoc_msg(MANDOCERR_ESC_BAD
, r
->parse
,
1952 ln
, (int)(p
- *bufp
), first
);
1955 fsz
= (size_t)(p
- first
);
1959 if ('\\' == *second
) {
1960 esc
= mandoc_escape(&p
, NULL
, NULL
);
1961 if (ESCAPE_ERROR
== esc
) {
1962 mandoc_msg(MANDOCERR_ESC_BAD
, r
->parse
,
1963 ln
, (int)(p
- *bufp
), second
);
1966 ssz
= (size_t)(p
- second
);
1967 } else if ('\0' == *second
) {
1968 mandoc_msg(MANDOCERR_ARGCOUNT
, r
->parse
,
1969 ln
, (int)(p
- *bufp
), NULL
);
1975 roff_setstrn(&r
->xmbtab
, first
, fsz
,
1980 if (NULL
== r
->xtab
)
1981 r
->xtab
= mandoc_calloc(128,
1982 sizeof(struct roffstr
));
1984 free(r
->xtab
[(int)*first
].p
);
1985 r
->xtab
[(int)*first
].p
= mandoc_strndup(second
, ssz
);
1986 r
->xtab
[(int)*first
].sz
= ssz
;
1998 mandoc_vmsg(MANDOCERR_SO
, r
->parse
, ln
, ppos
, "so %s", name
);
2001 * Handle `so'. Be EXTREMELY careful, as we shouldn't be
2002 * opening anything that's not in our cwd or anything beneath
2003 * it. Thus, explicitly disallow traversing up the file-system
2004 * or using absolute paths.
2007 if ('/' == *name
|| strstr(name
, "../") || strstr(name
, "/..")) {
2008 mandoc_vmsg(MANDOCERR_SO_PATH
, r
->parse
, ln
, ppos
,
2018 roff_userdef(ROFF_ARGS
)
2025 * Collect pointers to macro argument strings
2026 * and NUL-terminate them.
2029 for (i
= 0; i
< 9; i
++)
2030 arg
[i
] = '\0' == *cp
? "" :
2031 mandoc_getarg(r
->parse
, &cp
, ln
, &pos
);
2034 * Expand macro arguments.
2037 n1
= cp
= mandoc_strdup(r
->current_string
);
2038 while (NULL
!= (cp
= strstr(cp
, "\\$"))) {
2040 if (0 > i
|| 8 < i
) {
2041 /* Not an argument invocation. */
2046 *szp
= mandoc_asprintf(&n2
, "%s%s%s",
2047 n1
, arg
[i
], cp
+ 3) + 1;
2048 cp
= n2
+ (cp
- n1
);
2054 * Replace the macro invocation
2055 * by the expanded macro.
2060 *szp
= strlen(*bufp
) + 1;
2062 return(*szp
> 1 && '\n' == (*bufp
)[(int)*szp
- 2] ?
2063 ROFF_REPARSE
: ROFF_APPEND
);
2067 roff_getname(struct roff
*r
, char **cpp
, int ln
, int pos
)
2076 /* Read until end of name and terminate it with NUL. */
2077 for (cp
= name
; 1; cp
++) {
2078 if ('\0' == *cp
|| ' ' == *cp
) {
2085 if ('{' == cp
[1] || '}' == cp
[1])
2090 mandoc_vmsg(MANDOCERR_NAMESC
, r
->parse
, ln
, pos
,
2091 "%.*s", (int)(cp
- name
+ 1), name
);
2092 mandoc_escape((const char **)&cp
, NULL
, NULL
);
2096 /* Read past spaces. */
2105 * Store *string into the user-defined string called *name.
2106 * To clear an existing entry, call with (*r, *name, NULL, 0).
2107 * append == 0: replace mode
2108 * append == 1: single-line append mode
2109 * append == 2: multiline append mode, append '\n' after each call
2112 roff_setstr(struct roff
*r
, const char *name
, const char *string
,
2116 roff_setstrn(&r
->strtab
, name
, strlen(name
), string
,
2117 string
? strlen(string
) : 0, append
);
2121 roff_setstrn(struct roffkv
**r
, const char *name
, size_t namesz
,
2122 const char *string
, size_t stringsz
, int append
)
2127 size_t oldch
, newch
;
2129 /* Search for an existing string with the same name. */
2132 while (n
&& (namesz
!= n
->key
.sz
||
2133 strncmp(n
->key
.p
, name
, namesz
)))
2137 /* Create a new string table entry. */
2138 n
= mandoc_malloc(sizeof(struct roffkv
));
2139 n
->key
.p
= mandoc_strndup(name
, namesz
);
2145 } else if (0 == append
) {
2155 * One additional byte for the '\n' in multiline mode,
2156 * and one for the terminating '\0'.
2158 newch
= stringsz
+ (1 < append
? 2u : 1u);
2160 if (NULL
== n
->val
.p
) {
2161 n
->val
.p
= mandoc_malloc(newch
);
2166 n
->val
.p
= mandoc_realloc(n
->val
.p
, oldch
+ newch
);
2169 /* Skip existing content in the destination buffer. */
2170 c
= n
->val
.p
+ (int)oldch
;
2172 /* Append new content to the destination buffer. */
2174 while (i
< (int)stringsz
) {
2176 * Rudimentary roff copy mode:
2177 * Handle escaped backslashes.
2179 if ('\\' == string
[i
] && '\\' == string
[i
+ 1])
2184 /* Append terminating bytes. */
2189 n
->val
.sz
= (int)(c
- n
->val
.p
);
2193 roff_getstrn(const struct roff
*r
, const char *name
, size_t len
)
2195 const struct roffkv
*n
;
2198 for (n
= r
->strtab
; n
; n
= n
->next
)
2199 if (0 == strncmp(name
, n
->key
.p
, len
) &&
2200 '\0' == n
->key
.p
[(int)len
])
2203 for (i
= 0; i
< PREDEFS_MAX
; i
++)
2204 if (0 == strncmp(name
, predefs
[i
].name
, len
) &&
2205 '\0' == predefs
[i
].name
[(int)len
])
2206 return(predefs
[i
].str
);
2212 roff_freestr(struct roffkv
*r
)
2214 struct roffkv
*n
, *nn
;
2216 for (n
= r
; n
; n
= nn
) {
2224 const struct tbl_span
*
2225 roff_span(const struct roff
*r
)
2228 return(r
->tbl
? tbl_span(r
->tbl
) : NULL
);
2232 roff_eqn(const struct roff
*r
)
2235 return(r
->last_eqn
? &r
->last_eqn
->eqn
: NULL
);
2239 * Duplicate an input string, making the appropriate character
2240 * conversations (as stipulated by `tr') along the way.
2241 * Returns a heap-allocated string with all the replacements made.
2244 roff_strdup(const struct roff
*r
, const char *p
)
2246 const struct roffkv
*cp
;
2250 enum mandoc_esc esc
;
2252 if (NULL
== r
->xmbtab
&& NULL
== r
->xtab
)
2253 return(mandoc_strdup(p
));
2254 else if ('\0' == *p
)
2255 return(mandoc_strdup(""));
2258 * Step through each character looking for term matches
2259 * (remember that a `tr' can be invoked with an escape, which is
2260 * a glyph but the escape is multi-character).
2261 * We only do this if the character hash has been initialised
2262 * and the string is >0 length.
2268 while ('\0' != *p
) {
2269 if ('\\' != *p
&& r
->xtab
&& r
->xtab
[(int)*p
].p
) {
2270 sz
= r
->xtab
[(int)*p
].sz
;
2271 res
= mandoc_realloc(res
, ssz
+ sz
+ 1);
2272 memcpy(res
+ ssz
, r
->xtab
[(int)*p
].p
, sz
);
2276 } else if ('\\' != *p
) {
2277 res
= mandoc_realloc(res
, ssz
+ 2);
2282 /* Search for term matches. */
2283 for (cp
= r
->xmbtab
; cp
; cp
= cp
->next
)
2284 if (0 == strncmp(p
, cp
->key
.p
, cp
->key
.sz
))
2289 * A match has been found.
2290 * Append the match to the array and move
2291 * forward by its keysize.
2293 res
= mandoc_realloc(res
,
2294 ssz
+ cp
->val
.sz
+ 1);
2295 memcpy(res
+ ssz
, cp
->val
.p
, cp
->val
.sz
);
2297 p
+= (int)cp
->key
.sz
;
2302 * Handle escapes carefully: we need to copy
2303 * over just the escape itself, or else we might
2304 * do replacements within the escape itself.
2305 * Make sure to pass along the bogus string.
2308 esc
= mandoc_escape(&p
, NULL
, NULL
);
2309 if (ESCAPE_ERROR
== esc
) {
2311 res
= mandoc_realloc(res
, ssz
+ sz
+ 1);
2312 memcpy(res
+ ssz
, pp
, sz
);
2316 * We bail out on bad escapes.
2317 * No need to warn: we already did so when
2318 * roff_res() was called.
2321 res
= mandoc_realloc(res
, ssz
+ sz
+ 1);
2322 memcpy(res
+ ssz
, pp
, sz
);
2326 res
[(int)ssz
] = '\0';
2331 roff_getformat(const struct roff
*r
)
2338 * Find out whether a line is a macro line or not.
2339 * If it is, adjust the current position and return one; if it isn't,
2340 * return zero and don't change the current position.
2341 * If the control character has been set with `.cc', then let that grain
2343 * This is slighly contrary to groff, where using the non-breaking
2344 * control character when `cc' has been invoked will cause the
2345 * non-breaking macro contents to be printed verbatim.
2348 roff_getcontrol(const struct roff
*r
, const char *cp
, int *ppos
)
2354 if (0 != r
->control
&& cp
[pos
] == r
->control
)
2356 else if (0 != r
->control
)
2358 else if ('\\' == cp
[pos
] && '.' == cp
[pos
+ 1])
2360 else if ('.' == cp
[pos
] || '\'' == cp
[pos
])
2365 while (' ' == cp
[pos
] || '\t' == cp
[pos
])