]>
git.cameronkatri.com Git - mandoc.git/blob - roff.c
1 /* $Id: roff.c,v 1.206 2014/04/08 01:37:27 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 char *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 */
324 for (i
= 0; i
< (int)ROFF_USERDEF
; i
++) {
325 assert(roffs
[i
].name
[0] >= ASCII_LO
);
326 assert(roffs
[i
].name
[0] <= ASCII_HI
);
328 buc
= ROFF_HASH(roffs
[i
].name
);
330 if (NULL
!= (n
= hash
[buc
])) {
331 for ( ; n
->next
; n
= n
->next
)
335 hash
[buc
] = &roffs
[i
];
340 * Look up a roff token by its name. Returns ROFF_MAX if no macro by
341 * the nil-terminated string name could be found.
344 roffhash_find(const char *p
, size_t s
)
350 * libroff has an extremely simple hashtable, for the time
351 * being, which simply keys on the first character, which must
352 * be printable, then walks a chain. It works well enough until
356 if (p
[0] < ASCII_LO
|| p
[0] > ASCII_HI
)
361 if (NULL
== (n
= hash
[buc
]))
363 for ( ; n
; n
= n
->next
)
364 if (0 == strncmp(n
->name
, p
, s
) && '\0' == n
->name
[(int)s
])
365 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
;
391 * Push a roff node onto the instruction stack. This must later be
392 * removed with roffnode_pop().
395 roffnode_push(struct roff
*r
, enum rofft tok
, const char *name
,
400 p
= mandoc_calloc(1, sizeof(struct roffnode
));
403 p
->name
= mandoc_strdup(name
);
407 p
->rule
= p
->parent
? p
->parent
->rule
: 0;
414 roff_free1(struct roff
*r
)
416 struct tbl_node
*tbl
;
420 while (NULL
!= (tbl
= r
->first_tbl
)) {
421 r
->first_tbl
= tbl
->next
;
425 r
->first_tbl
= r
->last_tbl
= r
->tbl
= NULL
;
427 while (NULL
!= (e
= r
->first_eqn
)) {
428 r
->first_eqn
= e
->next
;
432 r
->first_eqn
= r
->last_eqn
= r
->eqn
= NULL
;
437 roff_freestr(r
->strtab
);
438 roff_freestr(r
->xmbtab
);
440 r
->strtab
= r
->xmbtab
= NULL
;
442 roff_freereg(r
->regtab
);
447 for (i
= 0; i
< 128; i
++)
455 roff_reset(struct roff
*r
)
464 roff_free(struct roff
*r
)
473 roff_alloc(struct mparse
*parse
, int options
)
477 r
= mandoc_calloc(1, sizeof(struct roff
));
479 r
->options
= options
;
488 * In the current line, expand escape sequences that tend to get
489 * used in numerical expressions and conditional requests.
490 * Also check the syntax of the remaining escape sequences.
493 roff_res(struct roff
*r
, char **bufp
, size_t *szp
, int ln
, int pos
)
495 char ubuf
[12]; /* buffer to print the number */
496 const char *start
; /* start of the string to process */
497 const char *stesc
; /* start of an escape sequence ('\\') */
498 const char *stnam
; /* start of the name, after "[(*" */
499 const char *cp
; /* end of the name, e.g. before ']' */
500 const char *res
; /* the string to be substituted */
501 char *nbuf
; /* new buffer to copy bufp to */
502 size_t maxl
; /* expected length of the escape name */
503 size_t naml
; /* actual length of the escape name */
504 size_t ressz
; /* size of the replacement string */
505 int expand_count
; /* to avoid infinite loops */
506 int npos
; /* position in numeric expression */
507 int irc
; /* return code from roff_evalnum() */
508 char term
; /* character terminating the escape */
512 stesc
= strchr(start
, '\0') - 1;
513 while (stesc
-- > start
) {
515 /* Search backwards for the next backslash. */
520 /* If it is escaped, skip it. */
522 for (cp
= stesc
- 1; cp
>= start
; cp
--)
526 if (0 == (stesc
- cp
) % 2) {
531 /* Decide whether to expand or to check only. */
548 if (ESCAPE_ERROR
== mandoc_escape(&cp
, NULL
, NULL
))
549 mandoc_msg(MANDOCERR_BADESCAPE
, r
->parse
,
550 ln
, (int)(stesc
- *bufp
), NULL
);
554 if (EXPAND_LIMIT
< ++expand_count
) {
555 mandoc_msg(MANDOCERR_ROFFLOOP
, r
->parse
,
556 ln
, (int)(stesc
- *bufp
), NULL
);
561 * The third character decides the length
562 * of the name of the string or register.
563 * Save a pointer to the name.
590 /* Advance to the end of the name. */
592 for (naml
= 0; 0 == maxl
|| naml
< maxl
; naml
++, cp
++) {
595 (MANDOCERR_BADESCAPE
,
597 (int)(stesc
- *bufp
), NULL
);
600 if (0 == maxl
&& *cp
== term
) {
607 * Retrieve the replacement string; if it is
608 * undefined, resume searching for escapes.
613 res
= roff_getstrn(r
, stnam
, naml
);
617 irc
= roff_evalnum(stnam
, &npos
, NULL
, 0);
618 ubuf
[0] = irc
&& stnam
+ npos
+ 1 == cp
623 snprintf(ubuf
, sizeof(ubuf
), "%d",
624 roff_getregn(r
, stnam
, naml
));
627 snprintf(ubuf
, sizeof(ubuf
), "%d",
634 (MANDOCERR_BADESCAPE
, r
->parse
,
635 ln
, (int)(stesc
- *bufp
), NULL
);
640 /* Replace the escape sequence by the string. */
643 nbuf
= mandoc_malloc(*szp
);
645 strlcpy(nbuf
, *bufp
, (size_t)(stesc
- *bufp
+ 1));
646 strlcat(nbuf
, res
, *szp
);
647 strlcat(nbuf
, cp
, *szp
);
649 /* Prepare for the next replacement. */
652 stesc
= nbuf
+ (stesc
- *bufp
) + ressz
;
660 * Process text streams:
661 * Convert all breakable hyphens into ASCII_HYPH.
662 * Decrement and spring input line trap.
665 roff_parsetext(char **bufp
, size_t *szp
, int pos
, int *offs
)
673 start
= p
= *bufp
+ pos
;
676 sz
= strcspn(p
, "-\\");
683 /* Skip over escapes. */
685 esc
= mandoc_escape((const char **)&p
, NULL
, NULL
);
686 if (ESCAPE_ERROR
== esc
)
689 } else if (p
== start
) {
694 if (isalpha((unsigned char)p
[-1]) &&
695 isalpha((unsigned char)p
[1]))
700 /* Spring the input line trap. */
701 if (1 == roffit_lines
) {
702 isz
= mandoc_asprintf(&p
, "%s\n.%s", *bufp
, roffit_macro
);
709 return(ROFF_REPARSE
);
710 } else if (1 < roffit_lines
)
716 roff_parseln(struct roff
*r
, int ln
, char **bufp
,
717 size_t *szp
, int pos
, int *offs
)
724 * Run the reserved-word filter only if we have some reserved
728 e
= roff_res(r
, bufp
, szp
, ln
, pos
);
731 assert(ROFF_CONT
== e
);
734 ctl
= roff_getcontrol(r
, *bufp
, &pos
);
737 * First, if a scope is open and we're not a macro, pass the
738 * text through the macro's filter. If a scope isn't open and
739 * we're not a macro, just let it through.
740 * Finally, if there's an equation scope open, divert it into it
741 * no matter our state.
744 if (r
->last
&& ! ctl
) {
746 assert(roffs
[t
].text
);
748 (r
, t
, bufp
, szp
, ln
, pos
, pos
, offs
);
749 assert(ROFF_IGN
== e
|| ROFF_CONT
== e
);
754 return(eqn_read(&r
->eqn
, ln
, *bufp
, ppos
, offs
));
757 return(tbl_read(r
->tbl
, ln
, *bufp
, pos
));
758 return(roff_parsetext(bufp
, szp
, pos
, offs
));
762 * If a scope is open, go to the child handler for that macro,
763 * as it may want to preprocess before doing anything with it.
764 * Don't do so if an equation is open.
769 assert(roffs
[t
].sub
);
770 return((*roffs
[t
].sub
)
772 ln
, ppos
, pos
, offs
));
776 * Lastly, as we've no scope open, try to look up and execute
777 * the new macro. If no macro is found, simply return and let
778 * the compilers handle it.
781 if (ROFF_MAX
== (t
= roff_parse(r
, *bufp
, &pos
)))
784 assert(roffs
[t
].proc
);
785 return((*roffs
[t
].proc
)
787 ln
, ppos
, pos
, offs
));
792 roff_endparse(struct roff
*r
)
796 mandoc_msg(MANDOCERR_SCOPEEXIT
, r
->parse
,
797 r
->last
->line
, r
->last
->col
, NULL
);
800 mandoc_msg(MANDOCERR_SCOPEEXIT
, r
->parse
,
801 r
->eqn
->eqn
.ln
, r
->eqn
->eqn
.pos
, NULL
);
806 mandoc_msg(MANDOCERR_SCOPEEXIT
, r
->parse
,
807 r
->tbl
->line
, r
->tbl
->pos
, NULL
);
813 * Parse a roff node's type from the input buffer. This must be in the
814 * form of ".foo xxx" in the usual way.
817 roff_parse(struct roff
*r
, const char *buf
, int *pos
)
823 if ('\0' == buf
[*pos
] || '"' == buf
[*pos
] ||
824 '\t' == buf
[*pos
] || ' ' == buf
[*pos
])
827 /* We stop the macro parse at an escape, tab, space, or nil. */
830 maclen
= strcspn(mac
, " \\\t\0");
832 t
= (r
->current_string
= roff_getstrn(r
, mac
, maclen
))
833 ? ROFF_USERDEF
: roffhash_find(mac
, maclen
);
837 while (buf
[*pos
] && ' ' == buf
[*pos
])
845 roff_cblock(ROFF_ARGS
)
849 * A block-close `..' should only be invoked as a child of an
850 * ignore macro, otherwise raise a warning and just ignore it.
853 if (NULL
== r
->last
) {
854 mandoc_msg(MANDOCERR_NOSCOPE
, r
->parse
, ln
, ppos
, NULL
);
858 switch (r
->last
->tok
) {
866 /* ROFF_de1 is remapped to ROFF_de in roff_block(). */
873 mandoc_msg(MANDOCERR_NOSCOPE
, r
->parse
, ln
, ppos
, NULL
);
878 mandoc_msg(MANDOCERR_ARGSLOST
, r
->parse
, ln
, pos
, NULL
);
881 roffnode_cleanscope(r
);
888 roffnode_cleanscope(struct roff
*r
)
892 if (--r
->last
->endspan
!= 0)
900 roff_ccond(struct roff
*r
, int ln
, int ppos
)
903 if (NULL
== r
->last
) {
904 mandoc_msg(MANDOCERR_NOSCOPE
, r
->parse
, ln
, ppos
, NULL
);
908 switch (r
->last
->tok
) {
916 mandoc_msg(MANDOCERR_NOSCOPE
, r
->parse
, ln
, ppos
, NULL
);
920 if (r
->last
->endspan
> -1) {
921 mandoc_msg(MANDOCERR_NOSCOPE
, r
->parse
, ln
, ppos
, NULL
);
926 roffnode_cleanscope(r
);
933 roff_block(ROFF_ARGS
)
941 if (ROFF_ig
!= tok
) {
942 if ('\0' == (*bufp
)[pos
]) {
943 mandoc_msg(MANDOCERR_NOARGS
, r
->parse
, ln
, ppos
, NULL
);
948 * Re-write `de1', since we don't really care about
949 * groff's strange compatibility mode, into `de'.
957 mandoc_msg(MANDOCERR_REQUEST
, r
->parse
, ln
, ppos
,
960 while ((*bufp
)[pos
] && ! isspace((unsigned char)(*bufp
)[pos
]))
963 while (isspace((unsigned char)(*bufp
)[pos
]))
964 (*bufp
)[pos
++] = '\0';
967 roffnode_push(r
, tok
, name
, ln
, ppos
);
970 * At the beginning of a `de' macro, clear the existing string
971 * with the same name, if there is one. New content will be
972 * appended from roff_block_text() in multiline mode.
976 roff_setstr(r
, name
, "", 0);
978 if ('\0' == (*bufp
)[pos
])
981 /* If present, process the custom end-of-line marker. */
984 while ((*bufp
)[pos
] && ! isspace((unsigned char)(*bufp
)[pos
]))
988 * Note: groff does NOT like escape characters in the input.
989 * Instead of detecting this, we're just going to let it fly and
994 sz
= (size_t)(pos
- sv
);
996 if (1 == sz
&& '.' == (*bufp
)[sv
])
999 r
->last
->end
= mandoc_malloc(sz
+ 1);
1001 memcpy(r
->last
->end
, *bufp
+ sv
, sz
);
1002 r
->last
->end
[(int)sz
] = '\0';
1005 mandoc_msg(MANDOCERR_ARGSLOST
, r
->parse
, ln
, pos
, NULL
);
1013 roff_block_sub(ROFF_ARGS
)
1019 * First check whether a custom macro exists at this level. If
1020 * it does, then check against it. This is some of groff's
1021 * stranger behaviours. If we encountered a custom end-scope
1022 * tag and that tag also happens to be a "real" macro, then we
1023 * need to try interpreting it again as a real macro. If it's
1024 * not, then return ignore. Else continue.
1028 for (i
= pos
, j
= 0; r
->last
->end
[j
]; j
++, i
++)
1029 if ((*bufp
)[i
] != r
->last
->end
[j
])
1032 if ('\0' == r
->last
->end
[j
] &&
1033 ('\0' == (*bufp
)[i
] ||
1034 ' ' == (*bufp
)[i
] ||
1035 '\t' == (*bufp
)[i
])) {
1037 roffnode_cleanscope(r
);
1039 while (' ' == (*bufp
)[i
] || '\t' == (*bufp
)[i
])
1043 if (ROFF_MAX
!= roff_parse(r
, *bufp
, &pos
))
1050 * If we have no custom end-query or lookup failed, then try
1051 * pulling it out of the hashtable.
1054 t
= roff_parse(r
, *bufp
, &pos
);
1057 * Macros other than block-end are only significant
1058 * in `de' blocks; elsewhere, simply throw them away.
1060 if (ROFF_cblock
!= t
) {
1062 roff_setstr(r
, r
->last
->name
, *bufp
+ ppos
, 2);
1066 assert(roffs
[t
].proc
);
1067 return((*roffs
[t
].proc
)(r
, t
, bufp
, szp
,
1068 ln
, ppos
, pos
, offs
));
1074 roff_block_text(ROFF_ARGS
)
1078 roff_setstr(r
, r
->last
->name
, *bufp
+ pos
, 2);
1086 roff_cond_sub(ROFF_ARGS
)
1093 roffnode_cleanscope(r
);
1094 t
= roff_parse(r
, *bufp
, &pos
);
1097 * Fully handle known macros when they are structurally
1098 * required or when the conditional evaluated to true.
1101 if ((ROFF_MAX
!= t
) &&
1102 (rr
|| ROFFMAC_STRUCT
& roffs
[t
].flags
)) {
1103 assert(roffs
[t
].proc
);
1104 return((*roffs
[t
].proc
)(r
, t
, bufp
, szp
,
1105 ln
, ppos
, pos
, offs
));
1109 * If `\}' occurs on a macro line without a preceding macro,
1110 * drop the line completely.
1114 if ('\\' == ep
[0] && '}' == ep
[1])
1117 /* Always check for the closing delimiter `\}'. */
1119 while (NULL
!= (ep
= strchr(ep
, '\\'))) {
1120 if ('}' == *(++ep
)) {
1122 roff_ccond(r
, ln
, ep
- *bufp
- 1);
1126 return(rr
? ROFF_CONT
: ROFF_IGN
);
1131 roff_cond_text(ROFF_ARGS
)
1137 roffnode_cleanscope(r
);
1140 while (NULL
!= (ep
= strchr(ep
, '\\'))) {
1141 if ('}' == *(++ep
)) {
1143 roff_ccond(r
, ln
, ep
- *bufp
- 1);
1147 return(rr
? ROFF_CONT
: ROFF_IGN
);
1151 * Parse a single signed integer number. Stop at the first non-digit.
1152 * If there is at least one digit, return success and advance the
1153 * parse point, else return failure and let the parse point unchanged.
1154 * Ignore overflows, treat them just like the C language.
1157 roff_getnum(const char *v
, int *pos
, int *res
)
1169 for (*res
= 0; isdigit((unsigned char)v
[p
]); p
++)
1170 *res
= 10 * *res
+ v
[p
] - '0';
1182 * Evaluate a string comparison condition.
1183 * The first character is the delimiter.
1184 * Succeed if the string up to its second occurrence
1185 * matches the string up to its third occurence.
1186 * Advance the cursor after the third occurrence
1187 * or lacking that, to the end of the line.
1190 roff_evalstrcond(const char *v
, int *pos
)
1192 const char *s1
, *s2
, *s3
;
1196 s1
= v
+ *pos
; /* initial delimiter */
1197 s2
= s1
+ 1; /* for scanning the first string */
1198 s3
= strchr(s2
, *s1
); /* for scanning the second string */
1200 if (NULL
== s3
) /* found no middle delimiter */
1203 while ('\0' != *++s3
) {
1204 if (*s2
!= *s3
) { /* mismatch */
1205 s3
= strchr(s3
, *s1
);
1208 if (*s3
== *s1
) { /* found the final delimiter */
1217 s3
= strchr(s2
, '\0');
1225 * Evaluate an optionally negated single character, numerical,
1226 * or string condition.
1229 roff_evalcond(const char *v
, int *pos
)
1231 int wanttrue
, number
;
1233 if ('!' == v
[*pos
]) {
1260 if (roff_evalnum(v
, pos
, &number
, 0))
1261 return((number
> 0) == wanttrue
);
1263 return(roff_evalstrcond(v
, pos
) == wanttrue
);
1268 roff_line_ignore(ROFF_ARGS
)
1276 roff_cond(ROFF_ARGS
)
1279 roffnode_push(r
, tok
, NULL
, ln
, ppos
);
1282 * An `.el' has no conditional body: it will consume the value
1283 * of the current rstack entry set in prior `ie' calls or
1286 * If we're not an `el', however, then evaluate the conditional.
1289 r
->last
->rule
= ROFF_el
== tok
?
1290 (r
->rstackpos
< 0 ? 0 : r
->rstack
[r
->rstackpos
--]) :
1291 roff_evalcond(*bufp
, &pos
);
1294 * An if-else will put the NEGATION of the current evaluated
1295 * conditional into the stack of rules.
1298 if (ROFF_ie
== tok
) {
1299 if (r
->rstackpos
== RSTACK_MAX
- 1) {
1300 mandoc_msg(MANDOCERR_MEM
,
1301 r
->parse
, ln
, ppos
, NULL
);
1304 r
->rstack
[++r
->rstackpos
] = !r
->last
->rule
;
1307 /* If the parent has false as its rule, then so do we. */
1309 if (r
->last
->parent
&& !r
->last
->parent
->rule
)
1314 * If there is nothing on the line after the conditional,
1315 * not even whitespace, use next-line scope.
1318 if ('\0' == (*bufp
)[pos
]) {
1319 r
->last
->endspan
= 2;
1323 while (' ' == (*bufp
)[pos
])
1326 /* An opening brace requests multiline scope. */
1328 if ('\\' == (*bufp
)[pos
] && '{' == (*bufp
)[pos
+ 1]) {
1329 r
->last
->endspan
= -1;
1335 * Anything else following the conditional causes
1336 * single-line scope. Warn if the scope contains
1337 * nothing but trailing whitespace.
1340 if ('\0' == (*bufp
)[pos
])
1341 mandoc_msg(MANDOCERR_NOARGS
, r
->parse
, ln
, ppos
, NULL
);
1343 r
->last
->endspan
= 1;
1355 char *name
, *string
;
1358 * A symbol is named by the first word following the macro
1359 * invocation up to a space. Its value is anything after the
1360 * name's trailing whitespace and optional double-quote. Thus,
1364 * will have `bar " ' as its value.
1367 string
= *bufp
+ pos
;
1368 name
= roff_getname(r
, &string
, ln
, pos
);
1372 /* Read past initial double-quote. */
1376 /* The rest is the value. */
1377 roff_setstr(r
, name
, string
, ROFF_as
== tok
);
1382 * Parse a single operator, one or two characters long.
1383 * If the operator is recognized, return success and advance the
1384 * parse point, else return failure and let the parse point unchanged.
1387 roff_getop(const char *v
, int *pos
, char *res
)
1408 switch (v
[*pos
+ 1]) {
1426 switch (v
[*pos
+ 1]) {
1440 if ('=' == v
[*pos
+ 1])
1452 * Evaluate either a parenthesized numeric expression
1453 * or a single signed integer number.
1456 roff_evalpar(const char *v
, int *pos
, int *res
)
1460 return(roff_getnum(v
, pos
, res
));
1463 if ( ! roff_evalnum(v
, pos
, res
, 1))
1467 * Omission of the closing parenthesis
1468 * is an error in validation mode,
1469 * but ignored in evaluation mode.
1474 else if (NULL
== res
)
1481 * Evaluate a complete numeric expression.
1482 * Proceed left to right, there is no concept of precedence.
1485 roff_evalnum(const char *v
, int *pos
, int *res
, int skipwhite
)
1487 int mypos
, operand2
;
1496 while (isspace((unsigned char)v
[*pos
]))
1499 if ( ! roff_evalpar(v
, pos
, res
))
1504 while (isspace((unsigned char)v
[*pos
]))
1507 if ( ! roff_getop(v
, pos
, &operator))
1511 while (isspace((unsigned char)v
[*pos
]))
1514 if ( ! roff_evalpar(v
, pos
, &operand2
))
1518 while (isspace((unsigned char)v
[*pos
]))
1541 *res
= *res
< operand2
;
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 if (operand2
< *res
)
1569 if (operand2
> *res
)
1580 roff_setreg(struct roff
*r
, const char *name
, int val
, char sign
)
1582 struct roffreg
*reg
;
1584 /* Search for an existing register with the same name. */
1587 while (reg
&& strcmp(name
, reg
->key
.p
))
1591 /* Create a new register. */
1592 reg
= mandoc_malloc(sizeof(struct roffreg
));
1593 reg
->key
.p
= mandoc_strdup(name
);
1594 reg
->key
.sz
= strlen(name
);
1596 reg
->next
= r
->regtab
;
1602 else if ('-' == sign
)
1609 * Handle some predefined read-only number registers.
1610 * For now, return -1 if the requested register is not predefined;
1611 * in case a predefined read-only register having the value -1
1612 * were to turn up, another special value would have to be chosen.
1615 roff_getregro(const char *name
)
1619 case ('A'): /* ASCII approximation mode is always off. */
1621 case ('g'): /* Groff compatibility mode is always on. */
1623 case ('H'): /* Fixed horizontal resolution. */
1625 case ('j'): /* Always adjust left margin only. */
1627 case ('T'): /* Some output device is always defined. */
1629 case ('V'): /* Fixed vertical resolution. */
1637 roff_getreg(const struct roff
*r
, const char *name
)
1639 struct roffreg
*reg
;
1642 if ('.' == name
[0] && '\0' != name
[1] && '\0' == name
[2]) {
1643 val
= roff_getregro(name
+ 1);
1648 for (reg
= r
->regtab
; reg
; reg
= reg
->next
)
1649 if (0 == strcmp(name
, reg
->key
.p
))
1656 roff_getregn(const struct roff
*r
, const char *name
, size_t len
)
1658 struct roffreg
*reg
;
1661 if ('.' == name
[0] && 2 == len
) {
1662 val
= roff_getregro(name
+ 1);
1667 for (reg
= r
->regtab
; reg
; reg
= reg
->next
)
1668 if (len
== reg
->key
.sz
&&
1669 0 == strncmp(name
, reg
->key
.p
, len
))
1676 roff_freereg(struct roffreg
*reg
)
1678 struct roffreg
*old_reg
;
1680 while (NULL
!= reg
) {
1697 key
= roff_getname(r
, &val
, ln
, pos
);
1700 if ('+' == sign
|| '-' == sign
)
1703 if (roff_evalnum(val
, NULL
, &iv
, 0))
1704 roff_setreg(r
, key
, iv
, sign
);
1712 struct roffreg
*reg
, **prev
;
1717 name
= roff_getname(r
, &cp
, ln
, pos
);
1722 if (NULL
== reg
|| !strcmp(name
, reg
->key
.p
))
1742 while ('\0' != *cp
) {
1743 name
= roff_getname(r
, &cp
, ln
, (int)(cp
- *bufp
));
1745 roff_setstr(r
, name
, NULL
, 0);
1758 /* Parse the number of lines. */
1760 len
= strcspn(cp
, " \t");
1762 if ((iv
= mandoc_strntoi(cp
, len
, 10)) <= 0) {
1763 mandoc_msg(MANDOCERR_NUMERIC
, r
->parse
,
1764 ln
, ppos
, *bufp
+ 1);
1769 /* Arm the input line trap. */
1771 roffit_macro
= mandoc_strdup(cp
);
1779 const char *const *cp
;
1781 if (0 == ((MPARSE_MDOC
| MPARSE_QUICK
) & r
->options
))
1782 for (cp
= __mdoc_reserved
; *cp
; cp
++)
1783 roff_setstr(r
, *cp
, NULL
, 0);
1792 const char *const *cp
;
1794 if (0 == (MPARSE_QUICK
& r
->options
))
1795 for (cp
= __man_reserved
; *cp
; cp
++)
1796 roff_setstr(r
, *cp
, NULL
, 0);
1807 mandoc_msg(MANDOCERR_NOSCOPE
, r
->parse
, ln
, ppos
, NULL
);
1820 mandoc_msg(MANDOCERR_NOSCOPE
, r
->parse
, ln
, ppos
, NULL
);
1822 tbl_restart(ppos
, ln
, r
->tbl
);
1829 roff_closeeqn(struct roff
*r
)
1832 return(r
->eqn
&& ROFF_EQN
== eqn_end(&r
->eqn
) ? 1 : 0);
1837 roff_openeqn(struct roff
*r
, const char *name
, int line
,
1838 int offs
, const char *buf
)
1843 assert(NULL
== r
->eqn
);
1844 e
= eqn_alloc(name
, offs
, line
, r
->parse
);
1847 r
->last_eqn
->next
= e
;
1849 r
->first_eqn
= r
->last_eqn
= e
;
1851 r
->eqn
= r
->last_eqn
= e
;
1855 eqn_read(&r
->eqn
, line
, buf
, offs
, &poff
);
1864 roff_openeqn(r
, *bufp
+ pos
, ln
, ppos
, NULL
);
1873 mandoc_msg(MANDOCERR_NOSCOPE
, r
->parse
, ln
, ppos
, NULL
);
1881 struct tbl_node
*tbl
;
1884 mandoc_msg(MANDOCERR_SCOPEBROKEN
, r
->parse
, ln
, ppos
, NULL
);
1888 tbl
= tbl_alloc(ppos
, ln
, r
->parse
);
1891 r
->last_tbl
->next
= tbl
;
1893 r
->first_tbl
= r
->last_tbl
= tbl
;
1895 r
->tbl
= r
->last_tbl
= tbl
;
1907 if ('\0' == *p
|| '.' == (r
->control
= *p
++))
1911 mandoc_msg(MANDOCERR_ARGCOUNT
, r
->parse
, ln
, ppos
, NULL
);
1920 const char *p
, *first
, *second
;
1922 enum mandoc_esc esc
;
1927 mandoc_msg(MANDOCERR_ARGCOUNT
, r
->parse
, ln
, ppos
, NULL
);
1931 while ('\0' != *p
) {
1935 if ('\\' == *first
) {
1936 esc
= mandoc_escape(&p
, NULL
, NULL
);
1937 if (ESCAPE_ERROR
== esc
) {
1939 (MANDOCERR_BADESCAPE
, r
->parse
,
1940 ln
, (int)(p
- *bufp
), NULL
);
1943 fsz
= (size_t)(p
- first
);
1947 if ('\\' == *second
) {
1948 esc
= mandoc_escape(&p
, NULL
, NULL
);
1949 if (ESCAPE_ERROR
== esc
) {
1951 (MANDOCERR_BADESCAPE
, r
->parse
,
1952 ln
, (int)(p
- *bufp
), NULL
);
1955 ssz
= (size_t)(p
- second
);
1956 } else if ('\0' == *second
) {
1957 mandoc_msg(MANDOCERR_ARGCOUNT
, r
->parse
,
1958 ln
, (int)(p
- *bufp
), NULL
);
1964 roff_setstrn(&r
->xmbtab
, first
,
1965 fsz
, second
, ssz
, 0);
1969 if (NULL
== r
->xtab
)
1970 r
->xtab
= mandoc_calloc
1971 (128, sizeof(struct roffstr
));
1973 free(r
->xtab
[(int)*first
].p
);
1974 r
->xtab
[(int)*first
].p
= mandoc_strndup(second
, ssz
);
1975 r
->xtab
[(int)*first
].sz
= ssz
;
1987 mandoc_msg(MANDOCERR_SO
, r
->parse
, ln
, ppos
, NULL
);
1990 * Handle `so'. Be EXTREMELY careful, as we shouldn't be
1991 * opening anything that's not in our cwd or anything beneath
1992 * it. Thus, explicitly disallow traversing up the file-system
1993 * or using absolute paths.
1997 if ('/' == *name
|| strstr(name
, "../") || strstr(name
, "/..")) {
1998 mandoc_msg(MANDOCERR_SOPATH
, r
->parse
, ln
, pos
, NULL
);
2008 roff_userdef(ROFF_ARGS
)
2015 * Collect pointers to macro argument strings
2016 * and NUL-terminate them.
2019 for (i
= 0; i
< 9; i
++)
2020 arg
[i
] = '\0' == *cp
? "" :
2021 mandoc_getarg(r
->parse
, &cp
, ln
, &pos
);
2024 * Expand macro arguments.
2027 n1
= cp
= mandoc_strdup(r
->current_string
);
2028 while (NULL
!= (cp
= strstr(cp
, "\\$"))) {
2030 if (0 > i
|| 8 < i
) {
2031 /* Not an argument invocation. */
2036 *szp
= strlen(n1
) - 3 + strlen(arg
[i
]) + 1;
2037 n2
= mandoc_malloc(*szp
);
2039 strlcpy(n2
, n1
, (size_t)(cp
- n1
+ 1));
2040 strlcat(n2
, arg
[i
], *szp
);
2041 strlcat(n2
, cp
+ 3, *szp
);
2043 cp
= n2
+ (cp
- n1
);
2049 * Replace the macro invocation
2050 * by the expanded macro.
2055 *szp
= strlen(*bufp
) + 1;
2057 return(*szp
> 1 && '\n' == (*bufp
)[(int)*szp
- 2] ?
2058 ROFF_REPARSE
: ROFF_APPEND
);
2062 roff_getname(struct roff
*r
, char **cpp
, int ln
, int pos
)
2070 /* Read until end of name. */
2071 for (cp
= name
; '\0' != *cp
&& ' ' != *cp
; cp
++) {
2077 mandoc_msg(MANDOCERR_NAMESC
, r
->parse
, ln
, pos
, NULL
);
2082 /* Nil-terminate name. */
2086 /* Read past spaces. */
2095 * Store *string into the user-defined string called *name.
2096 * To clear an existing entry, call with (*r, *name, NULL, 0).
2097 * append == 0: replace mode
2098 * append == 1: single-line append mode
2099 * append == 2: multiline append mode, append '\n' after each call
2102 roff_setstr(struct roff
*r
, const char *name
, const char *string
,
2106 roff_setstrn(&r
->strtab
, name
, strlen(name
), string
,
2107 string
? strlen(string
) : 0, append
);
2111 roff_setstrn(struct roffkv
**r
, const char *name
, size_t namesz
,
2112 const char *string
, size_t stringsz
, int append
)
2117 size_t oldch
, newch
;
2119 /* Search for an existing string with the same name. */
2122 while (n
&& strcmp(name
, n
->key
.p
))
2126 /* Create a new string table entry. */
2127 n
= mandoc_malloc(sizeof(struct roffkv
));
2128 n
->key
.p
= mandoc_strndup(name
, namesz
);
2134 } else if (0 == append
) {
2144 * One additional byte for the '\n' in multiline mode,
2145 * and one for the terminating '\0'.
2147 newch
= stringsz
+ (1 < append
? 2u : 1u);
2149 if (NULL
== n
->val
.p
) {
2150 n
->val
.p
= mandoc_malloc(newch
);
2155 n
->val
.p
= mandoc_realloc(n
->val
.p
, oldch
+ newch
);
2158 /* Skip existing content in the destination buffer. */
2159 c
= n
->val
.p
+ (int)oldch
;
2161 /* Append new content to the destination buffer. */
2163 while (i
< (int)stringsz
) {
2165 * Rudimentary roff copy mode:
2166 * Handle escaped backslashes.
2168 if ('\\' == string
[i
] && '\\' == string
[i
+ 1])
2173 /* Append terminating bytes. */
2178 n
->val
.sz
= (int)(c
- n
->val
.p
);
2182 roff_getstrn(const struct roff
*r
, const char *name
, size_t len
)
2184 const struct roffkv
*n
;
2187 for (n
= r
->strtab
; n
; n
= n
->next
)
2188 if (0 == strncmp(name
, n
->key
.p
, len
) &&
2189 '\0' == n
->key
.p
[(int)len
])
2192 for (i
= 0; i
< PREDEFS_MAX
; i
++)
2193 if (0 == strncmp(name
, predefs
[i
].name
, len
) &&
2194 '\0' == predefs
[i
].name
[(int)len
])
2195 return(predefs
[i
].str
);
2201 roff_freestr(struct roffkv
*r
)
2203 struct roffkv
*n
, *nn
;
2205 for (n
= r
; n
; n
= nn
) {
2213 const struct tbl_span
*
2214 roff_span(const struct roff
*r
)
2217 return(r
->tbl
? tbl_span(r
->tbl
) : NULL
);
2221 roff_eqn(const struct roff
*r
)
2224 return(r
->last_eqn
? &r
->last_eqn
->eqn
: NULL
);
2228 * Duplicate an input string, making the appropriate character
2229 * conversations (as stipulated by `tr') along the way.
2230 * Returns a heap-allocated string with all the replacements made.
2233 roff_strdup(const struct roff
*r
, const char *p
)
2235 const struct roffkv
*cp
;
2239 enum mandoc_esc esc
;
2241 if (NULL
== r
->xmbtab
&& NULL
== r
->xtab
)
2242 return(mandoc_strdup(p
));
2243 else if ('\0' == *p
)
2244 return(mandoc_strdup(""));
2247 * Step through each character looking for term matches
2248 * (remember that a `tr' can be invoked with an escape, which is
2249 * a glyph but the escape is multi-character).
2250 * We only do this if the character hash has been initialised
2251 * and the string is >0 length.
2257 while ('\0' != *p
) {
2258 if ('\\' != *p
&& r
->xtab
&& r
->xtab
[(int)*p
].p
) {
2259 sz
= r
->xtab
[(int)*p
].sz
;
2260 res
= mandoc_realloc(res
, ssz
+ sz
+ 1);
2261 memcpy(res
+ ssz
, r
->xtab
[(int)*p
].p
, sz
);
2265 } else if ('\\' != *p
) {
2266 res
= mandoc_realloc(res
, ssz
+ 2);
2271 /* Search for term matches. */
2272 for (cp
= r
->xmbtab
; cp
; cp
= cp
->next
)
2273 if (0 == strncmp(p
, cp
->key
.p
, cp
->key
.sz
))
2278 * A match has been found.
2279 * Append the match to the array and move
2280 * forward by its keysize.
2282 res
= mandoc_realloc
2283 (res
, ssz
+ cp
->val
.sz
+ 1);
2284 memcpy(res
+ ssz
, cp
->val
.p
, cp
->val
.sz
);
2286 p
+= (int)cp
->key
.sz
;
2291 * Handle escapes carefully: we need to copy
2292 * over just the escape itself, or else we might
2293 * do replacements within the escape itself.
2294 * Make sure to pass along the bogus string.
2297 esc
= mandoc_escape(&p
, NULL
, NULL
);
2298 if (ESCAPE_ERROR
== esc
) {
2300 res
= mandoc_realloc(res
, ssz
+ sz
+ 1);
2301 memcpy(res
+ ssz
, pp
, sz
);
2305 * We bail out on bad escapes.
2306 * No need to warn: we already did so when
2307 * roff_res() was called.
2310 res
= mandoc_realloc(res
, ssz
+ sz
+ 1);
2311 memcpy(res
+ ssz
, pp
, sz
);
2315 res
[(int)ssz
] = '\0';
2320 * Find out whether a line is a macro line or not.
2321 * If it is, adjust the current position and return one; if it isn't,
2322 * return zero and don't change the current position.
2323 * If the control character has been set with `.cc', then let that grain
2325 * This is slighly contrary to groff, where using the non-breaking
2326 * control character when `cc' has been invoked will cause the
2327 * non-breaking macro contents to be printed verbatim.
2330 roff_getcontrol(const struct roff
*r
, const char *cp
, int *ppos
)
2336 if (0 != r
->control
&& cp
[pos
] == r
->control
)
2338 else if (0 != r
->control
)
2340 else if ('\\' == cp
[pos
] && '.' == cp
[pos
+ 1])
2342 else if ('.' == cp
[pos
] || '\'' == cp
[pos
])
2347 while (' ' == cp
[pos
] || '\t' == cp
[pos
])