]>
git.cameronkatri.com Git - mandoc.git/blob - roff.c
1 /* $Id: roff.c,v 1.231 2014/10/16 01:28:38 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 eqn_inline
; /* current equation is inline */
124 int options
; /* parse options */
125 int rstacksz
; /* current size limit of rstack */
126 int rstackpos
; /* position in rstack */
127 int format
; /* current file in mdoc or man format */
128 char control
; /* control character */
132 enum rofft tok
; /* type of node */
133 struct roffnode
*parent
; /* up one in stack */
134 int line
; /* parse line */
135 int col
; /* parse col */
136 char *name
; /* node name, e.g. macro name */
137 char *end
; /* end-rules: custom token */
138 int endspan
; /* end-rules: next-line or infty */
139 int rule
; /* current evaluation rule */
142 #define ROFF_ARGS struct roff *r, /* parse ctx */ \
143 enum rofft tok, /* tok of macro */ \
144 char **bufp, /* input buffer */ \
145 size_t *szp, /* size of input buffer */ \
146 int ln, /* parse line */ \
147 int ppos, /* original pos in buffer */ \
148 int pos, /* current pos in buffer */ \
149 int *offs /* reset offset of buffer data */
151 typedef enum rofferr (*roffproc
)(ROFF_ARGS
);
154 const char *name
; /* macro name */
155 roffproc proc
; /* process new macro */
156 roffproc text
; /* process as child text of macro */
157 roffproc sub
; /* process as child of macro */
159 #define ROFFMAC_STRUCT (1 << 0) /* always interpret */
160 struct roffmac
*next
;
164 const char *name
; /* predefined input name */
165 const char *str
; /* replacement symbol */
168 #define PREDEF(__name, __str) \
169 { (__name), (__str) },
171 static enum rofft
roffhash_find(const char *, size_t);
172 static void roffhash_init(void);
173 static void roffnode_cleanscope(struct roff
*);
174 static void roffnode_pop(struct roff
*);
175 static void roffnode_push(struct roff
*, enum rofft
,
176 const char *, int, int);
177 static enum rofferr
roff_block(ROFF_ARGS
);
178 static enum rofferr
roff_block_text(ROFF_ARGS
);
179 static enum rofferr
roff_block_sub(ROFF_ARGS
);
180 static enum rofferr
roff_cblock(ROFF_ARGS
);
181 static enum rofferr
roff_cc(ROFF_ARGS
);
182 static void roff_ccond(struct roff
*, int, int);
183 static enum rofferr
roff_cond(ROFF_ARGS
);
184 static enum rofferr
roff_cond_text(ROFF_ARGS
);
185 static enum rofferr
roff_cond_sub(ROFF_ARGS
);
186 static enum rofferr
roff_ds(ROFF_ARGS
);
187 static enum rofferr
roff_eqndelim(struct roff
*,
188 char **, size_t *, int);
189 static int roff_evalcond(const char *, int *);
190 static int roff_evalnum(const char *, int *, int *, int);
191 static int roff_evalpar(const char *, int *, int *);
192 static int roff_evalstrcond(const char *, int *);
193 static void roff_free1(struct roff
*);
194 static void roff_freereg(struct roffreg
*);
195 static void roff_freestr(struct roffkv
*);
196 static size_t roff_getname(struct roff
*, char **, int, int);
197 static int roff_getnum(const char *, int *, int *);
198 static int roff_getop(const char *, int *, char *);
199 static int roff_getregn(const struct roff
*,
200 const char *, size_t);
201 static int roff_getregro(const char *name
);
202 static const char *roff_getstrn(const struct roff
*,
203 const char *, size_t);
204 static enum rofferr
roff_it(ROFF_ARGS
);
205 static enum rofferr
roff_line_ignore(ROFF_ARGS
);
206 static enum rofferr
roff_nr(ROFF_ARGS
);
207 static void roff_openeqn(struct roff
*, const char *,
208 int, int, const char *);
209 static enum rofft
roff_parse(struct roff
*, char *, int *,
211 static enum rofferr
roff_parsetext(char **, size_t *, int, int *);
212 static enum rofferr
roff_res(struct roff
*,
213 char **, size_t *, int, int);
214 static enum rofferr
roff_rm(ROFF_ARGS
);
215 static enum rofferr
roff_rr(ROFF_ARGS
);
216 static void roff_setstr(struct roff
*,
217 const char *, const char *, int);
218 static void roff_setstrn(struct roffkv
**, const char *,
219 size_t, const char *, size_t, int);
220 static enum rofferr
roff_so(ROFF_ARGS
);
221 static enum rofferr
roff_tr(ROFF_ARGS
);
222 static enum rofferr
roff_Dd(ROFF_ARGS
);
223 static enum rofferr
roff_TH(ROFF_ARGS
);
224 static enum rofferr
roff_TE(ROFF_ARGS
);
225 static enum rofferr
roff_TS(ROFF_ARGS
);
226 static enum rofferr
roff_EQ(ROFF_ARGS
);
227 static enum rofferr
roff_EN(ROFF_ARGS
);
228 static enum rofferr
roff_T_(ROFF_ARGS
);
229 static enum rofferr
roff_userdef(ROFF_ARGS
);
231 /* See roffhash_find() */
235 #define HASHWIDTH (ASCII_HI - ASCII_LO + 1)
237 static struct roffmac
*hash
[HASHWIDTH
];
239 static struct roffmac roffs
[ROFF_MAX
] = {
240 { "ad", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
241 { "am", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
242 { "ami", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
243 { "am1", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
244 { "as", roff_ds
, NULL
, NULL
, 0, NULL
},
245 { "cc", roff_cc
, NULL
, NULL
, 0, NULL
},
246 { "ce", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
247 { "de", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
248 { "dei", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
249 { "de1", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
250 { "ds", roff_ds
, NULL
, NULL
, 0, NULL
},
251 { "el", roff_cond
, roff_cond_text
, roff_cond_sub
, ROFFMAC_STRUCT
, NULL
},
252 { "fam", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
253 { "hw", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
254 { "hy", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
255 { "ie", roff_cond
, roff_cond_text
, roff_cond_sub
, ROFFMAC_STRUCT
, NULL
},
256 { "if", roff_cond
, roff_cond_text
, roff_cond_sub
, ROFFMAC_STRUCT
, NULL
},
257 { "ig", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
258 { "it", roff_it
, NULL
, NULL
, 0, NULL
},
259 { "ne", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
260 { "nh", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
261 { "nr", roff_nr
, NULL
, NULL
, 0, NULL
},
262 { "ns", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
263 { "pl", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
264 { "ps", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
265 { "rm", roff_rm
, NULL
, NULL
, 0, NULL
},
266 { "rr", roff_rr
, NULL
, NULL
, 0, NULL
},
267 { "so", roff_so
, NULL
, NULL
, 0, NULL
},
268 { "ta", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
269 { "tr", roff_tr
, NULL
, NULL
, 0, NULL
},
270 { "Dd", roff_Dd
, NULL
, NULL
, 0, NULL
},
271 { "TH", roff_TH
, NULL
, NULL
, 0, NULL
},
272 { "TS", roff_TS
, NULL
, NULL
, 0, NULL
},
273 { "TE", roff_TE
, NULL
, NULL
, 0, NULL
},
274 { "T&", roff_T_
, NULL
, NULL
, 0, NULL
},
275 { "EQ", roff_EQ
, NULL
, NULL
, 0, NULL
},
276 { "EN", roff_EN
, NULL
, NULL
, 0, NULL
},
277 { ".", roff_cblock
, NULL
, NULL
, 0, NULL
},
278 { NULL
, roff_userdef
, NULL
, NULL
, 0, NULL
},
281 /* not currently implemented: Ds em Eq LP Me PP pp Or Rd Sf SH */
282 const char *const __mdoc_reserved
[] = {
283 "Ac", "Ad", "An", "Ao", "Ap", "Aq", "Ar", "At",
284 "Bc", "Bd", "Bf", "Bk", "Bl", "Bo", "Bq",
285 "Brc", "Bro", "Brq", "Bsx", "Bt", "Bx",
286 "Cd", "Cm", "Db", "Dc", "Dd", "Dl", "Do", "Dq",
287 "Dt", "Dv", "Dx", "D1",
288 "Ec", "Ed", "Ef", "Ek", "El", "Em",
289 "En", "Eo", "Er", "Es", "Ev", "Ex",
290 "Fa", "Fc", "Fd", "Fl", "Fn", "Fo", "Fr", "Ft", "Fx",
291 "Hf", "Ic", "In", "It", "Lb", "Li", "Lk", "Lp",
292 "Ms", "Mt", "Nd", "Nm", "No", "Ns", "Nx",
293 "Oc", "Oo", "Op", "Os", "Ot", "Ox",
294 "Pa", "Pc", "Pf", "Po", "Pp", "Pq",
295 "Qc", "Ql", "Qo", "Qq", "Re", "Rs", "Rv",
296 "Sc", "Sh", "Sm", "So", "Sq",
297 "Ss", "St", "Sx", "Sy",
298 "Ta", "Tn", "Ud", "Ux", "Va", "Vt", "Xc", "Xo", "Xr",
299 "%A", "%B", "%C", "%D", "%I", "%J", "%N", "%O",
300 "%P", "%Q", "%R", "%T", "%U", "%V",
304 /* not currently implemented: BT DE DS ME MT PT SY TQ YS */
305 const char *const __man_reserved
[] = {
306 "AT", "B", "BI", "BR", "DT",
307 "EE", "EN", "EQ", "EX", "HP", "I", "IB", "IP", "IR",
308 "LP", "OP", "P", "PD", "PP",
309 "R", "RB", "RE", "RI", "RS", "SB", "SH", "SM", "SS",
310 "TE", "TH", "TP", "TS", "T&", "UC", "UE", "UR",
314 /* Array of injected predefined strings. */
315 #define PREDEFS_MAX 38
316 static const struct predef predefs
[PREDEFS_MAX
] = {
317 #include "predefs.in"
320 /* See roffhash_find() */
321 #define ROFF_HASH(p) (p[0] - ASCII_LO)
323 static int roffit_lines
; /* number of lines to delay */
324 static char *roffit_macro
; /* nil-terminated macro line */
333 for (i
= 0; i
< (int)ROFF_USERDEF
; i
++) {
334 assert(roffs
[i
].name
[0] >= ASCII_LO
);
335 assert(roffs
[i
].name
[0] <= ASCII_HI
);
337 buc
= ROFF_HASH(roffs
[i
].name
);
339 if (NULL
!= (n
= hash
[buc
])) {
340 for ( ; n
->next
; n
= n
->next
)
344 hash
[buc
] = &roffs
[i
];
349 * Look up a roff token by its name. Returns ROFF_MAX if no macro by
350 * the nil-terminated string name could be found.
353 roffhash_find(const char *p
, size_t s
)
359 * libroff has an extremely simple hashtable, for the time
360 * being, which simply keys on the first character, which must
361 * be printable, then walks a chain. It works well enough until
365 if (p
[0] < ASCII_LO
|| p
[0] > ASCII_HI
)
370 if (NULL
== (n
= hash
[buc
]))
372 for ( ; n
; n
= n
->next
)
373 if (0 == strncmp(n
->name
, p
, s
) && '\0' == n
->name
[(int)s
])
374 return((enum rofft
)(n
- roffs
));
380 * Pop the current node off of the stack of roff instructions currently
384 roffnode_pop(struct roff
*r
)
391 r
->last
= r
->last
->parent
;
398 * Push a roff node onto the instruction stack. This must later be
399 * removed with roffnode_pop().
402 roffnode_push(struct roff
*r
, enum rofft tok
, const char *name
,
407 p
= mandoc_calloc(1, sizeof(struct roffnode
));
410 p
->name
= mandoc_strdup(name
);
414 p
->rule
= p
->parent
? p
->parent
->rule
: 0;
420 roff_free1(struct roff
*r
)
422 struct tbl_node
*tbl
;
426 while (NULL
!= (tbl
= r
->first_tbl
)) {
427 r
->first_tbl
= tbl
->next
;
430 r
->first_tbl
= r
->last_tbl
= r
->tbl
= NULL
;
432 while (NULL
!= (e
= r
->first_eqn
)) {
433 r
->first_eqn
= e
->next
;
436 r
->first_eqn
= r
->last_eqn
= r
->eqn
= NULL
;
446 roff_freereg(r
->regtab
);
449 roff_freestr(r
->strtab
);
450 roff_freestr(r
->xmbtab
);
451 r
->strtab
= r
->xmbtab
= NULL
;
454 for (i
= 0; i
< 128; i
++)
461 roff_reset(struct roff
*r
)
465 r
->format
= r
->options
& (MPARSE_MDOC
| MPARSE_MAN
);
470 roff_free(struct roff
*r
)
478 roff_alloc(struct mparse
*parse
, int options
)
482 r
= mandoc_calloc(1, sizeof(struct roff
));
484 r
->options
= options
;
485 r
->format
= options
& (MPARSE_MDOC
| MPARSE_MAN
);
494 * In the current line, expand escape sequences that tend to get
495 * used in numerical expressions and conditional requests.
496 * Also check the syntax of the remaining escape sequences.
499 roff_res(struct roff
*r
, char **bufp
, size_t *szp
, int ln
, int pos
)
501 char ubuf
[24]; /* buffer to print the number */
502 const char *start
; /* start of the string to process */
503 char *stesc
; /* start of an escape sequence ('\\') */
504 const char *stnam
; /* start of the name, after "[(*" */
505 const char *cp
; /* end of the name, e.g. before ']' */
506 const char *res
; /* the string to be substituted */
507 char *nbuf
; /* new buffer to copy bufp to */
508 size_t maxl
; /* expected length of the escape name */
509 size_t naml
; /* actual length of the escape name */
510 int expand_count
; /* to avoid infinite loops */
511 int npos
; /* position in numeric expression */
512 int arg_complete
; /* argument not interrupted by eol */
513 char term
; /* character terminating the escape */
517 stesc
= strchr(start
, '\0') - 1;
518 while (stesc
-- > start
) {
520 /* Search backwards for the next backslash. */
525 /* If it is escaped, skip it. */
527 for (cp
= stesc
- 1; cp
>= start
; cp
--)
531 if (0 == (stesc
- cp
) % 2) {
536 /* Decide whether to expand or to check only. */
553 if (ESCAPE_ERROR
== mandoc_escape(&cp
, NULL
, NULL
))
554 mandoc_vmsg(MANDOCERR_ESC_BAD
,
555 r
->parse
, ln
, (int)(stesc
- *bufp
),
556 "%.*s", (int)(cp
- stesc
), stesc
);
560 if (EXPAND_LIMIT
< ++expand_count
) {
561 mandoc_msg(MANDOCERR_ROFFLOOP
, r
->parse
,
562 ln
, (int)(stesc
- *bufp
), NULL
);
567 * The third character decides the length
568 * of the name of the string or register.
569 * Save a pointer to the name.
596 /* Advance to the end of the name. */
599 for (naml
= 0; 0 == maxl
|| naml
< maxl
; naml
++, cp
++) {
601 mandoc_msg(MANDOCERR_ESC_BAD
, r
->parse
,
602 ln
, (int)(stesc
- *bufp
), stesc
);
606 if (0 == maxl
&& *cp
== term
) {
613 * Retrieve the replacement string; if it is
614 * undefined, resume searching for escapes.
620 res
= roff_getstrn(r
, stnam
, naml
);
624 ubuf
[0] = arg_complete
&&
625 roff_evalnum(stnam
, &npos
, NULL
, 0) &&
626 stnam
+ npos
+ 1 == cp
? '1' : '0';
631 (void)snprintf(ubuf
, sizeof(ubuf
), "%d",
632 roff_getregn(r
, stnam
, naml
));
637 /* use even incomplete args */
638 (void)snprintf(ubuf
, sizeof(ubuf
), "%d",
644 mandoc_vmsg(MANDOCERR_STR_UNDEF
,
645 r
->parse
, ln
, (int)(stesc
- *bufp
),
646 "%.*s", (int)naml
, stnam
);
650 /* Replace the escape sequence by the string. */
653 *szp
= mandoc_asprintf(&nbuf
, "%s%s%s",
656 /* Prepare for the next replacement. */
659 stesc
= nbuf
+ (stesc
- *bufp
) + strlen(res
);
667 * Process text streams:
668 * Convert all breakable hyphens into ASCII_HYPH.
669 * Decrement and spring input line trap.
672 roff_parsetext(char **bufp
, size_t *szp
, int pos
, int *offs
)
680 start
= p
= *bufp
+ pos
;
683 sz
= strcspn(p
, "-\\");
690 /* Skip over escapes. */
692 esc
= mandoc_escape((const char **)&p
, NULL
, NULL
);
693 if (ESCAPE_ERROR
== esc
)
696 } else if (p
== start
) {
701 if (isalpha((unsigned char)p
[-1]) &&
702 isalpha((unsigned char)p
[1]))
707 /* Spring the input line trap. */
708 if (1 == roffit_lines
) {
709 isz
= mandoc_asprintf(&p
, "%s\n.%s", *bufp
, roffit_macro
);
716 return(ROFF_REPARSE
);
717 } else if (1 < roffit_lines
)
723 roff_parseln(struct roff
*r
, int ln
, char **bufp
,
724 size_t *szp
, int pos
, int *offs
)
730 /* Handle in-line equation delimiters. */
732 if (r
->last_eqn
!= NULL
&& r
->last_eqn
->delim
&&
733 (r
->eqn
== NULL
|| r
->eqn_inline
)) {
734 e
= roff_eqndelim(r
, bufp
, szp
, pos
);
735 if (e
== ROFF_REPARSE
)
737 assert(e
== ROFF_CONT
);
740 /* Expand some escape sequences. */
742 e
= roff_res(r
, bufp
, szp
, ln
, pos
);
745 assert(ROFF_CONT
== e
);
748 ctl
= roff_getcontrol(r
, *bufp
, &pos
);
751 * First, if a scope is open and we're not a macro, pass the
752 * text through the macro's filter. If a scope isn't open and
753 * we're not a macro, just let it through.
754 * Finally, if there's an equation scope open, divert it into it
755 * no matter our state.
758 if (r
->last
&& ! ctl
) {
760 assert(roffs
[t
].text
);
761 e
= (*roffs
[t
].text
)(r
, t
, bufp
, szp
, ln
, pos
, pos
, offs
);
762 assert(ROFF_IGN
== e
|| ROFF_CONT
== e
);
767 return(eqn_read(&r
->eqn
, ln
, *bufp
, ppos
, offs
));
770 return(tbl_read(r
->tbl
, ln
, *bufp
, pos
));
771 return(roff_parsetext(bufp
, szp
, pos
, offs
));
774 /* Skip empty request lines. */
776 if ((*bufp
)[pos
] == '"') {
777 mandoc_msg(MANDOCERR_COMMENT_BAD
, r
->parse
,
780 } else if ((*bufp
)[pos
] == '\0')
784 * If a scope is open, go to the child handler for that macro,
785 * as it may want to preprocess before doing anything with it.
786 * Don't do so if an equation is open.
791 assert(roffs
[t
].sub
);
792 return((*roffs
[t
].sub
)(r
, t
, bufp
, szp
,
793 ln
, ppos
, pos
, offs
));
797 * Lastly, as we've no scope open, try to look up and execute
798 * the new macro. If no macro is found, simply return and let
799 * the compilers handle it.
802 if (ROFF_MAX
== (t
= roff_parse(r
, *bufp
, &pos
, ln
, ppos
)))
805 assert(roffs
[t
].proc
);
806 return((*roffs
[t
].proc
)(r
, t
, bufp
, szp
, ln
, ppos
, pos
, offs
));
810 roff_endparse(struct roff
*r
)
814 mandoc_msg(MANDOCERR_BLK_NOEND
, r
->parse
,
815 r
->last
->line
, r
->last
->col
,
816 roffs
[r
->last
->tok
].name
);
819 mandoc_msg(MANDOCERR_BLK_NOEND
, r
->parse
,
820 r
->eqn
->eqn
.ln
, r
->eqn
->eqn
.pos
, "EQ");
825 mandoc_msg(MANDOCERR_BLK_NOEND
, r
->parse
,
826 r
->tbl
->line
, r
->tbl
->pos
, "TS");
832 * Parse a roff node's type from the input buffer. This must be in the
833 * form of ".foo xxx" in the usual way.
836 roff_parse(struct roff
*r
, char *buf
, int *pos
, int ln
, int ppos
)
845 if ('\0' == *cp
|| '"' == *cp
|| '\t' == *cp
|| ' ' == *cp
)
849 maclen
= roff_getname(r
, &cp
, ln
, ppos
);
851 t
= (r
->current_string
= roff_getstrn(r
, mac
, maclen
))
852 ? ROFF_USERDEF
: roffhash_find(mac
, maclen
);
861 roff_cblock(ROFF_ARGS
)
865 * A block-close `..' should only be invoked as a child of an
866 * ignore macro, otherwise raise a warning and just ignore it.
869 if (NULL
== r
->last
) {
870 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
,
875 switch (r
->last
->tok
) {
877 /* ROFF_am1 is remapped to ROFF_am in roff_block(). */
882 /* ROFF_de1 is remapped to ROFF_de in roff_block(). */
889 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
,
895 mandoc_vmsg(MANDOCERR_ARG_SKIP
, r
->parse
, ln
, pos
,
896 ".. %s", *bufp
+ pos
);
899 roffnode_cleanscope(r
);
905 roffnode_cleanscope(struct roff
*r
)
909 if (--r
->last
->endspan
!= 0)
916 roff_ccond(struct roff
*r
, int ln
, int ppos
)
919 if (NULL
== r
->last
) {
920 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
,
925 switch (r
->last
->tok
) {
933 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
,
938 if (r
->last
->endspan
> -1) {
939 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
,
945 roffnode_cleanscope(r
);
950 roff_block(ROFF_ARGS
)
956 /* Ignore groff compatibility mode for now. */
960 else if (ROFF_am1
== tok
)
963 /* Parse the macro name argument. */
966 if (ROFF_ig
== tok
) {
971 namesz
= roff_getname(r
, &cp
, ln
, ppos
);
972 iname
[namesz
] = '\0';
975 /* Resolve the macro name argument if it is indirect. */
977 if (namesz
&& (ROFF_dei
== tok
|| ROFF_ami
== tok
)) {
978 if (NULL
== (name
= roff_getstrn(r
, iname
, namesz
))) {
979 mandoc_vmsg(MANDOCERR_STR_UNDEF
,
980 r
->parse
, ln
, (int)(iname
- *bufp
),
981 "%.*s", (int)namesz
, iname
);
984 namesz
= strlen(name
);
988 if (0 == namesz
&& ROFF_ig
!= tok
) {
989 mandoc_msg(MANDOCERR_REQ_EMPTY
, r
->parse
,
990 ln
, ppos
, roffs
[tok
].name
);
994 roffnode_push(r
, tok
, name
, ln
, ppos
);
997 * At the beginning of a `de' macro, clear the existing string
998 * with the same name, if there is one. New content will be
999 * appended from roff_block_text() in multiline mode.
1002 if (ROFF_de
== tok
|| ROFF_dei
== tok
)
1003 roff_setstrn(&r
->strtab
, name
, namesz
, "", 0, 0);
1008 /* Get the custom end marker. */
1011 namesz
= roff_getname(r
, &cp
, ln
, ppos
);
1013 /* Resolve the end marker if it is indirect. */
1015 if (namesz
&& (ROFF_dei
== tok
|| ROFF_ami
== tok
)) {
1016 if (NULL
== (name
= roff_getstrn(r
, iname
, namesz
))) {
1017 mandoc_vmsg(MANDOCERR_STR_UNDEF
,
1018 r
->parse
, ln
, (int)(iname
- *bufp
),
1019 "%.*s", (int)namesz
, iname
);
1022 namesz
= strlen(name
);
1027 r
->last
->end
= mandoc_strndup(name
, namesz
);
1030 mandoc_vmsg(MANDOCERR_ARG_EXCESS
, r
->parse
,
1031 ln
, pos
, ".%s ... %s", roffs
[tok
].name
, cp
);
1037 roff_block_sub(ROFF_ARGS
)
1043 * First check whether a custom macro exists at this level. If
1044 * it does, then check against it. This is some of groff's
1045 * stranger behaviours. If we encountered a custom end-scope
1046 * tag and that tag also happens to be a "real" macro, then we
1047 * need to try interpreting it again as a real macro. If it's
1048 * not, then return ignore. Else continue.
1052 for (i
= pos
, j
= 0; r
->last
->end
[j
]; j
++, i
++)
1053 if ((*bufp
)[i
] != r
->last
->end
[j
])
1056 if ('\0' == r
->last
->end
[j
] &&
1057 ('\0' == (*bufp
)[i
] ||
1058 ' ' == (*bufp
)[i
] ||
1059 '\t' == (*bufp
)[i
])) {
1061 roffnode_cleanscope(r
);
1063 while (' ' == (*bufp
)[i
] || '\t' == (*bufp
)[i
])
1067 if (ROFF_MAX
!= roff_parse(r
, *bufp
, &pos
, ln
, ppos
))
1074 * If we have no custom end-query or lookup failed, then try
1075 * pulling it out of the hashtable.
1078 t
= roff_parse(r
, *bufp
, &pos
, ln
, ppos
);
1080 if (ROFF_cblock
!= t
) {
1082 roff_setstr(r
, r
->last
->name
, *bufp
+ ppos
, 2);
1086 assert(roffs
[t
].proc
);
1087 return((*roffs
[t
].proc
)(r
, t
, bufp
, szp
, ln
, ppos
, pos
, offs
));
1091 roff_block_text(ROFF_ARGS
)
1095 roff_setstr(r
, r
->last
->name
, *bufp
+ pos
, 2);
1101 roff_cond_sub(ROFF_ARGS
)
1108 roffnode_cleanscope(r
);
1109 t
= roff_parse(r
, *bufp
, &pos
, ln
, ppos
);
1112 * Fully handle known macros when they are structurally
1113 * required or when the conditional evaluated to true.
1116 if ((ROFF_MAX
!= t
) &&
1117 (rr
|| ROFFMAC_STRUCT
& roffs
[t
].flags
)) {
1118 assert(roffs
[t
].proc
);
1119 return((*roffs
[t
].proc
)(r
, t
, bufp
, szp
,
1120 ln
, ppos
, pos
, offs
));
1124 * If `\}' occurs on a macro line without a preceding macro,
1125 * drop the line completely.
1129 if ('\\' == ep
[0] && '}' == ep
[1])
1132 /* Always check for the closing delimiter `\}'. */
1134 while (NULL
!= (ep
= strchr(ep
, '\\'))) {
1135 if ('}' == *(++ep
)) {
1137 roff_ccond(r
, ln
, ep
- *bufp
- 1);
1141 return(rr
? ROFF_CONT
: ROFF_IGN
);
1145 roff_cond_text(ROFF_ARGS
)
1151 roffnode_cleanscope(r
);
1154 while (NULL
!= (ep
= strchr(ep
, '\\'))) {
1155 if ('}' == *(++ep
)) {
1157 roff_ccond(r
, ln
, ep
- *bufp
- 1);
1161 return(rr
? ROFF_CONT
: ROFF_IGN
);
1165 * Parse a single signed integer number. Stop at the first non-digit.
1166 * If there is at least one digit, return success and advance the
1167 * parse point, else return failure and let the parse point unchanged.
1168 * Ignore overflows, treat them just like the C language.
1171 roff_getnum(const char *v
, int *pos
, int *res
)
1183 for (*res
= 0; isdigit((unsigned char)v
[p
]); p
++)
1184 *res
= 10 * *res
+ v
[p
] - '0';
1196 * Evaluate a string comparison condition.
1197 * The first character is the delimiter.
1198 * Succeed if the string up to its second occurrence
1199 * matches the string up to its third occurence.
1200 * Advance the cursor after the third occurrence
1201 * or lacking that, to the end of the line.
1204 roff_evalstrcond(const char *v
, int *pos
)
1206 const char *s1
, *s2
, *s3
;
1210 s1
= v
+ *pos
; /* initial delimiter */
1211 s2
= s1
+ 1; /* for scanning the first string */
1212 s3
= strchr(s2
, *s1
); /* for scanning the second string */
1214 if (NULL
== s3
) /* found no middle delimiter */
1217 while ('\0' != *++s3
) {
1218 if (*s2
!= *s3
) { /* mismatch */
1219 s3
= strchr(s3
, *s1
);
1222 if (*s3
== *s1
) { /* found the final delimiter */
1231 s3
= strchr(s2
, '\0');
1239 * Evaluate an optionally negated single character, numerical,
1240 * or string condition.
1243 roff_evalcond(const char *v
, int *pos
)
1245 int wanttrue
, number
;
1247 if ('!' == v
[*pos
]) {
1274 if (roff_evalnum(v
, pos
, &number
, 0))
1275 return((number
> 0) == wanttrue
);
1277 return(roff_evalstrcond(v
, pos
) == wanttrue
);
1281 roff_line_ignore(ROFF_ARGS
)
1288 roff_cond(ROFF_ARGS
)
1291 roffnode_push(r
, tok
, NULL
, ln
, ppos
);
1294 * An `.el' has no conditional body: it will consume the value
1295 * of the current rstack entry set in prior `ie' calls or
1298 * If we're not an `el', however, then evaluate the conditional.
1301 r
->last
->rule
= ROFF_el
== tok
?
1302 (r
->rstackpos
< 0 ? 0 : r
->rstack
[r
->rstackpos
--]) :
1303 roff_evalcond(*bufp
, &pos
);
1306 * An if-else will put the NEGATION of the current evaluated
1307 * conditional into the stack of rules.
1310 if (ROFF_ie
== tok
) {
1311 if (r
->rstackpos
+ 1 == r
->rstacksz
) {
1313 r
->rstack
= mandoc_reallocarray(r
->rstack
,
1314 r
->rstacksz
, sizeof(int));
1316 r
->rstack
[++r
->rstackpos
] = !r
->last
->rule
;
1319 /* If the parent has false as its rule, then so do we. */
1321 if (r
->last
->parent
&& !r
->last
->parent
->rule
)
1326 * If there is nothing on the line after the conditional,
1327 * not even whitespace, use next-line scope.
1330 if ('\0' == (*bufp
)[pos
]) {
1331 r
->last
->endspan
= 2;
1335 while (' ' == (*bufp
)[pos
])
1338 /* An opening brace requests multiline scope. */
1340 if ('\\' == (*bufp
)[pos
] && '{' == (*bufp
)[pos
+ 1]) {
1341 r
->last
->endspan
= -1;
1347 * Anything else following the conditional causes
1348 * single-line scope. Warn if the scope contains
1349 * nothing but trailing whitespace.
1352 if ('\0' == (*bufp
)[pos
])
1353 mandoc_msg(MANDOCERR_COND_EMPTY
, r
->parse
,
1354 ln
, ppos
, roffs
[tok
].name
);
1356 r
->last
->endspan
= 1;
1371 * The first word is the name of the string.
1372 * If it is empty or terminated by an escape sequence,
1373 * abort the `ds' request without defining anything.
1376 name
= string
= *bufp
+ pos
;
1380 namesz
= roff_getname(r
, &string
, ln
, pos
);
1381 if ('\\' == name
[namesz
])
1384 /* Read past the initial double-quote, if any. */
1388 /* The rest is the value. */
1389 roff_setstrn(&r
->strtab
, name
, namesz
, string
, strlen(string
),
1395 * Parse a single operator, one or two characters long.
1396 * If the operator is recognized, return success and advance the
1397 * parse point, else return failure and let the parse point unchanged.
1400 roff_getop(const char *v
, int *pos
, char *res
)
1421 switch (v
[*pos
+ 1]) {
1439 switch (v
[*pos
+ 1]) {
1453 if ('=' == v
[*pos
+ 1])
1465 * Evaluate either a parenthesized numeric expression
1466 * or a single signed integer number.
1469 roff_evalpar(const char *v
, int *pos
, int *res
)
1473 return(roff_getnum(v
, pos
, res
));
1476 if ( ! roff_evalnum(v
, pos
, res
, 1))
1480 * Omission of the closing parenthesis
1481 * is an error in validation mode,
1482 * but ignored in evaluation mode.
1487 else if (NULL
== res
)
1494 * Evaluate a complete numeric expression.
1495 * Proceed left to right, there is no concept of precedence.
1498 roff_evalnum(const char *v
, int *pos
, int *res
, int skipwhite
)
1500 int mypos
, operand2
;
1509 while (isspace((unsigned char)v
[*pos
]))
1512 if ( ! roff_evalpar(v
, pos
, res
))
1517 while (isspace((unsigned char)v
[*pos
]))
1520 if ( ! roff_getop(v
, pos
, &operator))
1524 while (isspace((unsigned char)v
[*pos
]))
1527 if ( ! roff_evalpar(v
, pos
, &operand2
))
1531 while (isspace((unsigned char)v
[*pos
]))
1554 *res
= *res
< operand2
;
1557 *res
= *res
> operand2
;
1560 *res
= *res
<= operand2
;
1563 *res
= *res
>= operand2
;
1566 *res
= *res
== operand2
;
1569 *res
= *res
!= operand2
;
1572 *res
= *res
&& operand2
;
1575 *res
= *res
|| operand2
;
1578 if (operand2
< *res
)
1582 if (operand2
> *res
)
1593 roff_setreg(struct roff
*r
, const char *name
, int val
, char sign
)
1595 struct roffreg
*reg
;
1597 /* Search for an existing register with the same name. */
1600 while (reg
&& strcmp(name
, reg
->key
.p
))
1604 /* Create a new register. */
1605 reg
= mandoc_malloc(sizeof(struct roffreg
));
1606 reg
->key
.p
= mandoc_strdup(name
);
1607 reg
->key
.sz
= strlen(name
);
1609 reg
->next
= r
->regtab
;
1615 else if ('-' == sign
)
1622 * Handle some predefined read-only number registers.
1623 * For now, return -1 if the requested register is not predefined;
1624 * in case a predefined read-only register having the value -1
1625 * were to turn up, another special value would have to be chosen.
1628 roff_getregro(const char *name
)
1632 case 'A': /* ASCII approximation mode is always off. */
1634 case 'g': /* Groff compatibility mode is always on. */
1636 case 'H': /* Fixed horizontal resolution. */
1638 case 'j': /* Always adjust left margin only. */
1640 case 'T': /* Some output device is always defined. */
1642 case 'V': /* Fixed vertical resolution. */
1650 roff_getreg(const struct roff
*r
, const char *name
)
1652 struct roffreg
*reg
;
1655 if ('.' == name
[0] && '\0' != name
[1] && '\0' == name
[2]) {
1656 val
= roff_getregro(name
+ 1);
1661 for (reg
= r
->regtab
; reg
; reg
= reg
->next
)
1662 if (0 == strcmp(name
, reg
->key
.p
))
1669 roff_getregn(const struct roff
*r
, const char *name
, size_t len
)
1671 struct roffreg
*reg
;
1674 if ('.' == name
[0] && 2 == len
) {
1675 val
= roff_getregro(name
+ 1);
1680 for (reg
= r
->regtab
; reg
; reg
= reg
->next
)
1681 if (len
== reg
->key
.sz
&&
1682 0 == strncmp(name
, reg
->key
.p
, len
))
1689 roff_freereg(struct roffreg
*reg
)
1691 struct roffreg
*old_reg
;
1693 while (NULL
!= reg
) {
1709 key
= val
= *bufp
+ pos
;
1713 keysz
= roff_getname(r
, &val
, ln
, pos
);
1714 if ('\\' == key
[keysz
])
1719 if ('+' == sign
|| '-' == sign
)
1722 if (roff_evalnum(val
, NULL
, &iv
, 0))
1723 roff_setreg(r
, key
, iv
, sign
);
1731 struct roffreg
*reg
, **prev
;
1735 name
= cp
= *bufp
+ pos
;
1738 namesz
= roff_getname(r
, &cp
, ln
, pos
);
1739 name
[namesz
] = '\0';
1744 if (NULL
== reg
|| !strcmp(name
, reg
->key
.p
))
1764 while ('\0' != *cp
) {
1766 namesz
= roff_getname(r
, &cp
, ln
, (int)(cp
- *bufp
));
1767 roff_setstrn(&r
->strtab
, name
, namesz
, NULL
, 0, 0);
1768 if ('\\' == name
[namesz
])
1781 /* Parse the number of lines. */
1783 len
= strcspn(cp
, " \t");
1785 if ((iv
= mandoc_strntoi(cp
, len
, 10)) <= 0) {
1786 mandoc_msg(MANDOCERR_IT_NONUM
, r
->parse
,
1787 ln
, ppos
, *bufp
+ 1);
1792 /* Arm the input line trap. */
1794 roffit_macro
= mandoc_strdup(cp
);
1801 const char *const *cp
;
1803 if ((r
->options
& (MPARSE_MDOC
| MPARSE_QUICK
)) == 0)
1804 for (cp
= __mdoc_reserved
; *cp
; cp
++)
1805 roff_setstr(r
, *cp
, NULL
, 0);
1808 r
->format
= MPARSE_MDOC
;
1816 const char *const *cp
;
1818 if ((r
->options
& MPARSE_QUICK
) == 0)
1819 for (cp
= __man_reserved
; *cp
; cp
++)
1820 roff_setstr(r
, *cp
, NULL
, 0);
1823 r
->format
= MPARSE_MAN
;
1833 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
,
1846 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
,
1849 tbl_restart(ppos
, ln
, r
->tbl
);
1855 * Handle in-line equation delimiters.
1858 roff_eqndelim(struct roff
*r
, char **bufp
, size_t *szp
, int pos
)
1863 * Outside equations, look for an opening delimiter.
1864 * If we are inside an equation, we already know it is
1865 * in-line, or this function wouldn't have been called;
1866 * so look for a closing delimiter.
1870 cp2
= strchr(cp1
, r
->eqn
== NULL
?
1871 r
->last_eqn
->odelim
: r
->last_eqn
->cdelim
);
1875 /* Found a delimiter; get rid of surrounding blanks. */
1878 while (cp2
[0] == ' ')
1880 while (cp1
[-1] == ' ')
1884 /* Replace the delimiter with an equation macro. */
1886 *szp
= mandoc_asprintf(&cp1
, "%s\n.E%s%s", *bufp
,
1887 r
->eqn
== NULL
? "Q\n" : "N\n\\&", cp2
) + 1;
1891 /* Toggle the in-line state of the eqn subsystem. */
1893 r
->eqn_inline
= r
->eqn
== NULL
;
1894 return(ROFF_REPARSE
);
1898 roff_openeqn(struct roff
*r
, const char *name
, int line
,
1899 int offs
, const char *buf
)
1904 assert(NULL
== r
->eqn
);
1905 e
= eqn_alloc(name
, offs
, line
, r
->parse
);
1908 r
->last_eqn
->next
= e
;
1909 e
->delim
= r
->last_eqn
->delim
;
1910 e
->odelim
= r
->last_eqn
->odelim
;
1911 e
->cdelim
= r
->last_eqn
->cdelim
;
1913 r
->first_eqn
= r
->last_eqn
= e
;
1915 r
->eqn
= r
->last_eqn
= e
;
1919 eqn_read(&r
->eqn
, line
, buf
, offs
, &poff
);
1927 roff_openeqn(r
, *bufp
+ pos
, ln
, ppos
, NULL
);
1935 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
, ln
, ppos
, "EN");
1942 struct tbl_node
*tbl
;
1945 mandoc_msg(MANDOCERR_BLK_BROKEN
, r
->parse
,
1946 ln
, ppos
, "TS breaks TS");
1950 tbl
= tbl_alloc(ppos
, ln
, r
->parse
);
1953 r
->last_tbl
->next
= tbl
;
1955 r
->first_tbl
= r
->last_tbl
= tbl
;
1957 r
->tbl
= r
->last_tbl
= tbl
;
1968 if ('\0' == *p
|| '.' == (r
->control
= *p
++))
1972 mandoc_msg(MANDOCERR_ARGCOUNT
, r
->parse
, ln
, ppos
, NULL
);
1980 const char *p
, *first
, *second
;
1982 enum mandoc_esc esc
;
1987 mandoc_msg(MANDOCERR_ARGCOUNT
, r
->parse
, ln
, ppos
, NULL
);
1991 while ('\0' != *p
) {
1995 if ('\\' == *first
) {
1996 esc
= mandoc_escape(&p
, NULL
, NULL
);
1997 if (ESCAPE_ERROR
== esc
) {
1998 mandoc_msg(MANDOCERR_ESC_BAD
, r
->parse
,
1999 ln
, (int)(p
- *bufp
), first
);
2002 fsz
= (size_t)(p
- first
);
2006 if ('\\' == *second
) {
2007 esc
= mandoc_escape(&p
, NULL
, NULL
);
2008 if (ESCAPE_ERROR
== esc
) {
2009 mandoc_msg(MANDOCERR_ESC_BAD
, r
->parse
,
2010 ln
, (int)(p
- *bufp
), second
);
2013 ssz
= (size_t)(p
- second
);
2014 } else if ('\0' == *second
) {
2015 mandoc_msg(MANDOCERR_ARGCOUNT
, r
->parse
,
2016 ln
, (int)(p
- *bufp
), NULL
);
2022 roff_setstrn(&r
->xmbtab
, first
, fsz
,
2027 if (NULL
== r
->xtab
)
2028 r
->xtab
= mandoc_calloc(128,
2029 sizeof(struct roffstr
));
2031 free(r
->xtab
[(int)*first
].p
);
2032 r
->xtab
[(int)*first
].p
= mandoc_strndup(second
, ssz
);
2033 r
->xtab
[(int)*first
].sz
= ssz
;
2045 mandoc_vmsg(MANDOCERR_SO
, r
->parse
, ln
, ppos
, "so %s", name
);
2048 * Handle `so'. Be EXTREMELY careful, as we shouldn't be
2049 * opening anything that's not in our cwd or anything beneath
2050 * it. Thus, explicitly disallow traversing up the file-system
2051 * or using absolute paths.
2054 if ('/' == *name
|| strstr(name
, "../") || strstr(name
, "/..")) {
2055 mandoc_vmsg(MANDOCERR_SO_PATH
, r
->parse
, ln
, ppos
,
2065 roff_userdef(ROFF_ARGS
)
2072 * Collect pointers to macro argument strings
2073 * and NUL-terminate them.
2076 for (i
= 0; i
< 9; i
++)
2077 arg
[i
] = '\0' == *cp
? "" :
2078 mandoc_getarg(r
->parse
, &cp
, ln
, &pos
);
2081 * Expand macro arguments.
2084 n1
= cp
= mandoc_strdup(r
->current_string
);
2085 while (NULL
!= (cp
= strstr(cp
, "\\$"))) {
2087 if (0 > i
|| 8 < i
) {
2088 /* Not an argument invocation. */
2093 *szp
= mandoc_asprintf(&n2
, "%s%s%s",
2094 n1
, arg
[i
], cp
+ 3) + 1;
2095 cp
= n2
+ (cp
- n1
);
2101 * Replace the macro invocation
2102 * by the expanded macro.
2107 *szp
= strlen(*bufp
) + 1;
2109 return(*szp
> 1 && '\n' == (*bufp
)[(int)*szp
- 2] ?
2110 ROFF_REPARSE
: ROFF_APPEND
);
2114 roff_getname(struct roff
*r
, char **cpp
, int ln
, int pos
)
2123 /* Read until end of name and terminate it with NUL. */
2124 for (cp
= name
; 1; cp
++) {
2125 if ('\0' == *cp
|| ' ' == *cp
) {
2132 if ('{' == cp
[1] || '}' == cp
[1])
2137 mandoc_vmsg(MANDOCERR_NAMESC
, r
->parse
, ln
, pos
,
2138 "%.*s", (int)(cp
- name
+ 1), name
);
2139 mandoc_escape((const char **)&cp
, NULL
, NULL
);
2143 /* Read past spaces. */
2152 * Store *string into the user-defined string called *name.
2153 * To clear an existing entry, call with (*r, *name, NULL, 0).
2154 * append == 0: replace mode
2155 * append == 1: single-line append mode
2156 * append == 2: multiline append mode, append '\n' after each call
2159 roff_setstr(struct roff
*r
, const char *name
, const char *string
,
2163 roff_setstrn(&r
->strtab
, name
, strlen(name
), string
,
2164 string
? strlen(string
) : 0, append
);
2168 roff_setstrn(struct roffkv
**r
, const char *name
, size_t namesz
,
2169 const char *string
, size_t stringsz
, int append
)
2174 size_t oldch
, newch
;
2176 /* Search for an existing string with the same name. */
2179 while (n
&& (namesz
!= n
->key
.sz
||
2180 strncmp(n
->key
.p
, name
, namesz
)))
2184 /* Create a new string table entry. */
2185 n
= mandoc_malloc(sizeof(struct roffkv
));
2186 n
->key
.p
= mandoc_strndup(name
, namesz
);
2192 } else if (0 == append
) {
2202 * One additional byte for the '\n' in multiline mode,
2203 * and one for the terminating '\0'.
2205 newch
= stringsz
+ (1 < append
? 2u : 1u);
2207 if (NULL
== n
->val
.p
) {
2208 n
->val
.p
= mandoc_malloc(newch
);
2213 n
->val
.p
= mandoc_realloc(n
->val
.p
, oldch
+ newch
);
2216 /* Skip existing content in the destination buffer. */
2217 c
= n
->val
.p
+ (int)oldch
;
2219 /* Append new content to the destination buffer. */
2221 while (i
< (int)stringsz
) {
2223 * Rudimentary roff copy mode:
2224 * Handle escaped backslashes.
2226 if ('\\' == string
[i
] && '\\' == string
[i
+ 1])
2231 /* Append terminating bytes. */
2236 n
->val
.sz
= (int)(c
- n
->val
.p
);
2240 roff_getstrn(const struct roff
*r
, const char *name
, size_t len
)
2242 const struct roffkv
*n
;
2245 for (n
= r
->strtab
; n
; n
= n
->next
)
2246 if (0 == strncmp(name
, n
->key
.p
, len
) &&
2247 '\0' == n
->key
.p
[(int)len
])
2250 for (i
= 0; i
< PREDEFS_MAX
; i
++)
2251 if (0 == strncmp(name
, predefs
[i
].name
, len
) &&
2252 '\0' == predefs
[i
].name
[(int)len
])
2253 return(predefs
[i
].str
);
2259 roff_freestr(struct roffkv
*r
)
2261 struct roffkv
*n
, *nn
;
2263 for (n
= r
; n
; n
= nn
) {
2271 const struct tbl_span
*
2272 roff_span(const struct roff
*r
)
2275 return(r
->tbl
? tbl_span(r
->tbl
) : NULL
);
2279 roff_eqn(const struct roff
*r
)
2282 return(r
->last_eqn
? &r
->last_eqn
->eqn
: NULL
);
2286 * Duplicate an input string, making the appropriate character
2287 * conversations (as stipulated by `tr') along the way.
2288 * Returns a heap-allocated string with all the replacements made.
2291 roff_strdup(const struct roff
*r
, const char *p
)
2293 const struct roffkv
*cp
;
2297 enum mandoc_esc esc
;
2299 if (NULL
== r
->xmbtab
&& NULL
== r
->xtab
)
2300 return(mandoc_strdup(p
));
2301 else if ('\0' == *p
)
2302 return(mandoc_strdup(""));
2305 * Step through each character looking for term matches
2306 * (remember that a `tr' can be invoked with an escape, which is
2307 * a glyph but the escape is multi-character).
2308 * We only do this if the character hash has been initialised
2309 * and the string is >0 length.
2315 while ('\0' != *p
) {
2316 if ('\\' != *p
&& r
->xtab
&& r
->xtab
[(int)*p
].p
) {
2317 sz
= r
->xtab
[(int)*p
].sz
;
2318 res
= mandoc_realloc(res
, ssz
+ sz
+ 1);
2319 memcpy(res
+ ssz
, r
->xtab
[(int)*p
].p
, sz
);
2323 } else if ('\\' != *p
) {
2324 res
= mandoc_realloc(res
, ssz
+ 2);
2329 /* Search for term matches. */
2330 for (cp
= r
->xmbtab
; cp
; cp
= cp
->next
)
2331 if (0 == strncmp(p
, cp
->key
.p
, cp
->key
.sz
))
2336 * A match has been found.
2337 * Append the match to the array and move
2338 * forward by its keysize.
2340 res
= mandoc_realloc(res
,
2341 ssz
+ cp
->val
.sz
+ 1);
2342 memcpy(res
+ ssz
, cp
->val
.p
, cp
->val
.sz
);
2344 p
+= (int)cp
->key
.sz
;
2349 * Handle escapes carefully: we need to copy
2350 * over just the escape itself, or else we might
2351 * do replacements within the escape itself.
2352 * Make sure to pass along the bogus string.
2355 esc
= mandoc_escape(&p
, NULL
, NULL
);
2356 if (ESCAPE_ERROR
== esc
) {
2358 res
= mandoc_realloc(res
, ssz
+ sz
+ 1);
2359 memcpy(res
+ ssz
, pp
, sz
);
2363 * We bail out on bad escapes.
2364 * No need to warn: we already did so when
2365 * roff_res() was called.
2368 res
= mandoc_realloc(res
, ssz
+ sz
+ 1);
2369 memcpy(res
+ ssz
, pp
, sz
);
2373 res
[(int)ssz
] = '\0';
2378 roff_getformat(const struct roff
*r
)
2385 * Find out whether a line is a macro line or not.
2386 * If it is, adjust the current position and return one; if it isn't,
2387 * return zero and don't change the current position.
2388 * If the control character has been set with `.cc', then let that grain
2390 * This is slighly contrary to groff, where using the non-breaking
2391 * control character when `cc' has been invoked will cause the
2392 * non-breaking macro contents to be printed verbatim.
2395 roff_getcontrol(const struct roff
*r
, const char *cp
, int *ppos
)
2401 if (0 != r
->control
&& cp
[pos
] == r
->control
)
2403 else if (0 != r
->control
)
2405 else if ('\\' == cp
[pos
] && '.' == cp
[pos
+ 1])
2407 else if ('.' == cp
[pos
] || '\'' == cp
[pos
])
2412 while (' ' == cp
[pos
] || '\t' == cp
[pos
])