]>
git.cameronkatri.com Git - mandoc.git/blob - roff.c
1 /* $Id: roff.c,v 1.244 2014/12/18 17:43:41 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 const struct mchars
*mchars
; /* character table */
111 struct roffnode
*last
; /* leaf of stack */
112 int *rstack
; /* stack of inverted `ie' values */
113 struct roffreg
*regtab
; /* number registers */
114 struct roffkv
*strtab
; /* user-defined strings & macros */
115 struct roffkv
*xmbtab
; /* multi-byte trans table (`tr') */
116 struct roffstr
*xtab
; /* single-byte trans table (`tr') */
117 const char *current_string
; /* value of last called user macro */
118 struct tbl_node
*first_tbl
; /* first table parsed */
119 struct tbl_node
*last_tbl
; /* last table parsed */
120 struct tbl_node
*tbl
; /* current table being parsed */
121 struct eqn_node
*last_eqn
; /* last equation parsed */
122 struct eqn_node
*first_eqn
; /* first equation parsed */
123 struct eqn_node
*eqn
; /* current equation being parsed */
124 int eqn_inline
; /* current equation is inline */
125 int options
; /* parse options */
126 int rstacksz
; /* current size limit of rstack */
127 int rstackpos
; /* position in rstack */
128 int format
; /* current file in mdoc or man format */
129 char control
; /* control character */
133 enum rofft tok
; /* type of node */
134 struct roffnode
*parent
; /* up one in stack */
135 int line
; /* parse line */
136 int col
; /* parse col */
137 char *name
; /* node name, e.g. macro name */
138 char *end
; /* end-rules: custom token */
139 int endspan
; /* end-rules: next-line or infty */
140 int rule
; /* current evaluation rule */
143 #define ROFF_ARGS struct roff *r, /* parse ctx */ \
144 enum rofft tok, /* tok of macro */ \
145 struct buf *buf, /* 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
*, struct buf
*, int);
188 static int roff_evalcond(struct roff
*r
, int,
189 const char *, int *);
190 static int roff_evalnum(struct roff
*, int,
191 const char *, int *, int *, int);
192 static int roff_evalpar(struct roff
*, int,
193 const char *, int *, int *);
194 static int roff_evalstrcond(const char *, int *);
195 static void roff_free1(struct roff
*);
196 static void roff_freereg(struct roffreg
*);
197 static void roff_freestr(struct roffkv
*);
198 static size_t roff_getname(struct roff
*, char **, int, int);
199 static int roff_getnum(const char *, int *, int *);
200 static int roff_getop(const char *, int *, char *);
201 static int roff_getregn(const struct roff
*,
202 const char *, size_t);
203 static int roff_getregro(const char *name
);
204 static const char *roff_getstrn(const struct roff
*,
205 const char *, size_t);
206 static enum rofferr
roff_it(ROFF_ARGS
);
207 static enum rofferr
roff_line_ignore(ROFF_ARGS
);
208 static enum rofferr
roff_nr(ROFF_ARGS
);
209 static enum rofft
roff_parse(struct roff
*, char *, int *,
211 static enum rofferr
roff_parsetext(struct buf
*, int, int *);
212 static enum rofferr
roff_res(struct roff
*, struct buf
*, int, int);
213 static enum rofferr
roff_rm(ROFF_ARGS
);
214 static enum rofferr
roff_rr(ROFF_ARGS
);
215 static void roff_setstr(struct roff
*,
216 const char *, const char *, int);
217 static void roff_setstrn(struct roffkv
**, const char *,
218 size_t, const char *, size_t, int);
219 static enum rofferr
roff_so(ROFF_ARGS
);
220 static enum rofferr
roff_tr(ROFF_ARGS
);
221 static enum rofferr
roff_Dd(ROFF_ARGS
);
222 static enum rofferr
roff_TH(ROFF_ARGS
);
223 static enum rofferr
roff_TE(ROFF_ARGS
);
224 static enum rofferr
roff_TS(ROFF_ARGS
);
225 static enum rofferr
roff_EQ(ROFF_ARGS
);
226 static enum rofferr
roff_EN(ROFF_ARGS
);
227 static enum rofferr
roff_T_(ROFF_ARGS
);
228 static enum rofferr
roff_userdef(ROFF_ARGS
);
230 /* See roffhash_find() */
234 #define HASHWIDTH (ASCII_HI - ASCII_LO + 1)
236 static struct roffmac
*hash
[HASHWIDTH
];
238 static struct roffmac roffs
[ROFF_MAX
] = {
239 { "ad", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
240 { "am", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
241 { "ami", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
242 { "am1", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
243 { "as", roff_ds
, NULL
, NULL
, 0, NULL
},
244 { "cc", roff_cc
, NULL
, NULL
, 0, NULL
},
245 { "ce", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
246 { "de", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
247 { "dei", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
248 { "de1", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
249 { "ds", roff_ds
, NULL
, NULL
, 0, NULL
},
250 { "el", roff_cond
, roff_cond_text
, roff_cond_sub
, ROFFMAC_STRUCT
, NULL
},
251 { "fam", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
252 { "hw", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
253 { "hy", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
254 { "ie", roff_cond
, roff_cond_text
, roff_cond_sub
, ROFFMAC_STRUCT
, NULL
},
255 { "if", roff_cond
, roff_cond_text
, roff_cond_sub
, ROFFMAC_STRUCT
, NULL
},
256 { "ig", roff_block
, roff_block_text
, roff_block_sub
, 0, NULL
},
257 { "it", roff_it
, NULL
, NULL
, 0, NULL
},
258 { "ne", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
259 { "nh", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
260 { "nr", roff_nr
, NULL
, NULL
, 0, NULL
},
261 { "ns", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
262 { "pl", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
263 { "ps", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
264 { "rm", roff_rm
, NULL
, NULL
, 0, NULL
},
265 { "rr", roff_rr
, NULL
, NULL
, 0, NULL
},
266 { "so", roff_so
, NULL
, NULL
, 0, NULL
},
267 { "ta", roff_line_ignore
, NULL
, NULL
, 0, NULL
},
268 { "tr", roff_tr
, NULL
, NULL
, 0, NULL
},
269 { "Dd", roff_Dd
, NULL
, NULL
, 0, NULL
},
270 { "TH", roff_TH
, NULL
, NULL
, 0, NULL
},
271 { "TS", roff_TS
, NULL
, NULL
, 0, NULL
},
272 { "TE", roff_TE
, NULL
, NULL
, 0, NULL
},
273 { "T&", roff_T_
, NULL
, NULL
, 0, NULL
},
274 { "EQ", roff_EQ
, NULL
, NULL
, 0, NULL
},
275 { "EN", roff_EN
, NULL
, NULL
, 0, NULL
},
276 { ".", roff_cblock
, NULL
, NULL
, 0, NULL
},
277 { NULL
, roff_userdef
, NULL
, NULL
, 0, NULL
},
280 /* not currently implemented: Ds em Eq LP Me PP pp Or Rd Sf SH */
281 const char *const __mdoc_reserved
[] = {
282 "Ac", "Ad", "An", "Ao", "Ap", "Aq", "Ar", "At",
283 "Bc", "Bd", "Bf", "Bk", "Bl", "Bo", "Bq",
284 "Brc", "Bro", "Brq", "Bsx", "Bt", "Bx",
285 "Cd", "Cm", "Db", "Dc", "Dd", "Dl", "Do", "Dq",
286 "Dt", "Dv", "Dx", "D1",
287 "Ec", "Ed", "Ef", "Ek", "El", "Em",
288 "En", "Eo", "Er", "Es", "Ev", "Ex",
289 "Fa", "Fc", "Fd", "Fl", "Fn", "Fo", "Fr", "Ft", "Fx",
290 "Hf", "Ic", "In", "It", "Lb", "Li", "Lk", "Lp",
291 "Ms", "Mt", "Nd", "Nm", "No", "Ns", "Nx",
292 "Oc", "Oo", "Op", "Os", "Ot", "Ox",
293 "Pa", "Pc", "Pf", "Po", "Pp", "Pq",
294 "Qc", "Ql", "Qo", "Qq", "Re", "Rs", "Rv",
295 "Sc", "Sh", "Sm", "So", "Sq",
296 "Ss", "St", "Sx", "Sy",
297 "Ta", "Tn", "Ud", "Ux", "Va", "Vt", "Xc", "Xo", "Xr",
298 "%A", "%B", "%C", "%D", "%I", "%J", "%N", "%O",
299 "%P", "%Q", "%R", "%T", "%U", "%V",
303 /* not currently implemented: BT DE DS ME MT PT SY TQ YS */
304 const char *const __man_reserved
[] = {
305 "AT", "B", "BI", "BR", "DT",
306 "EE", "EN", "EQ", "EX", "HP", "I", "IB", "IP", "IR",
307 "LP", "OP", "P", "PD", "PP",
308 "R", "RB", "RE", "RI", "RS", "SB", "SH", "SM", "SS",
309 "TE", "TH", "TP", "TS", "T&", "UC", "UE", "UR",
313 /* Array of injected predefined strings. */
314 #define PREDEFS_MAX 38
315 static const struct predef predefs
[PREDEFS_MAX
] = {
316 #include "predefs.in"
319 /* See roffhash_find() */
320 #define ROFF_HASH(p) (p[0] - ASCII_LO)
322 static int roffit_lines
; /* number of lines to delay */
323 static char *roffit_macro
; /* nil-terminated macro line */
332 for (i
= 0; i
< (int)ROFF_USERDEF
; i
++) {
333 assert(roffs
[i
].name
[0] >= ASCII_LO
);
334 assert(roffs
[i
].name
[0] <= ASCII_HI
);
336 buc
= ROFF_HASH(roffs
[i
].name
);
338 if (NULL
!= (n
= hash
[buc
])) {
339 for ( ; n
->next
; n
= n
->next
)
343 hash
[buc
] = &roffs
[i
];
348 * Look up a roff token by its name. Returns ROFF_MAX if no macro by
349 * the nil-terminated string name could be found.
352 roffhash_find(const char *p
, size_t s
)
358 * libroff has an extremely simple hashtable, for the time
359 * being, which simply keys on the first character, which must
360 * be printable, then walks a chain. It works well enough until
364 if (p
[0] < ASCII_LO
|| p
[0] > ASCII_HI
)
369 if (NULL
== (n
= hash
[buc
]))
371 for ( ; n
; n
= n
->next
)
372 if (0 == strncmp(n
->name
, p
, s
) && '\0' == n
->name
[(int)s
])
373 return((enum rofft
)(n
- roffs
));
379 * Pop the current node off of the stack of roff instructions currently
383 roffnode_pop(struct roff
*r
)
390 r
->last
= r
->last
->parent
;
397 * Push a roff node onto the instruction stack. This must later be
398 * removed with roffnode_pop().
401 roffnode_push(struct roff
*r
, enum rofft tok
, const char *name
,
406 p
= mandoc_calloc(1, sizeof(struct roffnode
));
409 p
->name
= mandoc_strdup(name
);
413 p
->rule
= p
->parent
? p
->parent
->rule
: 0;
419 roff_free1(struct roff
*r
)
421 struct tbl_node
*tbl
;
425 while (NULL
!= (tbl
= r
->first_tbl
)) {
426 r
->first_tbl
= tbl
->next
;
429 r
->first_tbl
= r
->last_tbl
= r
->tbl
= NULL
;
431 while (NULL
!= (e
= r
->first_eqn
)) {
432 r
->first_eqn
= e
->next
;
435 r
->first_eqn
= r
->last_eqn
= r
->eqn
= NULL
;
445 roff_freereg(r
->regtab
);
448 roff_freestr(r
->strtab
);
449 roff_freestr(r
->xmbtab
);
450 r
->strtab
= r
->xmbtab
= NULL
;
453 for (i
= 0; i
< 128; i
++)
460 roff_reset(struct roff
*r
)
464 r
->format
= r
->options
& (MPARSE_MDOC
| MPARSE_MAN
);
469 roff_free(struct roff
*r
)
477 roff_alloc(struct mparse
*parse
, const struct mchars
*mchars
, int options
)
481 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
, struct buf
*buf
, 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 buf->buf to */
508 size_t maxl
; /* expected length of the escape name */
509 size_t naml
; /* actual length of the escape name */
510 enum mandoc_esc esc
; /* type of the escape sequence */
511 int inaml
; /* length returned from mandoc_escape() */
512 int expand_count
; /* to avoid infinite loops */
513 int npos
; /* position in numeric expression */
514 int arg_complete
; /* argument not interrupted by eol */
515 char term
; /* character terminating the escape */
518 start
= buf
->buf
+ pos
;
519 stesc
= strchr(start
, '\0') - 1;
520 while (stesc
-- > start
) {
522 /* Search backwards for the next backslash. */
527 /* If it is escaped, skip it. */
529 for (cp
= stesc
- 1; cp
>= start
; cp
--)
533 if ((stesc
- cp
) % 2 == 0) {
538 /* Decide whether to expand or to check only. */
555 esc
= mandoc_escape(&cp
, &stnam
, &inaml
);
556 if (esc
== ESCAPE_ERROR
||
557 (esc
== ESCAPE_SPECIAL
&&
558 mchars_spec2cp(r
->mchars
, stnam
, inaml
) < 0))
559 mandoc_vmsg(MANDOCERR_ESC_BAD
,
560 r
->parse
, ln
, (int)(stesc
- buf
->buf
),
561 "%.*s", (int)(cp
- stesc
), stesc
);
565 if (EXPAND_LIMIT
< ++expand_count
) {
566 mandoc_msg(MANDOCERR_ROFFLOOP
, r
->parse
,
567 ln
, (int)(stesc
- buf
->buf
), NULL
);
572 * The third character decides the length
573 * of the name of the string or register.
574 * Save a pointer to the name.
601 /* Advance to the end of the name. */
604 for (naml
= 0; maxl
== 0 || naml
< maxl
; naml
++, cp
++) {
606 mandoc_msg(MANDOCERR_ESC_BAD
, r
->parse
,
607 ln
, (int)(stesc
- buf
->buf
), stesc
);
611 if (maxl
== 0 && *cp
== term
) {
618 * Retrieve the replacement string; if it is
619 * undefined, resume searching for escapes.
625 res
= roff_getstrn(r
, stnam
, naml
);
629 ubuf
[0] = arg_complete
&&
630 roff_evalnum(r
, ln
, stnam
, &npos
, NULL
, 0) &&
631 stnam
+ npos
+ 1 == cp
? '1' : '0';
636 (void)snprintf(ubuf
, sizeof(ubuf
), "%d",
637 roff_getregn(r
, stnam
, naml
));
642 /* use even incomplete args */
643 (void)snprintf(ubuf
, sizeof(ubuf
), "%d",
649 mandoc_vmsg(MANDOCERR_STR_UNDEF
,
650 r
->parse
, ln
, (int)(stesc
- buf
->buf
),
651 "%.*s", (int)naml
, stnam
);
655 /* Replace the escape sequence by the string. */
658 buf
->sz
= mandoc_asprintf(&nbuf
, "%s%s%s",
659 buf
->buf
, res
, cp
) + 1;
661 /* Prepare for the next replacement. */
664 stesc
= nbuf
+ (stesc
- buf
->buf
) + strlen(res
);
672 * Process text streams:
673 * Convert all breakable hyphens into ASCII_HYPH.
674 * Decrement and spring input line trap.
677 roff_parsetext(struct buf
*buf
, int pos
, int *offs
)
685 start
= p
= buf
->buf
+ pos
;
688 sz
= strcspn(p
, "-\\");
695 /* Skip over escapes. */
697 esc
= mandoc_escape((const char **)&p
, NULL
, NULL
);
698 if (esc
== ESCAPE_ERROR
)
701 } else if (p
== start
) {
706 if (isalpha((unsigned char)p
[-1]) &&
707 isalpha((unsigned char)p
[1]))
712 /* Spring the input line trap. */
713 if (roffit_lines
== 1) {
714 isz
= mandoc_asprintf(&p
, "%s\n.%s", buf
->buf
, roffit_macro
);
721 return(ROFF_REPARSE
);
722 } else if (roffit_lines
> 1)
728 roff_parseln(struct roff
*r
, int ln
, struct buf
*buf
, int *offs
)
732 int pos
; /* parse point */
733 int spos
; /* saved parse point for messages */
734 int ppos
; /* original offset in buf->buf */
735 int ctl
; /* macro line (boolean) */
739 /* Handle in-line equation delimiters. */
741 if (r
->tbl
== NULL
&&
742 r
->last_eqn
!= NULL
&& r
->last_eqn
->delim
&&
743 (r
->eqn
== NULL
|| r
->eqn_inline
)) {
744 e
= roff_eqndelim(r
, buf
, pos
);
745 if (e
== ROFF_REPARSE
)
747 assert(e
== ROFF_CONT
);
750 /* Expand some escape sequences. */
752 e
= roff_res(r
, buf
, ln
, pos
);
755 assert(e
== ROFF_CONT
);
757 ctl
= roff_getcontrol(r
, buf
->buf
, &pos
);
760 * First, if a scope is open and we're not a macro, pass the
761 * text through the macro's filter. If a scope isn't open and
762 * we're not a macro, just let it through.
763 * Finally, if there's an equation scope open, divert it into it
764 * no matter our state.
767 if (r
->last
&& ! ctl
) {
769 assert(roffs
[t
].text
);
770 e
= (*roffs
[t
].text
)(r
, t
, buf
, ln
, pos
, pos
, offs
);
771 assert(e
== ROFF_IGN
|| e
== ROFF_CONT
);
776 return(eqn_read(&r
->eqn
, ln
, buf
->buf
, ppos
, offs
));
779 return(tbl_read(r
->tbl
, ln
, buf
->buf
, pos
));
780 return(roff_parsetext(buf
, pos
, offs
));
783 /* Skip empty request lines. */
785 if (buf
->buf
[pos
] == '"') {
786 mandoc_msg(MANDOCERR_COMMENT_BAD
, r
->parse
,
789 } else if (buf
->buf
[pos
] == '\0')
793 * If a scope is open, go to the child handler for that macro,
794 * as it may want to preprocess before doing anything with it.
795 * Don't do so if an equation is open.
800 assert(roffs
[t
].sub
);
801 return((*roffs
[t
].sub
)(r
, t
, buf
, ln
, ppos
, pos
, offs
));
804 /* No scope is open. This is a new request or macro. */
807 t
= roff_parse(r
, buf
->buf
, &pos
, ln
, ppos
);
809 /* Tables ignore most macros. */
811 if (r
->tbl
!= NULL
&& (t
== ROFF_MAX
|| t
== ROFF_TS
)) {
812 mandoc_msg(MANDOCERR_TBLMACRO
, r
->parse
,
813 ln
, pos
, buf
->buf
+ spos
);
818 * This is neither a roff request nor a user-defined macro.
819 * Let the standard macro set parsers handle it.
825 /* Execute a roff request or a user defined macro. */
827 assert(roffs
[t
].proc
);
828 return((*roffs
[t
].proc
)(r
, t
, buf
, ln
, ppos
, pos
, offs
));
832 roff_endparse(struct roff
*r
)
836 mandoc_msg(MANDOCERR_BLK_NOEND
, r
->parse
,
837 r
->last
->line
, r
->last
->col
,
838 roffs
[r
->last
->tok
].name
);
841 mandoc_msg(MANDOCERR_BLK_NOEND
, r
->parse
,
842 r
->eqn
->eqn
.ln
, r
->eqn
->eqn
.pos
, "EQ");
847 mandoc_msg(MANDOCERR_BLK_NOEND
, r
->parse
,
848 r
->tbl
->line
, r
->tbl
->pos
, "TS");
854 * Parse a roff node's type from the input buffer. This must be in the
855 * form of ".foo xxx" in the usual way.
858 roff_parse(struct roff
*r
, char *buf
, int *pos
, int ln
, int ppos
)
867 if ('\0' == *cp
|| '"' == *cp
|| '\t' == *cp
|| ' ' == *cp
)
871 maclen
= roff_getname(r
, &cp
, ln
, ppos
);
873 t
= (r
->current_string
= roff_getstrn(r
, mac
, maclen
))
874 ? ROFF_USERDEF
: roffhash_find(mac
, maclen
);
883 roff_cblock(ROFF_ARGS
)
887 * A block-close `..' should only be invoked as a child of an
888 * ignore macro, otherwise raise a warning and just ignore it.
891 if (r
->last
== NULL
) {
892 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
,
897 switch (r
->last
->tok
) {
899 /* ROFF_am1 is remapped to ROFF_am in roff_block(). */
904 /* ROFF_de1 is remapped to ROFF_de in roff_block(). */
911 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
,
916 if (buf
->buf
[pos
] != '\0')
917 mandoc_vmsg(MANDOCERR_ARG_SKIP
, r
->parse
, ln
, pos
,
918 ".. %s", buf
->buf
+ pos
);
921 roffnode_cleanscope(r
);
927 roffnode_cleanscope(struct roff
*r
)
931 if (--r
->last
->endspan
!= 0)
938 roff_ccond(struct roff
*r
, int ln
, int ppos
)
941 if (NULL
== r
->last
) {
942 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
,
947 switch (r
->last
->tok
) {
955 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
,
960 if (r
->last
->endspan
> -1) {
961 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
,
967 roffnode_cleanscope(r
);
972 roff_block(ROFF_ARGS
)
978 /* Ignore groff compatibility mode for now. */
982 else if (tok
== ROFF_am1
)
985 /* Parse the macro name argument. */
988 if (tok
== ROFF_ig
) {
993 namesz
= roff_getname(r
, &cp
, ln
, ppos
);
994 iname
[namesz
] = '\0';
997 /* Resolve the macro name argument if it is indirect. */
999 if (namesz
&& (tok
== ROFF_dei
|| tok
== ROFF_ami
)) {
1000 if ((name
= roff_getstrn(r
, iname
, namesz
)) == NULL
) {
1001 mandoc_vmsg(MANDOCERR_STR_UNDEF
,
1002 r
->parse
, ln
, (int)(iname
- buf
->buf
),
1003 "%.*s", (int)namesz
, iname
);
1006 namesz
= strlen(name
);
1010 if (namesz
== 0 && tok
!= ROFF_ig
) {
1011 mandoc_msg(MANDOCERR_REQ_EMPTY
, r
->parse
,
1012 ln
, ppos
, roffs
[tok
].name
);
1016 roffnode_push(r
, tok
, name
, ln
, ppos
);
1019 * At the beginning of a `de' macro, clear the existing string
1020 * with the same name, if there is one. New content will be
1021 * appended from roff_block_text() in multiline mode.
1024 if (tok
== ROFF_de
|| tok
== ROFF_dei
)
1025 roff_setstrn(&r
->strtab
, name
, namesz
, "", 0, 0);
1030 /* Get the custom end marker. */
1033 namesz
= roff_getname(r
, &cp
, ln
, ppos
);
1035 /* Resolve the end marker if it is indirect. */
1037 if (namesz
&& (tok
== ROFF_dei
|| tok
== ROFF_ami
)) {
1038 if ((name
= roff_getstrn(r
, iname
, namesz
)) == NULL
) {
1039 mandoc_vmsg(MANDOCERR_STR_UNDEF
,
1040 r
->parse
, ln
, (int)(iname
- buf
->buf
),
1041 "%.*s", (int)namesz
, iname
);
1044 namesz
= strlen(name
);
1049 r
->last
->end
= mandoc_strndup(name
, namesz
);
1052 mandoc_vmsg(MANDOCERR_ARG_EXCESS
, r
->parse
,
1053 ln
, pos
, ".%s ... %s", roffs
[tok
].name
, cp
);
1059 roff_block_sub(ROFF_ARGS
)
1065 * First check whether a custom macro exists at this level. If
1066 * it does, then check against it. This is some of groff's
1067 * stranger behaviours. If we encountered a custom end-scope
1068 * tag and that tag also happens to be a "real" macro, then we
1069 * need to try interpreting it again as a real macro. If it's
1070 * not, then return ignore. Else continue.
1074 for (i
= pos
, j
= 0; r
->last
->end
[j
]; j
++, i
++)
1075 if (buf
->buf
[i
] != r
->last
->end
[j
])
1078 if (r
->last
->end
[j
] == '\0' &&
1079 (buf
->buf
[i
] == '\0' ||
1080 buf
->buf
[i
] == ' ' ||
1081 buf
->buf
[i
] == '\t')) {
1083 roffnode_cleanscope(r
);
1085 while (buf
->buf
[i
] == ' ' || buf
->buf
[i
] == '\t')
1089 if (roff_parse(r
, buf
->buf
, &pos
, ln
, ppos
) !=
1097 * If we have no custom end-query or lookup failed, then try
1098 * pulling it out of the hashtable.
1101 t
= roff_parse(r
, buf
->buf
, &pos
, ln
, ppos
);
1103 if (t
!= ROFF_cblock
) {
1105 roff_setstr(r
, r
->last
->name
, buf
->buf
+ ppos
, 2);
1109 assert(roffs
[t
].proc
);
1110 return((*roffs
[t
].proc
)(r
, t
, buf
, ln
, ppos
, pos
, offs
));
1114 roff_block_text(ROFF_ARGS
)
1118 roff_setstr(r
, r
->last
->name
, buf
->buf
+ pos
, 2);
1124 roff_cond_sub(ROFF_ARGS
)
1131 roffnode_cleanscope(r
);
1132 t
= roff_parse(r
, buf
->buf
, &pos
, ln
, ppos
);
1135 * Fully handle known macros when they are structurally
1136 * required or when the conditional evaluated to true.
1139 if ((t
!= ROFF_MAX
) &&
1140 (rr
|| roffs
[t
].flags
& ROFFMAC_STRUCT
)) {
1141 assert(roffs
[t
].proc
);
1142 return((*roffs
[t
].proc
)(r
, t
, buf
, ln
, ppos
, pos
, offs
));
1146 * If `\}' occurs on a macro line without a preceding macro,
1147 * drop the line completely.
1150 ep
= buf
->buf
+ pos
;
1151 if (ep
[0] == '\\' && ep
[1] == '}')
1154 /* Always check for the closing delimiter `\}'. */
1156 while ((ep
= strchr(ep
, '\\')) != NULL
) {
1157 if (*(++ep
) == '}') {
1159 roff_ccond(r
, ln
, ep
- buf
->buf
- 1);
1163 return(rr
? ROFF_CONT
: ROFF_IGN
);
1167 roff_cond_text(ROFF_ARGS
)
1173 roffnode_cleanscope(r
);
1175 ep
= buf
->buf
+ pos
;
1176 while ((ep
= strchr(ep
, '\\')) != NULL
) {
1177 if (*(++ep
) == '}') {
1179 roff_ccond(r
, ln
, ep
- buf
->buf
- 1);
1183 return(rr
? ROFF_CONT
: ROFF_IGN
);
1187 * Parse a single signed integer number. Stop at the first non-digit.
1188 * If there is at least one digit, return success and advance the
1189 * parse point, else return failure and let the parse point unchanged.
1190 * Ignore overflows, treat them just like the C language.
1193 roff_getnum(const char *v
, int *pos
, int *res
)
1205 for (*res
= 0; isdigit((unsigned char)v
[p
]); p
++)
1206 *res
= 10 * *res
+ v
[p
] - '0';
1218 * Evaluate a string comparison condition.
1219 * The first character is the delimiter.
1220 * Succeed if the string up to its second occurrence
1221 * matches the string up to its third occurence.
1222 * Advance the cursor after the third occurrence
1223 * or lacking that, to the end of the line.
1226 roff_evalstrcond(const char *v
, int *pos
)
1228 const char *s1
, *s2
, *s3
;
1232 s1
= v
+ *pos
; /* initial delimiter */
1233 s2
= s1
+ 1; /* for scanning the first string */
1234 s3
= strchr(s2
, *s1
); /* for scanning the second string */
1236 if (NULL
== s3
) /* found no middle delimiter */
1239 while ('\0' != *++s3
) {
1240 if (*s2
!= *s3
) { /* mismatch */
1241 s3
= strchr(s3
, *s1
);
1244 if (*s3
== *s1
) { /* found the final delimiter */
1253 s3
= strchr(s2
, '\0');
1254 else if (*s3
!= '\0')
1261 * Evaluate an optionally negated single character, numerical,
1262 * or string condition.
1265 roff_evalcond(struct roff
*r
, int ln
, const char *v
, int *pos
)
1267 int number
, savepos
, wanttrue
;
1269 if ('!' == v
[*pos
]) {
1301 if (roff_evalnum(r
, ln
, v
, pos
, &number
, 0))
1302 return((number
> 0) == wanttrue
);
1303 else if (*pos
== savepos
)
1304 return(roff_evalstrcond(v
, pos
) == wanttrue
);
1310 roff_line_ignore(ROFF_ARGS
)
1317 roff_cond(ROFF_ARGS
)
1320 roffnode_push(r
, tok
, NULL
, ln
, ppos
);
1323 * An `.el' has no conditional body: it will consume the value
1324 * of the current rstack entry set in prior `ie' calls or
1327 * If we're not an `el', however, then evaluate the conditional.
1330 r
->last
->rule
= tok
== ROFF_el
?
1331 (r
->rstackpos
< 0 ? 0 : r
->rstack
[r
->rstackpos
--]) :
1332 roff_evalcond(r
, ln
, buf
->buf
, &pos
);
1335 * An if-else will put the NEGATION of the current evaluated
1336 * conditional into the stack of rules.
1339 if (tok
== ROFF_ie
) {
1340 if (r
->rstackpos
+ 1 == r
->rstacksz
) {
1342 r
->rstack
= mandoc_reallocarray(r
->rstack
,
1343 r
->rstacksz
, sizeof(int));
1345 r
->rstack
[++r
->rstackpos
] = !r
->last
->rule
;
1348 /* If the parent has false as its rule, then so do we. */
1350 if (r
->last
->parent
&& !r
->last
->parent
->rule
)
1355 * If there is nothing on the line after the conditional,
1356 * not even whitespace, use next-line scope.
1359 if (buf
->buf
[pos
] == '\0') {
1360 r
->last
->endspan
= 2;
1364 while (buf
->buf
[pos
] == ' ')
1367 /* An opening brace requests multiline scope. */
1369 if (buf
->buf
[pos
] == '\\' && buf
->buf
[pos
+ 1] == '{') {
1370 r
->last
->endspan
= -1;
1376 * Anything else following the conditional causes
1377 * single-line scope. Warn if the scope contains
1378 * nothing but trailing whitespace.
1381 if (buf
->buf
[pos
] == '\0')
1382 mandoc_msg(MANDOCERR_COND_EMPTY
, r
->parse
,
1383 ln
, ppos
, roffs
[tok
].name
);
1385 r
->last
->endspan
= 1;
1400 * The first word is the name of the string.
1401 * If it is empty or terminated by an escape sequence,
1402 * abort the `ds' request without defining anything.
1405 name
= string
= buf
->buf
+ pos
;
1409 namesz
= roff_getname(r
, &string
, ln
, pos
);
1410 if (name
[namesz
] == '\\')
1413 /* Read past the initial double-quote, if any. */
1417 /* The rest is the value. */
1418 roff_setstrn(&r
->strtab
, name
, namesz
, string
, strlen(string
),
1424 * Parse a single operator, one or two characters long.
1425 * If the operator is recognized, return success and advance the
1426 * parse point, else return failure and let the parse point unchanged.
1429 roff_getop(const char *v
, int *pos
, char *res
)
1450 switch (v
[*pos
+ 1]) {
1468 switch (v
[*pos
+ 1]) {
1482 if ('=' == v
[*pos
+ 1])
1494 * Evaluate either a parenthesized numeric expression
1495 * or a single signed integer number.
1498 roff_evalpar(struct roff
*r
, int ln
,
1499 const char *v
, int *pos
, int *res
)
1503 return(roff_getnum(v
, pos
, res
));
1506 if ( ! roff_evalnum(r
, ln
, v
, pos
, res
, 1))
1510 * Omission of the closing parenthesis
1511 * is an error in validation mode,
1512 * but ignored in evaluation mode.
1517 else if (NULL
== res
)
1524 * Evaluate a complete numeric expression.
1525 * Proceed left to right, there is no concept of precedence.
1528 roff_evalnum(struct roff
*r
, int ln
, const char *v
,
1529 int *pos
, int *res
, int skipwhite
)
1531 int mypos
, operand2
;
1540 while (isspace((unsigned char)v
[*pos
]))
1543 if ( ! roff_evalpar(r
, ln
, v
, pos
, res
))
1548 while (isspace((unsigned char)v
[*pos
]))
1551 if ( ! roff_getop(v
, pos
, &operator))
1555 while (isspace((unsigned char)v
[*pos
]))
1558 if ( ! roff_evalpar(r
, ln
, v
, pos
, &operand2
))
1562 while (isspace((unsigned char)v
[*pos
]))
1579 if (operand2
== 0) {
1580 mandoc_msg(MANDOCERR_DIVZERO
,
1581 r
->parse
, ln
, *pos
, v
);
1588 if (operand2
== 0) {
1589 mandoc_msg(MANDOCERR_DIVZERO
,
1590 r
->parse
, ln
, *pos
, v
);
1597 *res
= *res
< operand2
;
1600 *res
= *res
> operand2
;
1603 *res
= *res
<= operand2
;
1606 *res
= *res
>= operand2
;
1609 *res
= *res
== operand2
;
1612 *res
= *res
!= operand2
;
1615 *res
= *res
&& operand2
;
1618 *res
= *res
|| operand2
;
1621 if (operand2
< *res
)
1625 if (operand2
> *res
)
1636 roff_setreg(struct roff
*r
, const char *name
, int val
, char sign
)
1638 struct roffreg
*reg
;
1640 /* Search for an existing register with the same name. */
1643 while (reg
&& strcmp(name
, reg
->key
.p
))
1647 /* Create a new register. */
1648 reg
= mandoc_malloc(sizeof(struct roffreg
));
1649 reg
->key
.p
= mandoc_strdup(name
);
1650 reg
->key
.sz
= strlen(name
);
1652 reg
->next
= r
->regtab
;
1658 else if ('-' == sign
)
1665 * Handle some predefined read-only number registers.
1666 * For now, return -1 if the requested register is not predefined;
1667 * in case a predefined read-only register having the value -1
1668 * were to turn up, another special value would have to be chosen.
1671 roff_getregro(const char *name
)
1675 case 'A': /* ASCII approximation mode is always off. */
1677 case 'g': /* Groff compatibility mode is always on. */
1679 case 'H': /* Fixed horizontal resolution. */
1681 case 'j': /* Always adjust left margin only. */
1683 case 'T': /* Some output device is always defined. */
1685 case 'V': /* Fixed vertical resolution. */
1693 roff_getreg(const struct roff
*r
, const char *name
)
1695 struct roffreg
*reg
;
1698 if ('.' == name
[0] && '\0' != name
[1] && '\0' == name
[2]) {
1699 val
= roff_getregro(name
+ 1);
1704 for (reg
= r
->regtab
; reg
; reg
= reg
->next
)
1705 if (0 == strcmp(name
, reg
->key
.p
))
1712 roff_getregn(const struct roff
*r
, const char *name
, size_t len
)
1714 struct roffreg
*reg
;
1717 if ('.' == name
[0] && 2 == len
) {
1718 val
= roff_getregro(name
+ 1);
1723 for (reg
= r
->regtab
; reg
; reg
= reg
->next
)
1724 if (len
== reg
->key
.sz
&&
1725 0 == strncmp(name
, reg
->key
.p
, len
))
1732 roff_freereg(struct roffreg
*reg
)
1734 struct roffreg
*old_reg
;
1736 while (NULL
!= reg
) {
1752 key
= val
= buf
->buf
+ pos
;
1756 keysz
= roff_getname(r
, &val
, ln
, pos
);
1757 if (key
[keysz
] == '\\')
1762 if (sign
== '+' || sign
== '-')
1765 if (roff_evalnum(r
, ln
, val
, NULL
, &iv
, 0))
1766 roff_setreg(r
, key
, iv
, sign
);
1774 struct roffreg
*reg
, **prev
;
1778 name
= cp
= buf
->buf
+ pos
;
1781 namesz
= roff_getname(r
, &cp
, ln
, pos
);
1782 name
[namesz
] = '\0';
1787 if (reg
== NULL
|| !strcmp(name
, reg
->key
.p
))
1806 cp
= buf
->buf
+ pos
;
1807 while (*cp
!= '\0') {
1809 namesz
= roff_getname(r
, &cp
, ln
, (int)(cp
- buf
->buf
));
1810 roff_setstrn(&r
->strtab
, name
, namesz
, NULL
, 0, 0);
1811 if (name
[namesz
] == '\\')
1824 /* Parse the number of lines. */
1825 cp
= buf
->buf
+ pos
;
1826 len
= strcspn(cp
, " \t");
1828 if ((iv
= mandoc_strntoi(cp
, len
, 10)) <= 0) {
1829 mandoc_msg(MANDOCERR_IT_NONUM
, r
->parse
,
1830 ln
, ppos
, buf
->buf
+ 1);
1835 /* Arm the input line trap. */
1837 roffit_macro
= mandoc_strdup(cp
);
1844 const char *const *cp
;
1846 if ((r
->options
& (MPARSE_MDOC
| MPARSE_QUICK
)) == 0)
1847 for (cp
= __mdoc_reserved
; *cp
; cp
++)
1848 roff_setstr(r
, *cp
, NULL
, 0);
1851 r
->format
= MPARSE_MDOC
;
1859 const char *const *cp
;
1861 if ((r
->options
& MPARSE_QUICK
) == 0)
1862 for (cp
= __man_reserved
; *cp
; cp
++)
1863 roff_setstr(r
, *cp
, NULL
, 0);
1866 r
->format
= MPARSE_MAN
;
1876 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
,
1889 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
,
1892 tbl_restart(ppos
, ln
, r
->tbl
);
1898 * Handle in-line equation delimiters.
1901 roff_eqndelim(struct roff
*r
, struct buf
*buf
, int pos
)
1904 const char *bef_pr
, *bef_nl
, *mac
, *aft_nl
, *aft_pr
;
1907 * Outside equations, look for an opening delimiter.
1908 * If we are inside an equation, we already know it is
1909 * in-line, or this function wouldn't have been called;
1910 * so look for a closing delimiter.
1913 cp1
= buf
->buf
+ pos
;
1914 cp2
= strchr(cp1
, r
->eqn
== NULL
?
1915 r
->last_eqn
->odelim
: r
->last_eqn
->cdelim
);
1920 bef_pr
= bef_nl
= aft_nl
= aft_pr
= "";
1922 /* Handle preceding text, protecting whitespace. */
1924 if (*buf
->buf
!= '\0') {
1931 * Prepare replacing the delimiter with an equation macro
1932 * and drop leading white space from the equation.
1935 if (r
->eqn
== NULL
) {
1942 /* Handle following text, protecting whitespace. */
1950 /* Do the actual replacement. */
1952 buf
->sz
= mandoc_asprintf(&cp1
, "%s%s%s%s%s%s%s", buf
->buf
,
1953 bef_pr
, bef_nl
, mac
, aft_nl
, aft_pr
, cp2
) + 1;
1957 /* Toggle the in-line state of the eqn subsystem. */
1959 r
->eqn_inline
= r
->eqn
== NULL
;
1960 return(ROFF_REPARSE
);
1968 assert(r
->eqn
== NULL
);
1969 e
= eqn_alloc(ppos
, ln
, r
->parse
);
1972 r
->last_eqn
->next
= e
;
1973 e
->delim
= r
->last_eqn
->delim
;
1974 e
->odelim
= r
->last_eqn
->odelim
;
1975 e
->cdelim
= r
->last_eqn
->cdelim
;
1977 r
->first_eqn
= r
->last_eqn
= e
;
1979 r
->eqn
= r
->last_eqn
= e
;
1981 if (buf
->buf
[pos
] != '\0')
1982 mandoc_vmsg(MANDOCERR_ARG_SKIP
, r
->parse
, ln
, pos
,
1983 ".EQ %s", buf
->buf
+ pos
);
1992 mandoc_msg(MANDOCERR_BLK_NOTOPEN
, r
->parse
, ln
, ppos
, "EN");
1999 struct tbl_node
*tbl
;
2002 mandoc_msg(MANDOCERR_BLK_BROKEN
, r
->parse
,
2003 ln
, ppos
, "TS breaks TS");
2007 tbl
= tbl_alloc(ppos
, ln
, r
->parse
);
2010 r
->last_tbl
->next
= tbl
;
2012 r
->first_tbl
= r
->last_tbl
= tbl
;
2014 r
->tbl
= r
->last_tbl
= tbl
;
2025 if (*p
== '\0' || (r
->control
= *p
++) == '.')
2029 mandoc_msg(MANDOCERR_ARGCOUNT
, r
->parse
, ln
, ppos
, NULL
);
2037 const char *p
, *first
, *second
;
2039 enum mandoc_esc esc
;
2044 mandoc_msg(MANDOCERR_ARGCOUNT
, r
->parse
, ln
, ppos
, NULL
);
2048 while (*p
!= '\0') {
2052 if (*first
== '\\') {
2053 esc
= mandoc_escape(&p
, NULL
, NULL
);
2054 if (esc
== ESCAPE_ERROR
) {
2055 mandoc_msg(MANDOCERR_ESC_BAD
, r
->parse
,
2056 ln
, (int)(p
- buf
->buf
), first
);
2059 fsz
= (size_t)(p
- first
);
2063 if (*second
== '\\') {
2064 esc
= mandoc_escape(&p
, NULL
, NULL
);
2065 if (esc
== ESCAPE_ERROR
) {
2066 mandoc_msg(MANDOCERR_ESC_BAD
, r
->parse
,
2067 ln
, (int)(p
- buf
->buf
), second
);
2070 ssz
= (size_t)(p
- second
);
2071 } else if (*second
== '\0') {
2072 mandoc_msg(MANDOCERR_ARGCOUNT
, r
->parse
,
2073 ln
, (int)(p
- buf
->buf
), NULL
);
2079 roff_setstrn(&r
->xmbtab
, first
, fsz
,
2084 if (r
->xtab
== NULL
)
2085 r
->xtab
= mandoc_calloc(128,
2086 sizeof(struct roffstr
));
2088 free(r
->xtab
[(int)*first
].p
);
2089 r
->xtab
[(int)*first
].p
= mandoc_strndup(second
, ssz
);
2090 r
->xtab
[(int)*first
].sz
= ssz
;
2101 name
= buf
->buf
+ pos
;
2102 mandoc_vmsg(MANDOCERR_SO
, r
->parse
, ln
, ppos
, "so %s", name
);
2105 * Handle `so'. Be EXTREMELY careful, as we shouldn't be
2106 * opening anything that's not in our cwd or anything beneath
2107 * it. Thus, explicitly disallow traversing up the file-system
2108 * or using absolute paths.
2111 if (*name
== '/' || strstr(name
, "../") || strstr(name
, "/..")) {
2112 mandoc_vmsg(MANDOCERR_SO_PATH
, r
->parse
, ln
, ppos
,
2122 roff_userdef(ROFF_ARGS
)
2129 * Collect pointers to macro argument strings
2130 * and NUL-terminate them.
2132 cp
= buf
->buf
+ pos
;
2133 for (i
= 0; i
< 9; i
++)
2134 arg
[i
] = *cp
== '\0' ? "" :
2135 mandoc_getarg(r
->parse
, &cp
, ln
, &pos
);
2138 * Expand macro arguments.
2141 n1
= cp
= mandoc_strdup(r
->current_string
);
2142 while ((cp
= strstr(cp
, "\\$")) != NULL
) {
2144 if (0 > i
|| 8 < i
) {
2145 /* Not an argument invocation. */
2150 buf
->sz
= mandoc_asprintf(&n2
, "%s%s%s",
2151 n1
, arg
[i
], cp
+ 3) + 1;
2152 cp
= n2
+ (cp
- n1
);
2158 * Replace the macro invocation
2159 * by the expanded macro.
2164 buf
->sz
= strlen(buf
->buf
) + 1;
2166 return(buf
->sz
> 1 && buf
->buf
[buf
->sz
- 2] == '\n' ?
2167 ROFF_REPARSE
: ROFF_APPEND
);
2171 roff_getname(struct roff
*r
, char **cpp
, int ln
, int pos
)
2180 /* Read until end of name and terminate it with NUL. */
2181 for (cp
= name
; 1; cp
++) {
2182 if ('\0' == *cp
|| ' ' == *cp
) {
2189 if ('{' == cp
[1] || '}' == cp
[1])
2194 mandoc_vmsg(MANDOCERR_NAMESC
, r
->parse
, ln
, pos
,
2195 "%.*s", (int)(cp
- name
+ 1), name
);
2196 mandoc_escape((const char **)&cp
, NULL
, NULL
);
2200 /* Read past spaces. */
2209 * Store *string into the user-defined string called *name.
2210 * To clear an existing entry, call with (*r, *name, NULL, 0).
2211 * append == 0: replace mode
2212 * append == 1: single-line append mode
2213 * append == 2: multiline append mode, append '\n' after each call
2216 roff_setstr(struct roff
*r
, const char *name
, const char *string
,
2220 roff_setstrn(&r
->strtab
, name
, strlen(name
), string
,
2221 string
? strlen(string
) : 0, append
);
2225 roff_setstrn(struct roffkv
**r
, const char *name
, size_t namesz
,
2226 const char *string
, size_t stringsz
, int append
)
2231 size_t oldch
, newch
;
2233 /* Search for an existing string with the same name. */
2236 while (n
&& (namesz
!= n
->key
.sz
||
2237 strncmp(n
->key
.p
, name
, namesz
)))
2241 /* Create a new string table entry. */
2242 n
= mandoc_malloc(sizeof(struct roffkv
));
2243 n
->key
.p
= mandoc_strndup(name
, namesz
);
2249 } else if (0 == append
) {
2259 * One additional byte for the '\n' in multiline mode,
2260 * and one for the terminating '\0'.
2262 newch
= stringsz
+ (1 < append
? 2u : 1u);
2264 if (NULL
== n
->val
.p
) {
2265 n
->val
.p
= mandoc_malloc(newch
);
2270 n
->val
.p
= mandoc_realloc(n
->val
.p
, oldch
+ newch
);
2273 /* Skip existing content in the destination buffer. */
2274 c
= n
->val
.p
+ (int)oldch
;
2276 /* Append new content to the destination buffer. */
2278 while (i
< (int)stringsz
) {
2280 * Rudimentary roff copy mode:
2281 * Handle escaped backslashes.
2283 if ('\\' == string
[i
] && '\\' == string
[i
+ 1])
2288 /* Append terminating bytes. */
2293 n
->val
.sz
= (int)(c
- n
->val
.p
);
2297 roff_getstrn(const struct roff
*r
, const char *name
, size_t len
)
2299 const struct roffkv
*n
;
2302 for (n
= r
->strtab
; n
; n
= n
->next
)
2303 if (0 == strncmp(name
, n
->key
.p
, len
) &&
2304 '\0' == n
->key
.p
[(int)len
])
2307 for (i
= 0; i
< PREDEFS_MAX
; i
++)
2308 if (0 == strncmp(name
, predefs
[i
].name
, len
) &&
2309 '\0' == predefs
[i
].name
[(int)len
])
2310 return(predefs
[i
].str
);
2316 roff_freestr(struct roffkv
*r
)
2318 struct roffkv
*n
, *nn
;
2320 for (n
= r
; n
; n
= nn
) {
2328 const struct tbl_span
*
2329 roff_span(const struct roff
*r
)
2332 return(r
->tbl
? tbl_span(r
->tbl
) : NULL
);
2336 roff_eqn(const struct roff
*r
)
2339 return(r
->last_eqn
? &r
->last_eqn
->eqn
: NULL
);
2343 * Duplicate an input string, making the appropriate character
2344 * conversations (as stipulated by `tr') along the way.
2345 * Returns a heap-allocated string with all the replacements made.
2348 roff_strdup(const struct roff
*r
, const char *p
)
2350 const struct roffkv
*cp
;
2354 enum mandoc_esc esc
;
2356 if (NULL
== r
->xmbtab
&& NULL
== r
->xtab
)
2357 return(mandoc_strdup(p
));
2358 else if ('\0' == *p
)
2359 return(mandoc_strdup(""));
2362 * Step through each character looking for term matches
2363 * (remember that a `tr' can be invoked with an escape, which is
2364 * a glyph but the escape is multi-character).
2365 * We only do this if the character hash has been initialised
2366 * and the string is >0 length.
2372 while ('\0' != *p
) {
2373 if ('\\' != *p
&& r
->xtab
&& r
->xtab
[(int)*p
].p
) {
2374 sz
= r
->xtab
[(int)*p
].sz
;
2375 res
= mandoc_realloc(res
, ssz
+ sz
+ 1);
2376 memcpy(res
+ ssz
, r
->xtab
[(int)*p
].p
, sz
);
2380 } else if ('\\' != *p
) {
2381 res
= mandoc_realloc(res
, ssz
+ 2);
2386 /* Search for term matches. */
2387 for (cp
= r
->xmbtab
; cp
; cp
= cp
->next
)
2388 if (0 == strncmp(p
, cp
->key
.p
, cp
->key
.sz
))
2393 * A match has been found.
2394 * Append the match to the array and move
2395 * forward by its keysize.
2397 res
= mandoc_realloc(res
,
2398 ssz
+ cp
->val
.sz
+ 1);
2399 memcpy(res
+ ssz
, cp
->val
.p
, cp
->val
.sz
);
2401 p
+= (int)cp
->key
.sz
;
2406 * Handle escapes carefully: we need to copy
2407 * over just the escape itself, or else we might
2408 * do replacements within the escape itself.
2409 * Make sure to pass along the bogus string.
2412 esc
= mandoc_escape(&p
, NULL
, NULL
);
2413 if (ESCAPE_ERROR
== esc
) {
2415 res
= mandoc_realloc(res
, ssz
+ sz
+ 1);
2416 memcpy(res
+ ssz
, pp
, sz
);
2420 * We bail out on bad escapes.
2421 * No need to warn: we already did so when
2422 * roff_res() was called.
2425 res
= mandoc_realloc(res
, ssz
+ sz
+ 1);
2426 memcpy(res
+ ssz
, pp
, sz
);
2430 res
[(int)ssz
] = '\0';
2435 roff_getformat(const struct roff
*r
)
2442 * Find out whether a line is a macro line or not.
2443 * If it is, adjust the current position and return one; if it isn't,
2444 * return zero and don't change the current position.
2445 * If the control character has been set with `.cc', then let that grain
2447 * This is slighly contrary to groff, where using the non-breaking
2448 * control character when `cc' has been invoked will cause the
2449 * non-breaking macro contents to be printed verbatim.
2452 roff_getcontrol(const struct roff
*r
, const char *cp
, int *ppos
)
2458 if (0 != r
->control
&& cp
[pos
] == r
->control
)
2460 else if (0 != r
->control
)
2462 else if ('\\' == cp
[pos
] && '.' == cp
[pos
+ 1])
2464 else if ('.' == cp
[pos
] || '\'' == cp
[pos
])
2469 while (' ' == cp
[pos
] || '\t' == cp
[pos
])