]>
git.cameronkatri.com Git - mandoc.git/blob - roff.c
2b01f5936ffd25b784b0967724251a4b23deff56
1 /* $Id: roff.c,v 1.212 2014/06/29 22:14:10 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.
29 #include "mandoc_aux.h"
31 #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
82 * An incredibly-simple string buffer.
85 char *p
; /* nil-terminated buffer */
86 size_t sz
; /* saved strlen(p) */
90 * A key-value roffstr pair as part of a singly-linked list.
95 struct roffkv
*next
; /* next in list */
99 * A single number register as part of a singly-linked list.
104 struct roffreg
*next
;
108 struct mparse
*parse
; /* parse point */
109 int options
; /* parse options */
110 struct roffnode
*last
; /* leaf of stack */
111 int rstack
[RSTACK_MAX
]; /* stack of !`ie' rules */
112 char control
; /* control character */
113 int rstackpos
; /* position in rstack */
114 struct roffreg
*regtab
; /* number registers */
115 struct roffkv
*strtab
; /* user-defined strings & macros */
116 struct roffkv
*xmbtab
; /* multi-byte trans table (`tr') */
117 struct roffstr
*xtab
; /* single-byte trans table (`tr') */
118 const char *current_string
; /* value of last called user macro */
119 struct tbl_node
*first_tbl
; /* first table parsed */
120 struct tbl_node
*last_tbl
; /* last table parsed */
121 struct tbl_node
*tbl
; /* current table being parsed */
122 struct eqn_node
*last_eqn
; /* last equation parsed */
123 struct eqn_node
*first_eqn
; /* first equation parsed */
124 struct eqn_node
*eqn
; /* current equation being parsed */
128 enum rofft tok
; /* type of node */
129 struct roffnode
*parent
; /* up one in stack */
130 int line
; /* parse line */
131 int col
; /* parse col */
132 char *name
; /* node name, e.g. macro name */
133 char *end
; /* end-rules: custom token */
134 int endspan
; /* end-rules: next-line or infty */
135 int rule
; /* current evaluation rule */
138 #define ROFF_ARGS struct roff *r, /* parse ctx */ \
139 enum rofft tok, /* tok of macro */ \
140 char **bufp, /* input buffer */ \
141 size_t *szp, /* size of input buffer */ \
142 int ln, /* parse line */ \
143 int ppos, /* original pos in buffer */ \
144 int pos, /* current pos in buffer */ \
145 int *offs /* reset offset of buffer data */
147 typedef enum rofferr (*roffproc
)(ROFF_ARGS
);
150 const char *name
; /* macro name */
151 roffproc proc
; /* process new macro */
152 roffproc text
; /* process as child text of macro */
153 roffproc sub
; /* process as child of macro */
155 #define ROFFMAC_STRUCT (1 << 0) /* always interpret */
156 struct roffmac
*next
;
160 const char *name
; /* predefined input name */
161 const char *str
; /* replacement symbol */
164 #define PREDEF(__name, __str) \
165 { (__name), (__str) },
167 static enum rofft
roffhash_find(const char *, size_t);
168 static void roffhash_init(void);
169 static void roffnode_cleanscope(struct roff
*);
170 static void roffnode_pop(struct roff
*);
171 static void roffnode_push(struct roff
*, enum rofft
,
172 const char *, int, int);
173 static enum rofferr
roff_block(ROFF_ARGS
);
174 static enum rofferr
roff_block_text(ROFF_ARGS
);
175 static enum rofferr
roff_block_sub(ROFF_ARGS
);
176 static enum rofferr
roff_cblock(ROFF_ARGS
);
177 static enum rofferr
roff_cc(ROFF_ARGS
);
178 static void roff_ccond(struct roff
*, int, int);
179 static enum rofferr
roff_cond(ROFF_ARGS
);
180 static enum rofferr
roff_cond_text(ROFF_ARGS
);
181 static enum rofferr
roff_cond_sub(ROFF_ARGS
);
182 static enum rofferr
roff_ds(ROFF_ARGS
);
183 static int roff_evalcond(const char *, int *);
184 static int roff_evalnum(const char *, int *, int *, int);
185 static int roff_evalpar(const char *, int *, int *);
186 static int roff_evalstrcond(const char *, int *);
187 static void roff_free1(struct roff
*);
188 static void roff_freereg(struct roffreg
*);
189 static void roff_freestr(struct roffkv
*);
190 static size_t roff_getname(struct roff
*, char **, int, int);
191 static int roff_getnum(const char *, int *, int *);
192 static int roff_getop(const char *, int *, char *);
193 static int roff_getregn(const struct roff
*,
194 const char *, size_t);
195 static int roff_getregro(const char *name
);
196 static const char *roff_getstrn(const struct roff
*,
197 const char *, size_t);
198 static enum rofferr
roff_it(ROFF_ARGS
);
199 static enum rofferr
roff_line_ignore(ROFF_ARGS
);
200 static enum rofferr
roff_nr(ROFF_ARGS
);
201 static void roff_openeqn(struct roff
*, const char *,
202 int, int, const char *);
203 static enum rofft
roff_parse(struct roff
*, const char *, int *);
204 static enum rofferr
roff_parsetext(char **, size_t *, int, int *);
205 static enum rofferr
roff_res(struct roff
*,
206 char **, size_t *, int, int);
207 static enum rofferr
roff_rm(ROFF_ARGS
);
208 static enum rofferr
roff_rr(ROFF_ARGS
);
209 static void roff_setstr(struct roff
*,
210 const char *, const char *, int);
211 static void roff_setstrn(struct roffkv
**, const char *,
212 size_t, const char *, size_t, int);
213 static enum rofferr
roff_so(ROFF_ARGS
);
214 static enum rofferr
roff_tr(ROFF_ARGS
);
215 static enum rofferr
roff_Dd(ROFF_ARGS
);
216 static enum rofferr
roff_TH(ROFF_ARGS
);
217 static enum rofferr
roff_TE(ROFF_ARGS
);
218 static enum rofferr
roff_TS(ROFF_ARGS
);
219 static enum rofferr
roff_EQ(ROFF_ARGS
);
220 static enum rofferr
roff_EN(ROFF_ARGS
);
221 static enum rofferr
roff_T_(ROFF_ARGS
);
222 static enum rofferr
roff_userdef(ROFF_ARGS
);
224 /* See roffhash_find() */
228 #define HASHWIDTH (ASCII_HI - ASCII_LO + 1)
230 static struct roffmac
*hash
[HASHWIDTH
];
232 static struct roffmac roffs
[ROFF_MAX
] = {
233 { "ad", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
234 { "am", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
235 { "ami", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
236 { "am1", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
237 { "as", roff_ds
, NULL
, NULL
, 0, NULL
},
238 { "cc", roff_cc
, NULL
, NULL
, 0, NULL
},
239 { "ce", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
240 { "de", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
241 { "dei", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
242 { "de1", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
243 { "ds", roff_ds
, NULL
, NULL
, 0, NULL
},
244 { "el", roff_cond
, roff_cond_text
, roff_cond_sub
, ROFFMAC_STRUCT
, NULL
},
245 { "fam", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
246 { "hw", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
247 { "hy", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
248 { "ie", roff_cond
, roff_cond_text
, roff_cond_sub
, ROFFMAC_STRUCT
, NULL
},
249 { "if", roff_cond
, roff_cond_text
, roff_cond_sub
, ROFFMAC_STRUCT
, NULL
},
250 { "ig", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
251 { "it", roff_it
, NULL
, NULL
, 0, NULL
},
252 { "ne", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
253 { "nh", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
254 { "nr", roff_nr
, NULL
, NULL
, 0, NULL
},
255 { "ns", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
256 { "ps", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
257 { "rm", roff_rm
, NULL
, NULL
, 0, NULL
},
258 { "rr", roff_rr
, NULL
, NULL
, 0, NULL
},
259 { "so", roff_so
, NULL
, NULL
, 0, NULL
},
260 { "ta", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
261 { "tr", roff_tr
, NULL
, NULL
, 0, NULL
},
262 { "Dd", roff_Dd
, NULL
, NULL
, 0, NULL
},
263 { "TH", roff_TH
, NULL
, NULL
, 0, NULL
},
264 { "TS", roff_TS
, NULL
, NULL
, 0, NULL
},
265 { "TE", roff_TE
, NULL
, NULL
, 0, NULL
},
266 { "T&", roff_T_
, NULL
, NULL
, 0, NULL
},
267 { "EQ", roff_EQ
, NULL
, NULL
, 0, NULL
},
268 { "EN", roff_EN
, NULL
, NULL
, 0, NULL
},
269 { ".", roff_cblock
, NULL
, NULL
, 0, NULL
},
270 { NULL
, roff_userdef
, NULL
, NULL
, 0, NULL
},
273 /* not currently implemented: Ds em Eq LP Me PP pp Or Rd Sf SH */
274 const char *const __mdoc_reserved
[] = {
275 "Ac", "Ad", "An", "Ao", "Ap", "Aq", "Ar", "At",
276 "Bc", "Bd", "Bf", "Bk", "Bl", "Bo", "Bq",
277 "Brc", "Bro", "Brq", "Bsx", "Bt", "Bx",
278 "Cd", "Cm", "Db", "Dc", "Dd", "Dl", "Do", "Dq",
279 "Dt", "Dv", "Dx", "D1",
280 "Ec", "Ed", "Ef", "Ek", "El", "Em",
281 "En", "Eo", "Er", "Es", "Ev", "Ex",
282 "Fa", "Fc", "Fd", "Fl", "Fn", "Fo", "Fr", "Ft", "Fx",
283 "Hf", "Ic", "In", "It", "Lb", "Li", "Lk", "Lp",
284 "Ms", "Mt", "Nd", "Nm", "No", "Ns", "Nx",
285 "Oc", "Oo", "Op", "Os", "Ot", "Ox",
286 "Pa", "Pc", "Pf", "Po", "Pp", "Pq",
287 "Qc", "Ql", "Qo", "Qq", "Re", "Rs", "Rv",
288 "Sc", "Sh", "Sm", "So", "Sq",
289 "Ss", "St", "Sx", "Sy",
290 "Ta", "Tn", "Ud", "Ux", "Va", "Vt", "Xc", "Xo", "Xr",
291 "%A", "%B", "%C", "%D", "%I", "%J", "%N", "%O",
292 "%P", "%Q", "%R", "%T", "%U", "%V",
296 /* not currently implemented: BT DE DS ME MT PT SY TQ YS */
297 const char *const __man_reserved
[] = {
298 "AT", "B", "BI", "BR", "DT",
299 "EE", "EN", "EQ", "EX", "HP", "I", "IB", "IP", "IR",
300 "LP", "OP", "P", "PD", "PP",
301 "R", "RB", "RE", "RI", "RS", "SB", "SH", "SM", "SS",
302 "TE", "TH", "TP", "TS", "T&", "UC", "UE", "UR",
306 /* Array of injected predefined strings. */
307 #define PREDEFS_MAX 38
308 static const struct predef predefs
[PREDEFS_MAX
] = {
309 #include "predefs.in"
312 /* See roffhash_find() */
313 #define ROFF_HASH(p) (p[0] - ASCII_LO)
315 static int roffit_lines
; /* number of lines to delay */
316 static char *roffit_macro
; /* nil-terminated macro line */
325 for (i
= 0; i
< (int)ROFF_USERDEF
; i
++) {
326 assert(roffs
[i
].name
[0] >= ASCII_LO
);
327 assert(roffs
[i
].name
[0] <= ASCII_HI
);
329 buc
= ROFF_HASH(roffs
[i
].name
);
331 if (NULL
!= (n
= hash
[buc
])) {
332 for ( ; n
->next
; n
= n
->next
)
336 hash
[buc
] = &roffs
[i
];
341 * Look up a roff token by its name. Returns ROFF_MAX if no macro by
342 * the nil-terminated string name could be found.
345 roffhash_find(const char *p
, size_t s
)
351 * libroff has an extremely simple hashtable, for the time
352 * being, which simply keys on the first character, which must
353 * be printable, then walks a chain. It works well enough until
357 if (p
[0] < ASCII_LO
|| p
[0] > ASCII_HI
)
362 if (NULL
== (n
= hash
[buc
]))
364 for ( ; n
; n
= n
->next
)
365 if (0 == strncmp(n
->name
, p
, s
) && '\0' == n
->name
[(int)s
])
366 return((enum rofft
)(n
- roffs
));
372 * Pop the current node off of the stack of roff instructions currently
376 roffnode_pop(struct roff
*r
)
383 r
->last
= r
->last
->parent
;
390 * Push a roff node onto the instruction stack. This must later be
391 * removed with roffnode_pop().
394 roffnode_push(struct roff
*r
, enum rofft tok
, const char *name
,
399 p
= mandoc_calloc(1, sizeof(struct roffnode
));
402 p
->name
= mandoc_strdup(name
);
406 p
->rule
= p
->parent
? p
->parent
->rule
: 0;
412 roff_free1(struct roff
*r
)
414 struct tbl_node
*tbl
;
418 while (NULL
!= (tbl
= r
->first_tbl
)) {
419 r
->first_tbl
= tbl
->next
;
423 r
->first_tbl
= r
->last_tbl
= r
->tbl
= NULL
;
425 while (NULL
!= (e
= r
->first_eqn
)) {
426 r
->first_eqn
= e
->next
;
430 r
->first_eqn
= r
->last_eqn
= r
->eqn
= NULL
;
435 roff_freestr(r
->strtab
);
436 roff_freestr(r
->xmbtab
);
438 r
->strtab
= r
->xmbtab
= NULL
;
440 roff_freereg(r
->regtab
);
445 for (i
= 0; i
< 128; i
++)
453 roff_reset(struct roff
*r
)
461 roff_free(struct roff
*r
)
469 roff_alloc(struct mparse
*parse
, int options
)
473 r
= mandoc_calloc(1, sizeof(struct roff
));
475 r
->options
= options
;
484 * In the current line, expand escape sequences that tend to get
485 * used in numerical expressions and conditional requests.
486 * Also check the syntax of the remaining escape sequences.
489 roff_res(struct roff
*r
, char **bufp
, size_t *szp
, int ln
, int pos
)
491 char ubuf
[24]; /* buffer to print the number */
492 const char *start
; /* start of the string to process */
493 char *stesc
; /* start of an escape sequence ('\\') */
494 const char *stnam
; /* start of the name, after "[(*" */
495 const char *cp
; /* end of the name, e.g. before ']' */
496 const char *res
; /* the string to be substituted */
497 char *nbuf
; /* new buffer to copy bufp to */
498 size_t maxl
; /* expected length of the escape name */
499 size_t naml
; /* actual length of the escape name */
500 int expand_count
; /* to avoid infinite loops */
501 int npos
; /* position in numeric expression */
502 int irc
; /* return code from roff_evalnum() */
503 char term
; /* character terminating the escape */
507 stesc
= strchr(start
, '\0') - 1;
508 while (stesc
-- > start
) {
510 /* Search backwards for the next backslash. */
515 /* If it is escaped, skip it. */
517 for (cp
= stesc
- 1; cp
>= start
; cp
--)
521 if (0 == (stesc
- cp
) % 2) {
526 /* Decide whether to expand or to check only. */
543 if (ESCAPE_ERROR
== mandoc_escape(&cp
, NULL
, NULL
))
544 mandoc_msg(MANDOCERR_BADESCAPE
, r
->parse
,
545 ln
, (int)(stesc
- *bufp
), NULL
);
549 if (EXPAND_LIMIT
< ++expand_count
) {
550 mandoc_msg(MANDOCERR_ROFFLOOP
, r
->parse
,
551 ln
, (int)(stesc
- *bufp
), NULL
);
556 * The third character decides the length
557 * of the name of the string or register.
558 * Save a pointer to the name.
585 /* Advance to the end of the name. */
587 for (naml
= 0; 0 == maxl
|| naml
< maxl
; naml
++, cp
++) {
589 mandoc_msg(MANDOCERR_BADESCAPE
, r
->parse
,
590 ln
, (int)(stesc
- *bufp
), NULL
);
593 if (0 == maxl
&& *cp
== term
) {
600 * Retrieve the replacement string; if it is
601 * undefined, resume searching for escapes.
606 res
= roff_getstrn(r
, stnam
, naml
);
610 irc
= roff_evalnum(stnam
, &npos
, NULL
, 0);
611 ubuf
[0] = irc
&& stnam
+ npos
+ 1 == cp
616 (void)snprintf(ubuf
, sizeof(ubuf
), "%d",
617 roff_getregn(r
, stnam
, naml
));
620 (void)snprintf(ubuf
, sizeof(ubuf
), "%d",
626 mandoc_msg(MANDOCERR_BADESCAPE
, r
->parse
,
627 ln
, (int)(stesc
- *bufp
), NULL
);
631 /* Replace the escape sequence by the string. */
634 *szp
= mandoc_asprintf(&nbuf
, "%s%s%s",
637 /* Prepare for the next replacement. */
640 stesc
= nbuf
+ (stesc
- *bufp
) + strlen(res
);
648 * Process text streams:
649 * Convert all breakable hyphens into ASCII_HYPH.
650 * Decrement and spring input line trap.
653 roff_parsetext(char **bufp
, size_t *szp
, int pos
, int *offs
)
661 start
= p
= *bufp
+ pos
;
664 sz
= strcspn(p
, "-\\");
671 /* Skip over escapes. */
673 esc
= mandoc_escape((const char **)&p
, NULL
, NULL
);
674 if (ESCAPE_ERROR
== esc
)
677 } else if (p
== start
) {
682 if (isalpha((unsigned char)p
[-1]) &&
683 isalpha((unsigned char)p
[1]))
688 /* Spring the input line trap. */
689 if (1 == roffit_lines
) {
690 isz
= mandoc_asprintf(&p
, "%s\n.%s", *bufp
, roffit_macro
);
697 return(ROFF_REPARSE
);
698 } else if (1 < roffit_lines
)
704 roff_parseln(struct roff
*r
, int ln
, char **bufp
,
705 size_t *szp
, int pos
, int *offs
)
712 * Run the reserved-word filter only if we have some reserved
716 e
= roff_res(r
, bufp
, szp
, ln
, pos
);
719 assert(ROFF_CONT
== e
);
722 ctl
= roff_getcontrol(r
, *bufp
, &pos
);
725 * First, if a scope is open and we're not a macro, pass the
726 * text through the macro's filter. If a scope isn't open and
727 * we're not a macro, just let it through.
728 * Finally, if there's an equation scope open, divert it into it
729 * no matter our state.
732 if (r
->last
&& ! ctl
) {
734 assert(roffs
[t
].text
);
735 e
= (*roffs
[t
].text
)(r
, t
, bufp
, szp
, ln
, pos
, pos
, offs
);
736 assert(ROFF_IGN
== e
|| ROFF_CONT
== e
);
741 return(eqn_read(&r
->eqn
, ln
, *bufp
, ppos
, offs
));
744 return(tbl_read(r
->tbl
, ln
, *bufp
, pos
));
745 return(roff_parsetext(bufp
, szp
, pos
, offs
));
749 * If a scope is open, go to the child handler for that macro,
750 * as it may want to preprocess before doing anything with it.
751 * Don't do so if an equation is open.
756 assert(roffs
[t
].sub
);
757 return((*roffs
[t
].sub
)(r
, t
, bufp
, szp
,
758 ln
, ppos
, pos
, offs
));
762 * Lastly, as we've no scope open, try to look up and execute
763 * the new macro. If no macro is found, simply return and let
764 * the compilers handle it.
767 if (ROFF_MAX
== (t
= roff_parse(r
, *bufp
, &pos
)))
770 assert(roffs
[t
].proc
);
771 return((*roffs
[t
].proc
)(r
, t
, bufp
, szp
, ln
, ppos
, pos
, offs
));
775 roff_endparse(struct roff
*r
)
779 mandoc_msg(MANDOCERR_SCOPEEXIT
, r
->parse
,
780 r
->last
->line
, r
->last
->col
, NULL
);
783 mandoc_msg(MANDOCERR_SCOPEEXIT
, r
->parse
,
784 r
->eqn
->eqn
.ln
, r
->eqn
->eqn
.pos
, NULL
);
789 mandoc_msg(MANDOCERR_SCOPEEXIT
, r
->parse
,
790 r
->tbl
->line
, r
->tbl
->pos
, NULL
);
796 * Parse a roff node's type from the input buffer. This must be in the
797 * form of ".foo xxx" in the usual way.
800 roff_parse(struct roff
*r
, const char *buf
, int *pos
)
806 if ('\0' == buf
[*pos
] || '"' == buf
[*pos
] ||
807 '\t' == buf
[*pos
] || ' ' == buf
[*pos
])
810 /* We stop the macro parse at an escape, tab, space, or nil. */
813 maclen
= strcspn(mac
, " \\\t\0");
815 t
= (r
->current_string
= roff_getstrn(r
, mac
, maclen
))
816 ? ROFF_USERDEF
: roffhash_find(mac
, maclen
);
820 while (buf
[*pos
] && ' ' == buf
[*pos
])
827 roff_cblock(ROFF_ARGS
)
831 * A block-close `..' should only be invoked as a child of an
832 * ignore macro, otherwise raise a warning and just ignore it.
835 if (NULL
== r
->last
) {
836 mandoc_msg(MANDOCERR_NOSCOPE
, r
->parse
, ln
, ppos
, NULL
);
840 switch (r
->last
->tok
) {
848 /* ROFF_de1 is remapped to ROFF_de in roff_block(). */
855 mandoc_msg(MANDOCERR_NOSCOPE
, r
->parse
, ln
, ppos
, NULL
);
860 mandoc_msg(MANDOCERR_ARGSLOST
, r
->parse
, ln
, pos
, NULL
);
863 roffnode_cleanscope(r
);
869 roffnode_cleanscope(struct roff
*r
)
873 if (--r
->last
->endspan
!= 0)
880 roff_ccond(struct roff
*r
, int ln
, int ppos
)
883 if (NULL
== r
->last
) {
884 mandoc_msg(MANDOCERR_NOSCOPE
, r
->parse
, ln
, ppos
, NULL
);
888 switch (r
->last
->tok
) {
896 mandoc_msg(MANDOCERR_NOSCOPE
, r
->parse
, ln
, ppos
, NULL
);
900 if (r
->last
->endspan
> -1) {
901 mandoc_msg(MANDOCERR_NOSCOPE
, r
->parse
, ln
, ppos
, NULL
);
906 roffnode_cleanscope(r
);
911 roff_block(ROFF_ARGS
)
919 if (ROFF_ig
!= tok
) {
920 if ('\0' == (*bufp
)[pos
]) {
921 mandoc_msg(MANDOCERR_NOARGS
, r
->parse
, ln
, ppos
, NULL
);
926 * Re-write `de1', since we don't really care about
927 * groff's strange compatibility mode, into `de'.
935 mandoc_msg(MANDOCERR_REQUEST
, r
->parse
, ln
, ppos
,
938 while ((*bufp
)[pos
] && ! isspace((unsigned char)(*bufp
)[pos
]))
941 while (isspace((unsigned char)(*bufp
)[pos
]))
942 (*bufp
)[pos
++] = '\0';
945 roffnode_push(r
, tok
, name
, ln
, ppos
);
948 * At the beginning of a `de' macro, clear the existing string
949 * with the same name, if there is one. New content will be
950 * appended from roff_block_text() in multiline mode.
954 roff_setstr(r
, name
, "", 0);
956 if ('\0' == (*bufp
)[pos
])
959 /* If present, process the custom end-of-line marker. */
962 while ((*bufp
)[pos
] && ! isspace((unsigned char)(*bufp
)[pos
]))
966 * Note: groff does NOT like escape characters in the input.
967 * Instead of detecting this, we're just going to let it fly and
972 sz
= (size_t)(pos
- sv
);
974 if (1 == sz
&& '.' == (*bufp
)[sv
])
977 r
->last
->end
= mandoc_malloc(sz
+ 1);
979 memcpy(r
->last
->end
, *bufp
+ sv
, sz
);
980 r
->last
->end
[(int)sz
] = '\0';
983 mandoc_msg(MANDOCERR_ARGSLOST
, r
->parse
, ln
, pos
, NULL
);
989 roff_block_sub(ROFF_ARGS
)
995 * First check whether a custom macro exists at this level. If
996 * it does, then check against it. This is some of groff's
997 * stranger behaviours. If we encountered a custom end-scope
998 * tag and that tag also happens to be a "real" macro, then we
999 * need to try interpreting it again as a real macro. If it's
1000 * not, then return ignore. Else continue.
1004 for (i
= pos
, j
= 0; r
->last
->end
[j
]; j
++, i
++)
1005 if ((*bufp
)[i
] != r
->last
->end
[j
])
1008 if ('\0' == r
->last
->end
[j
] &&
1009 ('\0' == (*bufp
)[i
] ||
1010 ' ' == (*bufp
)[i
] ||
1011 '\t' == (*bufp
)[i
])) {
1013 roffnode_cleanscope(r
);
1015 while (' ' == (*bufp
)[i
] || '\t' == (*bufp
)[i
])
1019 if (ROFF_MAX
!= roff_parse(r
, *bufp
, &pos
))
1026 * If we have no custom end-query or lookup failed, then try
1027 * pulling it out of the hashtable.
1030 t
= roff_parse(r
, *bufp
, &pos
);
1033 * Macros other than block-end are only significant
1034 * in `de' blocks; elsewhere, simply throw them away.
1036 if (ROFF_cblock
!= t
) {
1038 roff_setstr(r
, r
->last
->name
, *bufp
+ ppos
, 2);
1042 assert(roffs
[t
].proc
);
1043 return((*roffs
[t
].proc
)(r
, t
, bufp
, szp
, ln
, ppos
, pos
, offs
));
1047 roff_block_text(ROFF_ARGS
)
1051 roff_setstr(r
, r
->last
->name
, *bufp
+ pos
, 2);
1057 roff_cond_sub(ROFF_ARGS
)
1064 roffnode_cleanscope(r
);
1065 t
= roff_parse(r
, *bufp
, &pos
);
1068 * Fully handle known macros when they are structurally
1069 * required or when the conditional evaluated to true.
1072 if ((ROFF_MAX
!= t
) &&
1073 (rr
|| ROFFMAC_STRUCT
& roffs
[t
].flags
)) {
1074 assert(roffs
[t
].proc
);
1075 return((*roffs
[t
].proc
)(r
, t
, bufp
, szp
,
1076 ln
, ppos
, pos
, offs
));
1080 * If `\}' occurs on a macro line without a preceding macro,
1081 * drop the line completely.
1085 if ('\\' == ep
[0] && '}' == ep
[1])
1088 /* Always check for the closing delimiter `\}'. */
1090 while (NULL
!= (ep
= strchr(ep
, '\\'))) {
1091 if ('}' == *(++ep
)) {
1093 roff_ccond(r
, ln
, ep
- *bufp
- 1);
1097 return(rr
? ROFF_CONT
: ROFF_IGN
);
1101 roff_cond_text(ROFF_ARGS
)
1107 roffnode_cleanscope(r
);
1110 while (NULL
!= (ep
= strchr(ep
, '\\'))) {
1111 if ('}' == *(++ep
)) {
1113 roff_ccond(r
, ln
, ep
- *bufp
- 1);
1117 return(rr
? ROFF_CONT
: ROFF_IGN
);
1121 * Parse a single signed integer number. Stop at the first non-digit.
1122 * If there is at least one digit, return success and advance the
1123 * parse point, else return failure and let the parse point unchanged.
1124 * Ignore overflows, treat them just like the C language.
1127 roff_getnum(const char *v
, int *pos
, int *res
)
1139 for (*res
= 0; isdigit((unsigned char)v
[p
]); p
++)
1140 *res
= 10 * *res
+ v
[p
] - '0';
1152 * Evaluate a string comparison condition.
1153 * The first character is the delimiter.
1154 * Succeed if the string up to its second occurrence
1155 * matches the string up to its third occurence.
1156 * Advance the cursor after the third occurrence
1157 * or lacking that, to the end of the line.
1160 roff_evalstrcond(const char *v
, int *pos
)
1162 const char *s1
, *s2
, *s3
;
1166 s1
= v
+ *pos
; /* initial delimiter */
1167 s2
= s1
+ 1; /* for scanning the first string */
1168 s3
= strchr(s2
, *s1
); /* for scanning the second string */
1170 if (NULL
== s3
) /* found no middle delimiter */
1173 while ('\0' != *++s3
) {
1174 if (*s2
!= *s3
) { /* mismatch */
1175 s3
= strchr(s3
, *s1
);
1178 if (*s3
== *s1
) { /* found the final delimiter */
1187 s3
= strchr(s2
, '\0');
1195 * Evaluate an optionally negated single character, numerical,
1196 * or string condition.
1199 roff_evalcond(const char *v
, int *pos
)
1201 int wanttrue
, number
;
1203 if ('!' == v
[*pos
]) {
1230 if (roff_evalnum(v
, pos
, &number
, 0))
1231 return((number
> 0) == wanttrue
);
1233 return(roff_evalstrcond(v
, pos
) == wanttrue
);
1237 roff_line_ignore(ROFF_ARGS
)
1244 roff_cond(ROFF_ARGS
)
1247 roffnode_push(r
, tok
, NULL
, ln
, ppos
);
1250 * An `.el' has no conditional body: it will consume the value
1251 * of the current rstack entry set in prior `ie' calls or
1254 * If we're not an `el', however, then evaluate the conditional.
1257 r
->last
->rule
= ROFF_el
== tok
?
1258 (r
->rstackpos
< 0 ? 0 : r
->rstack
[r
->rstackpos
--]) :
1259 roff_evalcond(*bufp
, &pos
);
1262 * An if-else will put the NEGATION of the current evaluated
1263 * conditional into the stack of rules.
1266 if (ROFF_ie
== tok
) {
1267 if (r
->rstackpos
== RSTACK_MAX
- 1) {
1268 mandoc_msg(MANDOCERR_MEM
,
1269 r
->parse
, ln
, ppos
, NULL
);
1272 r
->rstack
[++r
->rstackpos
] = !r
->last
->rule
;
1275 /* If the parent has false as its rule, then so do we. */
1277 if (r
->last
->parent
&& !r
->last
->parent
->rule
)
1282 * If there is nothing on the line after the conditional,
1283 * not even whitespace, use next-line scope.
1286 if ('\0' == (*bufp
)[pos
]) {
1287 r
->last
->endspan
= 2;
1291 while (' ' == (*bufp
)[pos
])
1294 /* An opening brace requests multiline scope. */
1296 if ('\\' == (*bufp
)[pos
] && '{' == (*bufp
)[pos
+ 1]) {
1297 r
->last
->endspan
= -1;
1303 * Anything else following the conditional causes
1304 * single-line scope. Warn if the scope contains
1305 * nothing but trailing whitespace.
1308 if ('\0' == (*bufp
)[pos
])
1309 mandoc_msg(MANDOCERR_NOARGS
, r
->parse
, ln
, ppos
, NULL
);
1311 r
->last
->endspan
= 1;
1326 * The first word is the name of the string.
1327 * If it is empty or terminated by an escape sequence,
1328 * abort the `ds' request without defining anything.
1331 name
= string
= *bufp
+ pos
;
1335 namesz
= roff_getname(r
, &string
, ln
, pos
);
1336 if ('\\' == name
[namesz
])
1339 /* Read past the initial double-quote, if any. */
1343 /* The rest is the value. */
1344 roff_setstrn(&r
->strtab
, name
, namesz
, string
, strlen(string
),
1350 * Parse a single operator, one or two characters long.
1351 * If the operator is recognized, return success and advance the
1352 * parse point, else return failure and let the parse point unchanged.
1355 roff_getop(const char *v
, int *pos
, char *res
)
1376 switch (v
[*pos
+ 1]) {
1394 switch (v
[*pos
+ 1]) {
1408 if ('=' == v
[*pos
+ 1])
1420 * Evaluate either a parenthesized numeric expression
1421 * or a single signed integer number.
1424 roff_evalpar(const char *v
, int *pos
, int *res
)
1428 return(roff_getnum(v
, pos
, res
));
1431 if ( ! roff_evalnum(v
, pos
, res
, 1))
1435 * Omission of the closing parenthesis
1436 * is an error in validation mode,
1437 * but ignored in evaluation mode.
1442 else if (NULL
== res
)
1449 * Evaluate a complete numeric expression.
1450 * Proceed left to right, there is no concept of precedence.
1453 roff_evalnum(const char *v
, int *pos
, int *res
, int skipwhite
)
1455 int mypos
, operand2
;
1464 while (isspace((unsigned char)v
[*pos
]))
1467 if ( ! roff_evalpar(v
, pos
, res
))
1472 while (isspace((unsigned char)v
[*pos
]))
1475 if ( ! roff_getop(v
, pos
, &operator))
1479 while (isspace((unsigned char)v
[*pos
]))
1482 if ( ! roff_evalpar(v
, pos
, &operand2
))
1486 while (isspace((unsigned char)v
[*pos
]))
1509 *res
= *res
< operand2
;
1512 *res
= *res
> operand2
;
1515 *res
= *res
<= operand2
;
1518 *res
= *res
>= operand2
;
1521 *res
= *res
== operand2
;
1524 *res
= *res
!= operand2
;
1527 *res
= *res
&& operand2
;
1530 *res
= *res
|| operand2
;
1533 if (operand2
< *res
)
1537 if (operand2
> *res
)
1548 roff_setreg(struct roff
*r
, const char *name
, int val
, char sign
)
1550 struct roffreg
*reg
;
1552 /* Search for an existing register with the same name. */
1555 while (reg
&& strcmp(name
, reg
->key
.p
))
1559 /* Create a new register. */
1560 reg
= mandoc_malloc(sizeof(struct roffreg
));
1561 reg
->key
.p
= mandoc_strdup(name
);
1562 reg
->key
.sz
= strlen(name
);
1564 reg
->next
= r
->regtab
;
1570 else if ('-' == sign
)
1577 * Handle some predefined read-only number registers.
1578 * For now, return -1 if the requested register is not predefined;
1579 * in case a predefined read-only register having the value -1
1580 * were to turn up, another special value would have to be chosen.
1583 roff_getregro(const char *name
)
1587 case 'A': /* ASCII approximation mode is always off. */
1589 case 'g': /* Groff compatibility mode is always on. */
1591 case 'H': /* Fixed horizontal resolution. */
1593 case 'j': /* Always adjust left margin only. */
1595 case 'T': /* Some output device is always defined. */
1597 case 'V': /* Fixed vertical resolution. */
1605 roff_getreg(const struct roff
*r
, const char *name
)
1607 struct roffreg
*reg
;
1610 if ('.' == name
[0] && '\0' != name
[1] && '\0' == name
[2]) {
1611 val
= roff_getregro(name
+ 1);
1616 for (reg
= r
->regtab
; reg
; reg
= reg
->next
)
1617 if (0 == strcmp(name
, reg
->key
.p
))
1624 roff_getregn(const struct roff
*r
, const char *name
, size_t len
)
1626 struct roffreg
*reg
;
1629 if ('.' == name
[0] && 2 == len
) {
1630 val
= roff_getregro(name
+ 1);
1635 for (reg
= r
->regtab
; reg
; reg
= reg
->next
)
1636 if (len
== reg
->key
.sz
&&
1637 0 == strncmp(name
, reg
->key
.p
, len
))
1644 roff_freereg(struct roffreg
*reg
)
1646 struct roffreg
*old_reg
;
1648 while (NULL
!= reg
) {
1664 key
= val
= *bufp
+ pos
;
1668 keysz
= roff_getname(r
, &val
, ln
, pos
);
1669 if ('\\' == key
[keysz
])
1674 if ('+' == sign
|| '-' == sign
)
1677 if (roff_evalnum(val
, NULL
, &iv
, 0))
1678 roff_setreg(r
, key
, iv
, sign
);
1686 struct roffreg
*reg
, **prev
;
1690 name
= cp
= *bufp
+ pos
;
1693 namesz
= roff_getname(r
, &cp
, ln
, pos
);
1694 name
[namesz
] = '\0';
1699 if (NULL
== reg
|| !strcmp(name
, reg
->key
.p
))
1719 while ('\0' != *cp
) {
1721 namesz
= roff_getname(r
, &cp
, ln
, (int)(cp
- *bufp
));
1722 roff_setstrn(&r
->strtab
, name
, namesz
, NULL
, 0, 0);
1723 if ('\\' == name
[namesz
])
1736 /* Parse the number of lines. */
1738 len
= strcspn(cp
, " \t");
1740 if ((iv
= mandoc_strntoi(cp
, len
, 10)) <= 0) {
1741 mandoc_msg(MANDOCERR_NUMERIC
, r
->parse
,
1742 ln
, ppos
, *bufp
+ 1);
1747 /* Arm the input line trap. */
1749 roffit_macro
= mandoc_strdup(cp
);
1756 const char *const *cp
;
1758 if (0 == ((MPARSE_MDOC
| MPARSE_QUICK
) & r
->options
))
1759 for (cp
= __mdoc_reserved
; *cp
; cp
++)
1760 roff_setstr(r
, *cp
, NULL
, 0);
1768 const char *const *cp
;
1770 if (0 == (MPARSE_QUICK
& r
->options
))
1771 for (cp
= __man_reserved
; *cp
; cp
++)
1772 roff_setstr(r
, *cp
, NULL
, 0);
1782 mandoc_msg(MANDOCERR_NOSCOPE
, r
->parse
, ln
, ppos
, NULL
);
1794 mandoc_msg(MANDOCERR_NOSCOPE
, r
->parse
, ln
, ppos
, NULL
);
1796 tbl_restart(ppos
, ln
, r
->tbl
);
1803 roff_closeeqn(struct roff
*r
)
1806 return(r
->eqn
&& ROFF_EQN
== eqn_end(&r
->eqn
) ? 1 : 0);
1811 roff_openeqn(struct roff
*r
, const char *name
, int line
,
1812 int offs
, const char *buf
)
1817 assert(NULL
== r
->eqn
);
1818 e
= eqn_alloc(name
, offs
, line
, r
->parse
);
1821 r
->last_eqn
->next
= e
;
1823 r
->first_eqn
= r
->last_eqn
= e
;
1825 r
->eqn
= r
->last_eqn
= e
;
1829 eqn_read(&r
->eqn
, line
, buf
, offs
, &poff
);
1837 roff_openeqn(r
, *bufp
+ pos
, ln
, ppos
, NULL
);
1845 mandoc_msg(MANDOCERR_NOSCOPE
, r
->parse
, ln
, ppos
, NULL
);
1852 struct tbl_node
*tbl
;
1855 mandoc_msg(MANDOCERR_SCOPEBROKEN
, r
->parse
, ln
, ppos
, NULL
);
1859 tbl
= tbl_alloc(ppos
, ln
, r
->parse
);
1862 r
->last_tbl
->next
= tbl
;
1864 r
->first_tbl
= r
->last_tbl
= tbl
;
1866 r
->tbl
= r
->last_tbl
= tbl
;
1877 if ('\0' == *p
|| '.' == (r
->control
= *p
++))
1881 mandoc_msg(MANDOCERR_ARGCOUNT
, r
->parse
, ln
, ppos
, NULL
);
1889 const char *p
, *first
, *second
;
1891 enum mandoc_esc esc
;
1896 mandoc_msg(MANDOCERR_ARGCOUNT
, r
->parse
, ln
, ppos
, NULL
);
1900 while ('\0' != *p
) {
1904 if ('\\' == *first
) {
1905 esc
= mandoc_escape(&p
, NULL
, NULL
);
1906 if (ESCAPE_ERROR
== esc
) {
1907 mandoc_msg(MANDOCERR_BADESCAPE
,
1909 (int)(p
- *bufp
), NULL
);
1912 fsz
= (size_t)(p
- first
);
1916 if ('\\' == *second
) {
1917 esc
= mandoc_escape(&p
, NULL
, NULL
);
1918 if (ESCAPE_ERROR
== esc
) {
1919 mandoc_msg(MANDOCERR_BADESCAPE
,
1921 (int)(p
- *bufp
), NULL
);
1924 ssz
= (size_t)(p
- second
);
1925 } else if ('\0' == *second
) {
1926 mandoc_msg(MANDOCERR_ARGCOUNT
, r
->parse
,
1927 ln
, (int)(p
- *bufp
), NULL
);
1933 roff_setstrn(&r
->xmbtab
, first
, fsz
,
1938 if (NULL
== r
->xtab
)
1939 r
->xtab
= mandoc_calloc(128,
1940 sizeof(struct roffstr
));
1942 free(r
->xtab
[(int)*first
].p
);
1943 r
->xtab
[(int)*first
].p
= mandoc_strndup(second
, ssz
);
1944 r
->xtab
[(int)*first
].sz
= ssz
;
1956 mandoc_vmsg(MANDOCERR_SO
, r
->parse
, ln
, ppos
, ".so %s", name
);
1959 * Handle `so'. Be EXTREMELY careful, as we shouldn't be
1960 * opening anything that's not in our cwd or anything beneath
1961 * it. Thus, explicitly disallow traversing up the file-system
1962 * or using absolute paths.
1965 if ('/' == *name
|| strstr(name
, "../") || strstr(name
, "/..")) {
1966 mandoc_vmsg(MANDOCERR_SO_PATH
, r
->parse
, ln
, ppos
,
1976 roff_userdef(ROFF_ARGS
)
1983 * Collect pointers to macro argument strings
1984 * and NUL-terminate them.
1987 for (i
= 0; i
< 9; i
++)
1988 arg
[i
] = '\0' == *cp
? "" :
1989 mandoc_getarg(r
->parse
, &cp
, ln
, &pos
);
1992 * Expand macro arguments.
1995 n1
= cp
= mandoc_strdup(r
->current_string
);
1996 while (NULL
!= (cp
= strstr(cp
, "\\$"))) {
1998 if (0 > i
|| 8 < i
) {
1999 /* Not an argument invocation. */
2004 *szp
= mandoc_asprintf(&n2
, "%s%s%s",
2005 n1
, arg
[i
], cp
+ 3) + 1;
2006 cp
= n2
+ (cp
- n1
);
2012 * Replace the macro invocation
2013 * by the expanded macro.
2018 *szp
= strlen(*bufp
) + 1;
2020 return(*szp
> 1 && '\n' == (*bufp
)[(int)*szp
- 2] ?
2021 ROFF_REPARSE
: ROFF_APPEND
);
2025 roff_getname(struct roff
*r
, char **cpp
, int ln
, int pos
)
2034 /* Read until end of name and terminate it with NUL. */
2035 for (cp
= name
; 1; cp
++) {
2036 if ('\0' == *cp
|| ' ' == *cp
) {
2045 namesz
= cp
- name
- 1;
2046 mandoc_msg(MANDOCERR_NAMESC
, r
->parse
, ln
, pos
, NULL
);
2047 mandoc_escape((const char **)&cp
, NULL
, NULL
);
2051 /* Read past spaces. */
2060 * Store *string into the user-defined string called *name.
2061 * To clear an existing entry, call with (*r, *name, NULL, 0).
2062 * append == 0: replace mode
2063 * append == 1: single-line append mode
2064 * append == 2: multiline append mode, append '\n' after each call
2067 roff_setstr(struct roff
*r
, const char *name
, const char *string
,
2071 roff_setstrn(&r
->strtab
, name
, strlen(name
), string
,
2072 string
? strlen(string
) : 0, append
);
2076 roff_setstrn(struct roffkv
**r
, const char *name
, size_t namesz
,
2077 const char *string
, size_t stringsz
, int append
)
2082 size_t oldch
, newch
;
2084 /* Search for an existing string with the same name. */
2087 while (n
&& (namesz
!= n
->key
.sz
||
2088 strncmp(n
->key
.p
, name
, namesz
)))
2092 /* Create a new string table entry. */
2093 n
= mandoc_malloc(sizeof(struct roffkv
));
2094 n
->key
.p
= mandoc_strndup(name
, namesz
);
2100 } else if (0 == append
) {
2110 * One additional byte for the '\n' in multiline mode,
2111 * and one for the terminating '\0'.
2113 newch
= stringsz
+ (1 < append
? 2u : 1u);
2115 if (NULL
== n
->val
.p
) {
2116 n
->val
.p
= mandoc_malloc(newch
);
2121 n
->val
.p
= mandoc_realloc(n
->val
.p
, oldch
+ newch
);
2124 /* Skip existing content in the destination buffer. */
2125 c
= n
->val
.p
+ (int)oldch
;
2127 /* Append new content to the destination buffer. */
2129 while (i
< (int)stringsz
) {
2131 * Rudimentary roff copy mode:
2132 * Handle escaped backslashes.
2134 if ('\\' == string
[i
] && '\\' == string
[i
+ 1])
2139 /* Append terminating bytes. */
2144 n
->val
.sz
= (int)(c
- n
->val
.p
);
2148 roff_getstrn(const struct roff
*r
, const char *name
, size_t len
)
2150 const struct roffkv
*n
;
2153 for (n
= r
->strtab
; n
; n
= n
->next
)
2154 if (0 == strncmp(name
, n
->key
.p
, len
) &&
2155 '\0' == n
->key
.p
[(int)len
])
2158 for (i
= 0; i
< PREDEFS_MAX
; i
++)
2159 if (0 == strncmp(name
, predefs
[i
].name
, len
) &&
2160 '\0' == predefs
[i
].name
[(int)len
])
2161 return(predefs
[i
].str
);
2167 roff_freestr(struct roffkv
*r
)
2169 struct roffkv
*n
, *nn
;
2171 for (n
= r
; n
; n
= nn
) {
2179 const struct tbl_span
*
2180 roff_span(const struct roff
*r
)
2183 return(r
->tbl
? tbl_span(r
->tbl
) : NULL
);
2187 roff_eqn(const struct roff
*r
)
2190 return(r
->last_eqn
? &r
->last_eqn
->eqn
: NULL
);
2194 * Duplicate an input string, making the appropriate character
2195 * conversations (as stipulated by `tr') along the way.
2196 * Returns a heap-allocated string with all the replacements made.
2199 roff_strdup(const struct roff
*r
, const char *p
)
2201 const struct roffkv
*cp
;
2205 enum mandoc_esc esc
;
2207 if (NULL
== r
->xmbtab
&& NULL
== r
->xtab
)
2208 return(mandoc_strdup(p
));
2209 else if ('\0' == *p
)
2210 return(mandoc_strdup(""));
2213 * Step through each character looking for term matches
2214 * (remember that a `tr' can be invoked with an escape, which is
2215 * a glyph but the escape is multi-character).
2216 * We only do this if the character hash has been initialised
2217 * and the string is >0 length.
2223 while ('\0' != *p
) {
2224 if ('\\' != *p
&& r
->xtab
&& r
->xtab
[(int)*p
].p
) {
2225 sz
= r
->xtab
[(int)*p
].sz
;
2226 res
= mandoc_realloc(res
, ssz
+ sz
+ 1);
2227 memcpy(res
+ ssz
, r
->xtab
[(int)*p
].p
, sz
);
2231 } else if ('\\' != *p
) {
2232 res
= mandoc_realloc(res
, ssz
+ 2);
2237 /* Search for term matches. */
2238 for (cp
= r
->xmbtab
; cp
; cp
= cp
->next
)
2239 if (0 == strncmp(p
, cp
->key
.p
, cp
->key
.sz
))
2244 * A match has been found.
2245 * Append the match to the array and move
2246 * forward by its keysize.
2248 res
= mandoc_realloc(res
,
2249 ssz
+ cp
->val
.sz
+ 1);
2250 memcpy(res
+ ssz
, cp
->val
.p
, cp
->val
.sz
);
2252 p
+= (int)cp
->key
.sz
;
2257 * Handle escapes carefully: we need to copy
2258 * over just the escape itself, or else we might
2259 * do replacements within the escape itself.
2260 * Make sure to pass along the bogus string.
2263 esc
= mandoc_escape(&p
, NULL
, NULL
);
2264 if (ESCAPE_ERROR
== esc
) {
2266 res
= mandoc_realloc(res
, ssz
+ sz
+ 1);
2267 memcpy(res
+ ssz
, pp
, sz
);
2271 * We bail out on bad escapes.
2272 * No need to warn: we already did so when
2273 * roff_res() was called.
2276 res
= mandoc_realloc(res
, ssz
+ sz
+ 1);
2277 memcpy(res
+ ssz
, pp
, sz
);
2281 res
[(int)ssz
] = '\0';
2286 * Find out whether a line is a macro line or not.
2287 * If it is, adjust the current position and return one; if it isn't,
2288 * return zero and don't change the current position.
2289 * If the control character has been set with `.cc', then let that grain
2291 * This is slighly contrary to groff, where using the non-breaking
2292 * control character when `cc' has been invoked will cause the
2293 * non-breaking macro contents to be printed verbatim.
2296 roff_getcontrol(const struct roff
*r
, const char *cp
, int *ppos
)
2302 if (0 != r
->control
&& cp
[pos
] == r
->control
)
2304 else if (0 != r
->control
)
2306 else if ('\\' == cp
[pos
] && '.' == cp
[pos
+ 1])
2308 else if ('.' == cp
[pos
] || '\'' == cp
[pos
])
2313 while (' ' == cp
[pos
] || '\t' == cp
[pos
])