1*6d38604fSBaptiste Daroussin /* $Id: roff.c,v 1.378 2021/08/10 12:55:04 schwarze Exp $ */
261d06d6bSBaptiste Daroussin /*
3*6d38604fSBaptiste Daroussin * Copyright (c) 2010-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org>
461d06d6bSBaptiste Daroussin * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
561d06d6bSBaptiste Daroussin *
661d06d6bSBaptiste Daroussin * Permission to use, copy, modify, and distribute this software for any
761d06d6bSBaptiste Daroussin * purpose with or without fee is hereby granted, provided that the above
861d06d6bSBaptiste Daroussin * copyright notice and this permission notice appear in all copies.
961d06d6bSBaptiste Daroussin *
1061d06d6bSBaptiste Daroussin * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
1161d06d6bSBaptiste Daroussin * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1261d06d6bSBaptiste Daroussin * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
1361d06d6bSBaptiste Daroussin * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1461d06d6bSBaptiste Daroussin * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1561d06d6bSBaptiste Daroussin * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1661d06d6bSBaptiste Daroussin * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*6d38604fSBaptiste Daroussin *
18*6d38604fSBaptiste Daroussin * Implementation of the roff(7) parser for mandoc(1).
1961d06d6bSBaptiste Daroussin */
2061d06d6bSBaptiste Daroussin #include "config.h"
2161d06d6bSBaptiste Daroussin
2261d06d6bSBaptiste Daroussin #include <sys/types.h>
2361d06d6bSBaptiste Daroussin
2461d06d6bSBaptiste Daroussin #include <assert.h>
2561d06d6bSBaptiste Daroussin #include <ctype.h>
2661d06d6bSBaptiste Daroussin #include <limits.h>
2761d06d6bSBaptiste Daroussin #include <stddef.h>
2861d06d6bSBaptiste Daroussin #include <stdint.h>
2961d06d6bSBaptiste Daroussin #include <stdio.h>
3061d06d6bSBaptiste Daroussin #include <stdlib.h>
3161d06d6bSBaptiste Daroussin #include <string.h>
3261d06d6bSBaptiste Daroussin
3361d06d6bSBaptiste Daroussin #include "mandoc_aux.h"
3461d06d6bSBaptiste Daroussin #include "mandoc_ohash.h"
357295610fSBaptiste Daroussin #include "mandoc.h"
3661d06d6bSBaptiste Daroussin #include "roff.h"
377295610fSBaptiste Daroussin #include "mandoc_parse.h"
3861d06d6bSBaptiste Daroussin #include "libmandoc.h"
3961d06d6bSBaptiste Daroussin #include "roff_int.h"
407295610fSBaptiste Daroussin #include "tbl_parse.h"
417295610fSBaptiste Daroussin #include "eqn_parse.h"
427295610fSBaptiste Daroussin
437295610fSBaptiste Daroussin /*
447295610fSBaptiste Daroussin * ASCII_ESC is used to signal from roff_getarg() to roff_expand()
457295610fSBaptiste Daroussin * that an escape sequence resulted from copy-in processing and
467295610fSBaptiste Daroussin * needs to be checked or interpolated. As it is used nowhere
477295610fSBaptiste Daroussin * else, it is defined here rather than in a header file.
487295610fSBaptiste Daroussin */
497295610fSBaptiste Daroussin #define ASCII_ESC 27
5061d06d6bSBaptiste Daroussin
5161d06d6bSBaptiste Daroussin /* Maximum number of string expansions per line, to break infinite loops. */
5261d06d6bSBaptiste Daroussin #define EXPAND_LIMIT 1000
5361d06d6bSBaptiste Daroussin
5461d06d6bSBaptiste Daroussin /* Types of definitions of macros and strings. */
5561d06d6bSBaptiste Daroussin #define ROFFDEF_USER (1 << 1) /* User-defined. */
5661d06d6bSBaptiste Daroussin #define ROFFDEF_PRE (1 << 2) /* Predefined. */
5761d06d6bSBaptiste Daroussin #define ROFFDEF_REN (1 << 3) /* Renamed standard macro. */
5861d06d6bSBaptiste Daroussin #define ROFFDEF_STD (1 << 4) /* mdoc(7) or man(7) macro. */
5961d06d6bSBaptiste Daroussin #define ROFFDEF_ANY (ROFFDEF_USER | ROFFDEF_PRE | \
6061d06d6bSBaptiste Daroussin ROFFDEF_REN | ROFFDEF_STD)
6161d06d6bSBaptiste Daroussin #define ROFFDEF_UNDEF (1 << 5) /* Completely undefined. */
6261d06d6bSBaptiste Daroussin
6361d06d6bSBaptiste Daroussin /* --- data types --------------------------------------------------------- */
6461d06d6bSBaptiste Daroussin
6561d06d6bSBaptiste Daroussin /*
6661d06d6bSBaptiste Daroussin * An incredibly-simple string buffer.
6761d06d6bSBaptiste Daroussin */
6861d06d6bSBaptiste Daroussin struct roffstr {
6961d06d6bSBaptiste Daroussin char *p; /* nil-terminated buffer */
7061d06d6bSBaptiste Daroussin size_t sz; /* saved strlen(p) */
7161d06d6bSBaptiste Daroussin };
7261d06d6bSBaptiste Daroussin
7361d06d6bSBaptiste Daroussin /*
7461d06d6bSBaptiste Daroussin * A key-value roffstr pair as part of a singly-linked list.
7561d06d6bSBaptiste Daroussin */
7661d06d6bSBaptiste Daroussin struct roffkv {
7761d06d6bSBaptiste Daroussin struct roffstr key;
7861d06d6bSBaptiste Daroussin struct roffstr val;
7961d06d6bSBaptiste Daroussin struct roffkv *next; /* next in list */
8061d06d6bSBaptiste Daroussin };
8161d06d6bSBaptiste Daroussin
8261d06d6bSBaptiste Daroussin /*
8361d06d6bSBaptiste Daroussin * A single number register as part of a singly-linked list.
8461d06d6bSBaptiste Daroussin */
8561d06d6bSBaptiste Daroussin struct roffreg {
8661d06d6bSBaptiste Daroussin struct roffstr key;
8761d06d6bSBaptiste Daroussin int val;
8861d06d6bSBaptiste Daroussin int step;
8961d06d6bSBaptiste Daroussin struct roffreg *next;
9061d06d6bSBaptiste Daroussin };
9161d06d6bSBaptiste Daroussin
9261d06d6bSBaptiste Daroussin /*
9361d06d6bSBaptiste Daroussin * Association of request and macro names with token IDs.
9461d06d6bSBaptiste Daroussin */
9561d06d6bSBaptiste Daroussin struct roffreq {
9661d06d6bSBaptiste Daroussin enum roff_tok tok;
9761d06d6bSBaptiste Daroussin char name[];
9861d06d6bSBaptiste Daroussin };
9961d06d6bSBaptiste Daroussin
1007295610fSBaptiste Daroussin /*
1017295610fSBaptiste Daroussin * A macro processing context.
1027295610fSBaptiste Daroussin * More than one is needed when macro calls are nested.
1037295610fSBaptiste Daroussin */
1047295610fSBaptiste Daroussin struct mctx {
1057295610fSBaptiste Daroussin char **argv;
1067295610fSBaptiste Daroussin int argc;
1077295610fSBaptiste Daroussin int argsz;
1087295610fSBaptiste Daroussin };
1097295610fSBaptiste Daroussin
11061d06d6bSBaptiste Daroussin struct roff {
11161d06d6bSBaptiste Daroussin struct roff_man *man; /* mdoc or man parser */
11261d06d6bSBaptiste Daroussin struct roffnode *last; /* leaf of stack */
1137295610fSBaptiste Daroussin struct mctx *mstack; /* stack of macro contexts */
11461d06d6bSBaptiste Daroussin int *rstack; /* stack of inverted `ie' values */
11561d06d6bSBaptiste Daroussin struct ohash *reqtab; /* request lookup table */
11661d06d6bSBaptiste Daroussin struct roffreg *regtab; /* number registers */
11761d06d6bSBaptiste Daroussin struct roffkv *strtab; /* user-defined strings & macros */
11861d06d6bSBaptiste Daroussin struct roffkv *rentab; /* renamed strings & macros */
11961d06d6bSBaptiste Daroussin struct roffkv *xmbtab; /* multi-byte trans table (`tr') */
12061d06d6bSBaptiste Daroussin struct roffstr *xtab; /* single-byte trans table (`tr') */
12161d06d6bSBaptiste Daroussin const char *current_string; /* value of last called user macro */
12261d06d6bSBaptiste Daroussin struct tbl_node *first_tbl; /* first table parsed */
12361d06d6bSBaptiste Daroussin struct tbl_node *last_tbl; /* last table parsed */
12461d06d6bSBaptiste Daroussin struct tbl_node *tbl; /* current table being parsed */
12561d06d6bSBaptiste Daroussin struct eqn_node *last_eqn; /* equation parser */
12661d06d6bSBaptiste Daroussin struct eqn_node *eqn; /* active equation parser */
12761d06d6bSBaptiste Daroussin int eqn_inline; /* current equation is inline */
12861d06d6bSBaptiste Daroussin int options; /* parse options */
1297295610fSBaptiste Daroussin int mstacksz; /* current size of mstack */
1307295610fSBaptiste Daroussin int mstackpos; /* position in mstack */
13161d06d6bSBaptiste Daroussin int rstacksz; /* current size limit of rstack */
13261d06d6bSBaptiste Daroussin int rstackpos; /* position in rstack */
13361d06d6bSBaptiste Daroussin int format; /* current file in mdoc or man format */
13461d06d6bSBaptiste Daroussin char control; /* control character */
13561d06d6bSBaptiste Daroussin char escape; /* escape character */
13661d06d6bSBaptiste Daroussin };
13761d06d6bSBaptiste Daroussin
13845a5aec3SBaptiste Daroussin /*
13945a5aec3SBaptiste Daroussin * A macro definition, condition, or ignored block.
14045a5aec3SBaptiste Daroussin */
14161d06d6bSBaptiste Daroussin struct roffnode {
14261d06d6bSBaptiste Daroussin enum roff_tok tok; /* type of node */
14361d06d6bSBaptiste Daroussin struct roffnode *parent; /* up one in stack */
14461d06d6bSBaptiste Daroussin int line; /* parse line */
14561d06d6bSBaptiste Daroussin int col; /* parse col */
14661d06d6bSBaptiste Daroussin char *name; /* node name, e.g. macro name */
14745a5aec3SBaptiste Daroussin char *end; /* custom end macro of the block */
14845a5aec3SBaptiste Daroussin int endspan; /* scope to: 1=eol 2=next line -1=\} */
14945a5aec3SBaptiste Daroussin int rule; /* content is: 1=evaluated 0=skipped */
15061d06d6bSBaptiste Daroussin };
15161d06d6bSBaptiste Daroussin
15261d06d6bSBaptiste Daroussin #define ROFF_ARGS struct roff *r, /* parse ctx */ \
15361d06d6bSBaptiste Daroussin enum roff_tok tok, /* tok of macro */ \
15461d06d6bSBaptiste Daroussin struct buf *buf, /* input buffer */ \
15561d06d6bSBaptiste Daroussin int ln, /* parse line */ \
15661d06d6bSBaptiste Daroussin int ppos, /* original pos in buffer */ \
15761d06d6bSBaptiste Daroussin int pos, /* current pos in buffer */ \
15861d06d6bSBaptiste Daroussin int *offs /* reset offset of buffer data */
15961d06d6bSBaptiste Daroussin
1607295610fSBaptiste Daroussin typedef int (*roffproc)(ROFF_ARGS);
16161d06d6bSBaptiste Daroussin
16261d06d6bSBaptiste Daroussin struct roffmac {
16361d06d6bSBaptiste Daroussin roffproc proc; /* process new macro */
16461d06d6bSBaptiste Daroussin roffproc text; /* process as child text of macro */
16561d06d6bSBaptiste Daroussin roffproc sub; /* process as child of macro */
16661d06d6bSBaptiste Daroussin int flags;
16761d06d6bSBaptiste Daroussin #define ROFFMAC_STRUCT (1 << 0) /* always interpret */
16861d06d6bSBaptiste Daroussin };
16961d06d6bSBaptiste Daroussin
17061d06d6bSBaptiste Daroussin struct predef {
17161d06d6bSBaptiste Daroussin const char *name; /* predefined input name */
17261d06d6bSBaptiste Daroussin const char *str; /* replacement symbol */
17361d06d6bSBaptiste Daroussin };
17461d06d6bSBaptiste Daroussin
17561d06d6bSBaptiste Daroussin #define PREDEF(__name, __str) \
17661d06d6bSBaptiste Daroussin { (__name), (__str) },
17761d06d6bSBaptiste Daroussin
17861d06d6bSBaptiste Daroussin /* --- function prototypes ------------------------------------------------ */
17961d06d6bSBaptiste Daroussin
1807295610fSBaptiste Daroussin static int roffnode_cleanscope(struct roff *);
1817295610fSBaptiste Daroussin static int roffnode_pop(struct roff *);
18261d06d6bSBaptiste Daroussin static void roffnode_push(struct roff *, enum roff_tok,
18361d06d6bSBaptiste Daroussin const char *, int, int);
1847295610fSBaptiste Daroussin static void roff_addtbl(struct roff_man *, int, struct tbl_node *);
1857295610fSBaptiste Daroussin static int roff_als(ROFF_ARGS);
1867295610fSBaptiste Daroussin static int roff_block(ROFF_ARGS);
1877295610fSBaptiste Daroussin static int roff_block_text(ROFF_ARGS);
1887295610fSBaptiste Daroussin static int roff_block_sub(ROFF_ARGS);
18945a5aec3SBaptiste Daroussin static int roff_break(ROFF_ARGS);
1907295610fSBaptiste Daroussin static int roff_cblock(ROFF_ARGS);
1917295610fSBaptiste Daroussin static int roff_cc(ROFF_ARGS);
1927295610fSBaptiste Daroussin static int roff_ccond(struct roff *, int, int);
1937295610fSBaptiste Daroussin static int roff_char(ROFF_ARGS);
1947295610fSBaptiste Daroussin static int roff_cond(ROFF_ARGS);
195*6d38604fSBaptiste Daroussin static int roff_cond_checkend(ROFF_ARGS);
1967295610fSBaptiste Daroussin static int roff_cond_text(ROFF_ARGS);
1977295610fSBaptiste Daroussin static int roff_cond_sub(ROFF_ARGS);
1987295610fSBaptiste Daroussin static int roff_ds(ROFF_ARGS);
1997295610fSBaptiste Daroussin static int roff_ec(ROFF_ARGS);
2007295610fSBaptiste Daroussin static int roff_eo(ROFF_ARGS);
2017295610fSBaptiste Daroussin static int roff_eqndelim(struct roff *, struct buf *, int);
202*6d38604fSBaptiste Daroussin static int roff_evalcond(struct roff *, int, char *, int *);
20361d06d6bSBaptiste Daroussin static int roff_evalnum(struct roff *, int,
20461d06d6bSBaptiste Daroussin const char *, int *, int *, int);
20561d06d6bSBaptiste Daroussin static int roff_evalpar(struct roff *, int,
20661d06d6bSBaptiste Daroussin const char *, int *, int *, int);
20761d06d6bSBaptiste Daroussin static int roff_evalstrcond(const char *, int *);
2087295610fSBaptiste Daroussin static int roff_expand(struct roff *, struct buf *,
2097295610fSBaptiste Daroussin int, int, char);
21061d06d6bSBaptiste Daroussin static void roff_free1(struct roff *);
21161d06d6bSBaptiste Daroussin static void roff_freereg(struct roffreg *);
21261d06d6bSBaptiste Daroussin static void roff_freestr(struct roffkv *);
21361d06d6bSBaptiste Daroussin static size_t roff_getname(struct roff *, char **, int, int);
21461d06d6bSBaptiste Daroussin static int roff_getnum(const char *, int *, int *, int);
21561d06d6bSBaptiste Daroussin static int roff_getop(const char *, int *, char *);
21661d06d6bSBaptiste Daroussin static int roff_getregn(struct roff *,
21761d06d6bSBaptiste Daroussin const char *, size_t, char);
21861d06d6bSBaptiste Daroussin static int roff_getregro(const struct roff *,
21961d06d6bSBaptiste Daroussin const char *name);
22061d06d6bSBaptiste Daroussin static const char *roff_getstrn(struct roff *,
22161d06d6bSBaptiste Daroussin const char *, size_t, int *);
22261d06d6bSBaptiste Daroussin static int roff_hasregn(const struct roff *,
22361d06d6bSBaptiste Daroussin const char *, size_t);
2247295610fSBaptiste Daroussin static int roff_insec(ROFF_ARGS);
2257295610fSBaptiste Daroussin static int roff_it(ROFF_ARGS);
2267295610fSBaptiste Daroussin static int roff_line_ignore(ROFF_ARGS);
22761d06d6bSBaptiste Daroussin static void roff_man_alloc1(struct roff_man *);
22861d06d6bSBaptiste Daroussin static void roff_man_free1(struct roff_man *);
2297295610fSBaptiste Daroussin static int roff_manyarg(ROFF_ARGS);
2307295610fSBaptiste Daroussin static int roff_noarg(ROFF_ARGS);
2317295610fSBaptiste Daroussin static int roff_nop(ROFF_ARGS);
2327295610fSBaptiste Daroussin static int roff_nr(ROFF_ARGS);
2337295610fSBaptiste Daroussin static int roff_onearg(ROFF_ARGS);
23461d06d6bSBaptiste Daroussin static enum roff_tok roff_parse(struct roff *, char *, int *,
23561d06d6bSBaptiste Daroussin int, int);
2367295610fSBaptiste Daroussin static int roff_parsetext(struct roff *, struct buf *,
23761d06d6bSBaptiste Daroussin int, int *);
2387295610fSBaptiste Daroussin static int roff_renamed(ROFF_ARGS);
2397295610fSBaptiste Daroussin static int roff_return(ROFF_ARGS);
2407295610fSBaptiste Daroussin static int roff_rm(ROFF_ARGS);
2417295610fSBaptiste Daroussin static int roff_rn(ROFF_ARGS);
2427295610fSBaptiste Daroussin static int roff_rr(ROFF_ARGS);
24361d06d6bSBaptiste Daroussin static void roff_setregn(struct roff *, const char *,
24461d06d6bSBaptiste Daroussin size_t, int, char, int);
24561d06d6bSBaptiste Daroussin static void roff_setstr(struct roff *,
24661d06d6bSBaptiste Daroussin const char *, const char *, int);
24761d06d6bSBaptiste Daroussin static void roff_setstrn(struct roffkv **, const char *,
24861d06d6bSBaptiste Daroussin size_t, const char *, size_t, int);
2497295610fSBaptiste Daroussin static int roff_shift(ROFF_ARGS);
2507295610fSBaptiste Daroussin static int roff_so(ROFF_ARGS);
2517295610fSBaptiste Daroussin static int roff_tr(ROFF_ARGS);
2527295610fSBaptiste Daroussin static int roff_Dd(ROFF_ARGS);
2537295610fSBaptiste Daroussin static int roff_TE(ROFF_ARGS);
2547295610fSBaptiste Daroussin static int roff_TS(ROFF_ARGS);
2557295610fSBaptiste Daroussin static int roff_EQ(ROFF_ARGS);
2567295610fSBaptiste Daroussin static int roff_EN(ROFF_ARGS);
2577295610fSBaptiste Daroussin static int roff_T_(ROFF_ARGS);
2587295610fSBaptiste Daroussin static int roff_unsupp(ROFF_ARGS);
2597295610fSBaptiste Daroussin static int roff_userdef(ROFF_ARGS);
26061d06d6bSBaptiste Daroussin
26161d06d6bSBaptiste Daroussin /* --- constant data ------------------------------------------------------ */
26261d06d6bSBaptiste Daroussin
26361d06d6bSBaptiste Daroussin #define ROFFNUM_SCALE (1 << 0) /* Honour scaling in roff_getnum(). */
26461d06d6bSBaptiste Daroussin #define ROFFNUM_WHITE (1 << 1) /* Skip whitespace in roff_evalnum(). */
26561d06d6bSBaptiste Daroussin
26661d06d6bSBaptiste Daroussin const char *__roff_name[MAN_MAX + 1] = {
2677295610fSBaptiste Daroussin "br", "ce", "fi", "ft",
2687295610fSBaptiste Daroussin "ll", "mc", "nf",
2697295610fSBaptiste Daroussin "po", "rj", "sp",
27061d06d6bSBaptiste Daroussin "ta", "ti", NULL,
27161d06d6bSBaptiste Daroussin "ab", "ad", "af", "aln",
27261d06d6bSBaptiste Daroussin "als", "am", "am1", "ami",
27361d06d6bSBaptiste Daroussin "ami1", "as", "as1", "asciify",
27461d06d6bSBaptiste Daroussin "backtrace", "bd", "bleedat", "blm",
27561d06d6bSBaptiste Daroussin "box", "boxa", "bp", "BP",
27661d06d6bSBaptiste Daroussin "break", "breakchar", "brnl", "brp",
27761d06d6bSBaptiste Daroussin "brpnl", "c2", "cc",
27861d06d6bSBaptiste Daroussin "cf", "cflags", "ch", "char",
27961d06d6bSBaptiste Daroussin "chop", "class", "close", "CL",
28061d06d6bSBaptiste Daroussin "color", "composite", "continue", "cp",
28161d06d6bSBaptiste Daroussin "cropat", "cs", "cu", "da",
28261d06d6bSBaptiste Daroussin "dch", "Dd", "de", "de1",
28361d06d6bSBaptiste Daroussin "defcolor", "dei", "dei1", "device",
28461d06d6bSBaptiste Daroussin "devicem", "di", "do", "ds",
28561d06d6bSBaptiste Daroussin "ds1", "dwh", "dt", "ec",
28661d06d6bSBaptiste Daroussin "ecr", "ecs", "el", "em",
28761d06d6bSBaptiste Daroussin "EN", "eo", "EP", "EQ",
28861d06d6bSBaptiste Daroussin "errprint", "ev", "evc", "ex",
28961d06d6bSBaptiste Daroussin "fallback", "fam", "fc", "fchar",
29061d06d6bSBaptiste Daroussin "fcolor", "fdeferlig", "feature", "fkern",
29161d06d6bSBaptiste Daroussin "fl", "flig", "fp", "fps",
29261d06d6bSBaptiste Daroussin "fschar", "fspacewidth", "fspecial", "ftr",
29361d06d6bSBaptiste Daroussin "fzoom", "gcolor", "hc", "hcode",
29461d06d6bSBaptiste Daroussin "hidechar", "hla", "hlm", "hpf",
29561d06d6bSBaptiste Daroussin "hpfa", "hpfcode", "hw", "hy",
29661d06d6bSBaptiste Daroussin "hylang", "hylen", "hym", "hypp",
29761d06d6bSBaptiste Daroussin "hys", "ie", "if", "ig",
29861d06d6bSBaptiste Daroussin "index", "it", "itc", "IX",
29961d06d6bSBaptiste Daroussin "kern", "kernafter", "kernbefore", "kernpair",
30061d06d6bSBaptiste Daroussin "lc", "lc_ctype", "lds", "length",
30161d06d6bSBaptiste Daroussin "letadj", "lf", "lg", "lhang",
30261d06d6bSBaptiste Daroussin "linetabs", "lnr", "lnrf", "lpfx",
30361d06d6bSBaptiste Daroussin "ls", "lsm", "lt",
30461d06d6bSBaptiste Daroussin "mediasize", "minss", "mk", "mso",
30561d06d6bSBaptiste Daroussin "na", "ne", "nh", "nhychar",
30661d06d6bSBaptiste Daroussin "nm", "nn", "nop", "nr",
30761d06d6bSBaptiste Daroussin "nrf", "nroff", "ns", "nx",
30861d06d6bSBaptiste Daroussin "open", "opena", "os", "output",
30961d06d6bSBaptiste Daroussin "padj", "papersize", "pc", "pev",
31061d06d6bSBaptiste Daroussin "pi", "PI", "pl", "pm",
31161d06d6bSBaptiste Daroussin "pn", "pnr", "ps",
31261d06d6bSBaptiste Daroussin "psbb", "pshape", "pso", "ptr",
31361d06d6bSBaptiste Daroussin "pvs", "rchar", "rd", "recursionlimit",
31461d06d6bSBaptiste Daroussin "return", "rfschar", "rhang",
31561d06d6bSBaptiste Daroussin "rm", "rn", "rnn", "rr",
31661d06d6bSBaptiste Daroussin "rs", "rt", "schar", "sentchar",
31761d06d6bSBaptiste Daroussin "shc", "shift", "sizes", "so",
31861d06d6bSBaptiste Daroussin "spacewidth", "special", "spreadwarn", "ss",
31961d06d6bSBaptiste Daroussin "sty", "substring", "sv", "sy",
32061d06d6bSBaptiste Daroussin "T&", "tc", "TE",
32161d06d6bSBaptiste Daroussin "TH", "tkf", "tl",
32261d06d6bSBaptiste Daroussin "tm", "tm1", "tmc", "tr",
32361d06d6bSBaptiste Daroussin "track", "transchar", "trf", "trimat",
32461d06d6bSBaptiste Daroussin "trin", "trnt", "troff", "TS",
32561d06d6bSBaptiste Daroussin "uf", "ul", "unformat", "unwatch",
32661d06d6bSBaptiste Daroussin "unwatchn", "vpt", "vs", "warn",
32761d06d6bSBaptiste Daroussin "warnscale", "watch", "watchlength", "watchn",
32861d06d6bSBaptiste Daroussin "wh", "while", "write", "writec",
32961d06d6bSBaptiste Daroussin "writem", "xflag", ".", NULL,
33061d06d6bSBaptiste Daroussin NULL, "text",
33161d06d6bSBaptiste Daroussin "Dd", "Dt", "Os", "Sh",
33261d06d6bSBaptiste Daroussin "Ss", "Pp", "D1", "Dl",
33361d06d6bSBaptiste Daroussin "Bd", "Ed", "Bl", "El",
33461d06d6bSBaptiste Daroussin "It", "Ad", "An", "Ap",
33561d06d6bSBaptiste Daroussin "Ar", "Cd", "Cm", "Dv",
33661d06d6bSBaptiste Daroussin "Er", "Ev", "Ex", "Fa",
33761d06d6bSBaptiste Daroussin "Fd", "Fl", "Fn", "Ft",
33861d06d6bSBaptiste Daroussin "Ic", "In", "Li", "Nd",
33961d06d6bSBaptiste Daroussin "Nm", "Op", "Ot", "Pa",
34061d06d6bSBaptiste Daroussin "Rv", "St", "Va", "Vt",
34161d06d6bSBaptiste Daroussin "Xr", "%A", "%B", "%D",
34261d06d6bSBaptiste Daroussin "%I", "%J", "%N", "%O",
34361d06d6bSBaptiste Daroussin "%P", "%R", "%T", "%V",
34461d06d6bSBaptiste Daroussin "Ac", "Ao", "Aq", "At",
34561d06d6bSBaptiste Daroussin "Bc", "Bf", "Bo", "Bq",
34661d06d6bSBaptiste Daroussin "Bsx", "Bx", "Db", "Dc",
34761d06d6bSBaptiste Daroussin "Do", "Dq", "Ec", "Ef",
34861d06d6bSBaptiste Daroussin "Em", "Eo", "Fx", "Ms",
34961d06d6bSBaptiste Daroussin "No", "Ns", "Nx", "Ox",
35061d06d6bSBaptiste Daroussin "Pc", "Pf", "Po", "Pq",
35161d06d6bSBaptiste Daroussin "Qc", "Ql", "Qo", "Qq",
35261d06d6bSBaptiste Daroussin "Re", "Rs", "Sc", "So",
35361d06d6bSBaptiste Daroussin "Sq", "Sm", "Sx", "Sy",
35461d06d6bSBaptiste Daroussin "Tn", "Ux", "Xc", "Xo",
35561d06d6bSBaptiste Daroussin "Fo", "Fc", "Oo", "Oc",
35661d06d6bSBaptiste Daroussin "Bk", "Ek", "Bt", "Hf",
35761d06d6bSBaptiste Daroussin "Fr", "Ud", "Lb", "Lp",
35861d06d6bSBaptiste Daroussin "Lk", "Mt", "Brq", "Bro",
35961d06d6bSBaptiste Daroussin "Brc", "%C", "Es", "En",
36061d06d6bSBaptiste Daroussin "Dx", "%Q", "%U", "Ta",
361*6d38604fSBaptiste Daroussin "Tg", NULL,
36261d06d6bSBaptiste Daroussin "TH", "SH", "SS", "TP",
3637295610fSBaptiste Daroussin "TQ",
36461d06d6bSBaptiste Daroussin "LP", "PP", "P", "IP",
36561d06d6bSBaptiste Daroussin "HP", "SM", "SB", "BI",
36661d06d6bSBaptiste Daroussin "IB", "BR", "RB", "R",
36761d06d6bSBaptiste Daroussin "B", "I", "IR", "RI",
36861d06d6bSBaptiste Daroussin "RE", "RS", "DT", "UC",
36961d06d6bSBaptiste Daroussin "PD", "AT", "in",
3707295610fSBaptiste Daroussin "SY", "YS", "OP",
3717295610fSBaptiste Daroussin "EX", "EE", "UR",
37261d06d6bSBaptiste Daroussin "UE", "MT", "ME", NULL
37361d06d6bSBaptiste Daroussin };
37461d06d6bSBaptiste Daroussin const char *const *roff_name = __roff_name;
37561d06d6bSBaptiste Daroussin
37661d06d6bSBaptiste Daroussin static struct roffmac roffs[TOKEN_NONE] = {
3777295610fSBaptiste Daroussin { roff_noarg, NULL, NULL, 0 }, /* br */
37861d06d6bSBaptiste Daroussin { roff_onearg, NULL, NULL, 0 }, /* ce */
3797295610fSBaptiste Daroussin { roff_noarg, NULL, NULL, 0 }, /* fi */
38061d06d6bSBaptiste Daroussin { roff_onearg, NULL, NULL, 0 }, /* ft */
38161d06d6bSBaptiste Daroussin { roff_onearg, NULL, NULL, 0 }, /* ll */
38261d06d6bSBaptiste Daroussin { roff_onearg, NULL, NULL, 0 }, /* mc */
3837295610fSBaptiste Daroussin { roff_noarg, NULL, NULL, 0 }, /* nf */
38461d06d6bSBaptiste Daroussin { roff_onearg, NULL, NULL, 0 }, /* po */
38561d06d6bSBaptiste Daroussin { roff_onearg, NULL, NULL, 0 }, /* rj */
38661d06d6bSBaptiste Daroussin { roff_onearg, NULL, NULL, 0 }, /* sp */
38761d06d6bSBaptiste Daroussin { roff_manyarg, NULL, NULL, 0 }, /* ta */
38861d06d6bSBaptiste Daroussin { roff_onearg, NULL, NULL, 0 }, /* ti */
38961d06d6bSBaptiste Daroussin { NULL, NULL, NULL, 0 }, /* ROFF_MAX */
39061d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* ab */
39161d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* ad */
39261d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* af */
39361d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* aln */
39461d06d6bSBaptiste Daroussin { roff_als, NULL, NULL, 0 }, /* als */
39561d06d6bSBaptiste Daroussin { roff_block, roff_block_text, roff_block_sub, 0 }, /* am */
39661d06d6bSBaptiste Daroussin { roff_block, roff_block_text, roff_block_sub, 0 }, /* am1 */
39761d06d6bSBaptiste Daroussin { roff_block, roff_block_text, roff_block_sub, 0 }, /* ami */
39861d06d6bSBaptiste Daroussin { roff_block, roff_block_text, roff_block_sub, 0 }, /* ami1 */
39961d06d6bSBaptiste Daroussin { roff_ds, NULL, NULL, 0 }, /* as */
40061d06d6bSBaptiste Daroussin { roff_ds, NULL, NULL, 0 }, /* as1 */
40161d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* asciify */
40261d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* backtrace */
40361d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* bd */
40461d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* bleedat */
40561d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* blm */
40661d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* box */
40761d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* boxa */
40861d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* bp */
40961d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* BP */
41045a5aec3SBaptiste Daroussin { roff_break, NULL, NULL, 0 }, /* break */
41161d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* breakchar */
41261d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* brnl */
4137295610fSBaptiste Daroussin { roff_noarg, NULL, NULL, 0 }, /* brp */
41461d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* brpnl */
41561d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* c2 */
41661d06d6bSBaptiste Daroussin { roff_cc, NULL, NULL, 0 }, /* cc */
41761d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* cf */
41861d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* cflags */
41961d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* ch */
4207295610fSBaptiste Daroussin { roff_char, NULL, NULL, 0 }, /* char */
42161d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* chop */
42261d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* class */
42361d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* close */
42461d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* CL */
42561d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* color */
42661d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* composite */
42761d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* continue */
42861d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* cp */
42961d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* cropat */
43061d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* cs */
43161d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* cu */
43261d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* da */
43361d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* dch */
43461d06d6bSBaptiste Daroussin { roff_Dd, NULL, NULL, 0 }, /* Dd */
43561d06d6bSBaptiste Daroussin { roff_block, roff_block_text, roff_block_sub, 0 }, /* de */
43661d06d6bSBaptiste Daroussin { roff_block, roff_block_text, roff_block_sub, 0 }, /* de1 */
43761d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* defcolor */
43861d06d6bSBaptiste Daroussin { roff_block, roff_block_text, roff_block_sub, 0 }, /* dei */
43961d06d6bSBaptiste Daroussin { roff_block, roff_block_text, roff_block_sub, 0 }, /* dei1 */
44061d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* device */
44161d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* devicem */
44261d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* di */
44361d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* do */
44461d06d6bSBaptiste Daroussin { roff_ds, NULL, NULL, 0 }, /* ds */
44561d06d6bSBaptiste Daroussin { roff_ds, NULL, NULL, 0 }, /* ds1 */
44661d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* dwh */
44761d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* dt */
44861d06d6bSBaptiste Daroussin { roff_ec, NULL, NULL, 0 }, /* ec */
44961d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* ecr */
45061d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* ecs */
45161d06d6bSBaptiste Daroussin { roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT }, /* el */
45261d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* em */
45361d06d6bSBaptiste Daroussin { roff_EN, NULL, NULL, 0 }, /* EN */
45461d06d6bSBaptiste Daroussin { roff_eo, NULL, NULL, 0 }, /* eo */
45561d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* EP */
45661d06d6bSBaptiste Daroussin { roff_EQ, NULL, NULL, 0 }, /* EQ */
45761d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* errprint */
45861d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* ev */
45961d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* evc */
46061d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* ex */
46161d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* fallback */
46261d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* fam */
46361d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* fc */
46461d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* fchar */
46561d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* fcolor */
46661d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* fdeferlig */
46761d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* feature */
46861d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* fkern */
46961d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* fl */
47061d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* flig */
47161d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* fp */
47261d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* fps */
47361d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* fschar */
47461d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* fspacewidth */
47561d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* fspecial */
47661d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* ftr */
47761d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* fzoom */
47861d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* gcolor */
47961d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hc */
48061d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hcode */
48161d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hidechar */
48261d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hla */
48361d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hlm */
48461d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hpf */
48561d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hpfa */
48661d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hpfcode */
48761d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hw */
48861d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hy */
48961d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hylang */
49061d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hylen */
49161d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hym */
49261d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hypp */
49361d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hys */
49461d06d6bSBaptiste Daroussin { roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT }, /* ie */
49561d06d6bSBaptiste Daroussin { roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT }, /* if */
49661d06d6bSBaptiste Daroussin { roff_block, roff_block_text, roff_block_sub, 0 }, /* ig */
49761d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* index */
49861d06d6bSBaptiste Daroussin { roff_it, NULL, NULL, 0 }, /* it */
49961d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* itc */
50061d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* IX */
50161d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* kern */
50261d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* kernafter */
50361d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* kernbefore */
50461d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* kernpair */
50561d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* lc */
50661d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* lc_ctype */
50761d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* lds */
50861d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* length */
50961d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* letadj */
51061d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* lf */
51161d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* lg */
51261d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* lhang */
51361d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* linetabs */
51461d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* lnr */
51561d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* lnrf */
51661d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* lpfx */
51761d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* ls */
51861d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* lsm */
51961d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* lt */
52061d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* mediasize */
52161d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* minss */
52261d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* mk */
52361d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* mso */
52461d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* na */
52561d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* ne */
52661d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* nh */
52761d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* nhychar */
52861d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* nm */
52961d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* nn */
5307295610fSBaptiste Daroussin { roff_nop, NULL, NULL, 0 }, /* nop */
53161d06d6bSBaptiste Daroussin { roff_nr, NULL, NULL, 0 }, /* nr */
53261d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* nrf */
53361d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* nroff */
53461d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* ns */
53561d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* nx */
53661d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* open */
53761d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* opena */
53861d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* os */
53961d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* output */
54061d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* padj */
54161d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* papersize */
54261d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* pc */
54361d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* pev */
54461d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* pi */
54561d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* PI */
54661d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* pl */
54761d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* pm */
54861d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* pn */
54961d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* pnr */
55061d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* ps */
55161d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* psbb */
55261d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* pshape */
55361d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* pso */
55461d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* ptr */
55561d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* pvs */
55661d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* rchar */
55761d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* rd */
55861d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* recursionlimit */
5597295610fSBaptiste Daroussin { roff_return, NULL, NULL, 0 }, /* return */
56061d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* rfschar */
56161d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* rhang */
56261d06d6bSBaptiste Daroussin { roff_rm, NULL, NULL, 0 }, /* rm */
56361d06d6bSBaptiste Daroussin { roff_rn, NULL, NULL, 0 }, /* rn */
56461d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* rnn */
56561d06d6bSBaptiste Daroussin { roff_rr, NULL, NULL, 0 }, /* rr */
56661d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* rs */
56761d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* rt */
56861d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* schar */
56961d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* sentchar */
57061d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* shc */
5717295610fSBaptiste Daroussin { roff_shift, NULL, NULL, 0 }, /* shift */
57261d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* sizes */
57361d06d6bSBaptiste Daroussin { roff_so, NULL, NULL, 0 }, /* so */
57461d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* spacewidth */
57561d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* special */
57661d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* spreadwarn */
57761d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* ss */
57861d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* sty */
57961d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* substring */
58061d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* sv */
58161d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* sy */
58261d06d6bSBaptiste Daroussin { roff_T_, NULL, NULL, 0 }, /* T& */
58361d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* tc */
58461d06d6bSBaptiste Daroussin { roff_TE, NULL, NULL, 0 }, /* TE */
58561d06d6bSBaptiste Daroussin { roff_Dd, NULL, NULL, 0 }, /* TH */
58661d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* tkf */
58761d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* tl */
58861d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* tm */
58961d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* tm1 */
59061d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* tmc */
59161d06d6bSBaptiste Daroussin { roff_tr, NULL, NULL, 0 }, /* tr */
59261d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* track */
59361d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* transchar */
59461d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* trf */
59561d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* trimat */
59661d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* trin */
59761d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* trnt */
59861d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* troff */
59961d06d6bSBaptiste Daroussin { roff_TS, NULL, NULL, 0 }, /* TS */
60061d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* uf */
60161d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* ul */
60261d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* unformat */
60361d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* unwatch */
60461d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* unwatchn */
60561d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* vpt */
60661d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* vs */
60761d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* warn */
60861d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* warnscale */
60961d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* watch */
61061d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* watchlength */
61161d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* watchn */
61261d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* wh */
6137295610fSBaptiste Daroussin { roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT }, /*while*/
61461d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* write */
61561d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* writec */
61661d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* writem */
61761d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* xflag */
61861d06d6bSBaptiste Daroussin { roff_cblock, NULL, NULL, 0 }, /* . */
61961d06d6bSBaptiste Daroussin { roff_renamed, NULL, NULL, 0 },
62061d06d6bSBaptiste Daroussin { roff_userdef, NULL, NULL, 0 }
62161d06d6bSBaptiste Daroussin };
62261d06d6bSBaptiste Daroussin
62361d06d6bSBaptiste Daroussin /* Array of injected predefined strings. */
62461d06d6bSBaptiste Daroussin #define PREDEFS_MAX 38
62561d06d6bSBaptiste Daroussin static const struct predef predefs[PREDEFS_MAX] = {
62661d06d6bSBaptiste Daroussin #include "predefs.in"
62761d06d6bSBaptiste Daroussin };
62861d06d6bSBaptiste Daroussin
62961d06d6bSBaptiste Daroussin static int roffce_lines; /* number of input lines to center */
63061d06d6bSBaptiste Daroussin static struct roff_node *roffce_node; /* active request */
63161d06d6bSBaptiste Daroussin static int roffit_lines; /* number of lines to delay */
63261d06d6bSBaptiste Daroussin static char *roffit_macro; /* nil-terminated macro line */
63361d06d6bSBaptiste Daroussin
63461d06d6bSBaptiste Daroussin
63561d06d6bSBaptiste Daroussin /* --- request table ------------------------------------------------------ */
63661d06d6bSBaptiste Daroussin
63761d06d6bSBaptiste Daroussin struct ohash *
roffhash_alloc(enum roff_tok mintok,enum roff_tok maxtok)63861d06d6bSBaptiste Daroussin roffhash_alloc(enum roff_tok mintok, enum roff_tok maxtok)
63961d06d6bSBaptiste Daroussin {
64061d06d6bSBaptiste Daroussin struct ohash *htab;
64161d06d6bSBaptiste Daroussin struct roffreq *req;
64261d06d6bSBaptiste Daroussin enum roff_tok tok;
64361d06d6bSBaptiste Daroussin size_t sz;
64461d06d6bSBaptiste Daroussin unsigned int slot;
64561d06d6bSBaptiste Daroussin
64661d06d6bSBaptiste Daroussin htab = mandoc_malloc(sizeof(*htab));
64761d06d6bSBaptiste Daroussin mandoc_ohash_init(htab, 8, offsetof(struct roffreq, name));
64861d06d6bSBaptiste Daroussin
64961d06d6bSBaptiste Daroussin for (tok = mintok; tok < maxtok; tok++) {
65061d06d6bSBaptiste Daroussin if (roff_name[tok] == NULL)
65161d06d6bSBaptiste Daroussin continue;
65261d06d6bSBaptiste Daroussin sz = strlen(roff_name[tok]);
65361d06d6bSBaptiste Daroussin req = mandoc_malloc(sizeof(*req) + sz + 1);
65461d06d6bSBaptiste Daroussin req->tok = tok;
65561d06d6bSBaptiste Daroussin memcpy(req->name, roff_name[tok], sz + 1);
65661d06d6bSBaptiste Daroussin slot = ohash_qlookup(htab, req->name);
65761d06d6bSBaptiste Daroussin ohash_insert(htab, slot, req);
65861d06d6bSBaptiste Daroussin }
65961d06d6bSBaptiste Daroussin return htab;
66061d06d6bSBaptiste Daroussin }
66161d06d6bSBaptiste Daroussin
66261d06d6bSBaptiste Daroussin void
roffhash_free(struct ohash * htab)66361d06d6bSBaptiste Daroussin roffhash_free(struct ohash *htab)
66461d06d6bSBaptiste Daroussin {
66561d06d6bSBaptiste Daroussin struct roffreq *req;
66661d06d6bSBaptiste Daroussin unsigned int slot;
66761d06d6bSBaptiste Daroussin
66861d06d6bSBaptiste Daroussin if (htab == NULL)
66961d06d6bSBaptiste Daroussin return;
67061d06d6bSBaptiste Daroussin for (req = ohash_first(htab, &slot); req != NULL;
67161d06d6bSBaptiste Daroussin req = ohash_next(htab, &slot))
67261d06d6bSBaptiste Daroussin free(req);
67361d06d6bSBaptiste Daroussin ohash_delete(htab);
67461d06d6bSBaptiste Daroussin free(htab);
67561d06d6bSBaptiste Daroussin }
67661d06d6bSBaptiste Daroussin
67761d06d6bSBaptiste Daroussin enum roff_tok
roffhash_find(struct ohash * htab,const char * name,size_t sz)67861d06d6bSBaptiste Daroussin roffhash_find(struct ohash *htab, const char *name, size_t sz)
67961d06d6bSBaptiste Daroussin {
68061d06d6bSBaptiste Daroussin struct roffreq *req;
68161d06d6bSBaptiste Daroussin const char *end;
68261d06d6bSBaptiste Daroussin
68361d06d6bSBaptiste Daroussin if (sz) {
68461d06d6bSBaptiste Daroussin end = name + sz;
68561d06d6bSBaptiste Daroussin req = ohash_find(htab, ohash_qlookupi(htab, name, &end));
68661d06d6bSBaptiste Daroussin } else
68761d06d6bSBaptiste Daroussin req = ohash_find(htab, ohash_qlookup(htab, name));
68861d06d6bSBaptiste Daroussin return req == NULL ? TOKEN_NONE : req->tok;
68961d06d6bSBaptiste Daroussin }
69061d06d6bSBaptiste Daroussin
69161d06d6bSBaptiste Daroussin /* --- stack of request blocks -------------------------------------------- */
69261d06d6bSBaptiste Daroussin
69361d06d6bSBaptiste Daroussin /*
69461d06d6bSBaptiste Daroussin * Pop the current node off of the stack of roff instructions currently
69545a5aec3SBaptiste Daroussin * pending. Return 1 if it is a loop or 0 otherwise.
69661d06d6bSBaptiste Daroussin */
6977295610fSBaptiste Daroussin static int
roffnode_pop(struct roff * r)69861d06d6bSBaptiste Daroussin roffnode_pop(struct roff *r)
69961d06d6bSBaptiste Daroussin {
70061d06d6bSBaptiste Daroussin struct roffnode *p;
7017295610fSBaptiste Daroussin int inloop;
70261d06d6bSBaptiste Daroussin
70361d06d6bSBaptiste Daroussin p = r->last;
7047295610fSBaptiste Daroussin inloop = p->tok == ROFF_while;
7057295610fSBaptiste Daroussin r->last = p->parent;
70661d06d6bSBaptiste Daroussin free(p->name);
70761d06d6bSBaptiste Daroussin free(p->end);
70861d06d6bSBaptiste Daroussin free(p);
7097295610fSBaptiste Daroussin return inloop;
71061d06d6bSBaptiste Daroussin }
71161d06d6bSBaptiste Daroussin
71261d06d6bSBaptiste Daroussin /*
71361d06d6bSBaptiste Daroussin * Push a roff node onto the instruction stack. This must later be
71461d06d6bSBaptiste Daroussin * removed with roffnode_pop().
71561d06d6bSBaptiste Daroussin */
71661d06d6bSBaptiste Daroussin static void
roffnode_push(struct roff * r,enum roff_tok tok,const char * name,int line,int col)71761d06d6bSBaptiste Daroussin roffnode_push(struct roff *r, enum roff_tok tok, const char *name,
71861d06d6bSBaptiste Daroussin int line, int col)
71961d06d6bSBaptiste Daroussin {
72061d06d6bSBaptiste Daroussin struct roffnode *p;
72161d06d6bSBaptiste Daroussin
72261d06d6bSBaptiste Daroussin p = mandoc_calloc(1, sizeof(struct roffnode));
72361d06d6bSBaptiste Daroussin p->tok = tok;
72461d06d6bSBaptiste Daroussin if (name)
72561d06d6bSBaptiste Daroussin p->name = mandoc_strdup(name);
72661d06d6bSBaptiste Daroussin p->parent = r->last;
72761d06d6bSBaptiste Daroussin p->line = line;
72861d06d6bSBaptiste Daroussin p->col = col;
72961d06d6bSBaptiste Daroussin p->rule = p->parent ? p->parent->rule : 0;
73061d06d6bSBaptiste Daroussin
73161d06d6bSBaptiste Daroussin r->last = p;
73261d06d6bSBaptiste Daroussin }
73361d06d6bSBaptiste Daroussin
73461d06d6bSBaptiste Daroussin /* --- roff parser state data management ---------------------------------- */
73561d06d6bSBaptiste Daroussin
73661d06d6bSBaptiste Daroussin static void
roff_free1(struct roff * r)73761d06d6bSBaptiste Daroussin roff_free1(struct roff *r)
73861d06d6bSBaptiste Daroussin {
73961d06d6bSBaptiste Daroussin int i;
74061d06d6bSBaptiste Daroussin
7417295610fSBaptiste Daroussin tbl_free(r->first_tbl);
74261d06d6bSBaptiste Daroussin r->first_tbl = r->last_tbl = r->tbl = NULL;
74361d06d6bSBaptiste Daroussin
74461d06d6bSBaptiste Daroussin eqn_free(r->last_eqn);
74561d06d6bSBaptiste Daroussin r->last_eqn = r->eqn = NULL;
74661d06d6bSBaptiste Daroussin
7477295610fSBaptiste Daroussin while (r->mstackpos >= 0)
7487295610fSBaptiste Daroussin roff_userret(r);
7497295610fSBaptiste Daroussin
75061d06d6bSBaptiste Daroussin while (r->last)
75161d06d6bSBaptiste Daroussin roffnode_pop(r);
75261d06d6bSBaptiste Daroussin
75361d06d6bSBaptiste Daroussin free (r->rstack);
75461d06d6bSBaptiste Daroussin r->rstack = NULL;
75561d06d6bSBaptiste Daroussin r->rstacksz = 0;
75661d06d6bSBaptiste Daroussin r->rstackpos = -1;
75761d06d6bSBaptiste Daroussin
75861d06d6bSBaptiste Daroussin roff_freereg(r->regtab);
75961d06d6bSBaptiste Daroussin r->regtab = NULL;
76061d06d6bSBaptiste Daroussin
76161d06d6bSBaptiste Daroussin roff_freestr(r->strtab);
76261d06d6bSBaptiste Daroussin roff_freestr(r->rentab);
76361d06d6bSBaptiste Daroussin roff_freestr(r->xmbtab);
76461d06d6bSBaptiste Daroussin r->strtab = r->rentab = r->xmbtab = NULL;
76561d06d6bSBaptiste Daroussin
76661d06d6bSBaptiste Daroussin if (r->xtab)
76761d06d6bSBaptiste Daroussin for (i = 0; i < 128; i++)
76861d06d6bSBaptiste Daroussin free(r->xtab[i].p);
76961d06d6bSBaptiste Daroussin free(r->xtab);
77061d06d6bSBaptiste Daroussin r->xtab = NULL;
77161d06d6bSBaptiste Daroussin }
77261d06d6bSBaptiste Daroussin
77361d06d6bSBaptiste Daroussin void
roff_reset(struct roff * r)77461d06d6bSBaptiste Daroussin roff_reset(struct roff *r)
77561d06d6bSBaptiste Daroussin {
77661d06d6bSBaptiste Daroussin roff_free1(r);
777*6d38604fSBaptiste Daroussin r->options |= MPARSE_COMMENT;
77861d06d6bSBaptiste Daroussin r->format = r->options & (MPARSE_MDOC | MPARSE_MAN);
77961d06d6bSBaptiste Daroussin r->control = '\0';
78061d06d6bSBaptiste Daroussin r->escape = '\\';
78161d06d6bSBaptiste Daroussin roffce_lines = 0;
78261d06d6bSBaptiste Daroussin roffce_node = NULL;
78361d06d6bSBaptiste Daroussin roffit_lines = 0;
78461d06d6bSBaptiste Daroussin roffit_macro = NULL;
78561d06d6bSBaptiste Daroussin }
78661d06d6bSBaptiste Daroussin
78761d06d6bSBaptiste Daroussin void
roff_free(struct roff * r)78861d06d6bSBaptiste Daroussin roff_free(struct roff *r)
78961d06d6bSBaptiste Daroussin {
7907295610fSBaptiste Daroussin int i;
7917295610fSBaptiste Daroussin
79261d06d6bSBaptiste Daroussin roff_free1(r);
7937295610fSBaptiste Daroussin for (i = 0; i < r->mstacksz; i++)
7947295610fSBaptiste Daroussin free(r->mstack[i].argv);
7957295610fSBaptiste Daroussin free(r->mstack);
79661d06d6bSBaptiste Daroussin roffhash_free(r->reqtab);
79761d06d6bSBaptiste Daroussin free(r);
79861d06d6bSBaptiste Daroussin }
79961d06d6bSBaptiste Daroussin
80061d06d6bSBaptiste Daroussin struct roff *
roff_alloc(int options)8017295610fSBaptiste Daroussin roff_alloc(int options)
80261d06d6bSBaptiste Daroussin {
80361d06d6bSBaptiste Daroussin struct roff *r;
80461d06d6bSBaptiste Daroussin
80561d06d6bSBaptiste Daroussin r = mandoc_calloc(1, sizeof(struct roff));
80661d06d6bSBaptiste Daroussin r->reqtab = roffhash_alloc(0, ROFF_RENAMED);
807*6d38604fSBaptiste Daroussin r->options = options | MPARSE_COMMENT;
80861d06d6bSBaptiste Daroussin r->format = options & (MPARSE_MDOC | MPARSE_MAN);
8097295610fSBaptiste Daroussin r->mstackpos = -1;
81061d06d6bSBaptiste Daroussin r->rstackpos = -1;
81161d06d6bSBaptiste Daroussin r->escape = '\\';
81261d06d6bSBaptiste Daroussin return r;
81361d06d6bSBaptiste Daroussin }
81461d06d6bSBaptiste Daroussin
81561d06d6bSBaptiste Daroussin /* --- syntax tree state data management ---------------------------------- */
81661d06d6bSBaptiste Daroussin
81761d06d6bSBaptiste Daroussin static void
roff_man_free1(struct roff_man * man)81861d06d6bSBaptiste Daroussin roff_man_free1(struct roff_man *man)
81961d06d6bSBaptiste Daroussin {
8207295610fSBaptiste Daroussin if (man->meta.first != NULL)
8217295610fSBaptiste Daroussin roff_node_delete(man, man->meta.first);
82261d06d6bSBaptiste Daroussin free(man->meta.msec);
82361d06d6bSBaptiste Daroussin free(man->meta.vol);
82461d06d6bSBaptiste Daroussin free(man->meta.os);
82561d06d6bSBaptiste Daroussin free(man->meta.arch);
82661d06d6bSBaptiste Daroussin free(man->meta.title);
82761d06d6bSBaptiste Daroussin free(man->meta.name);
82861d06d6bSBaptiste Daroussin free(man->meta.date);
8297295610fSBaptiste Daroussin free(man->meta.sodest);
8307295610fSBaptiste Daroussin }
8317295610fSBaptiste Daroussin
8327295610fSBaptiste Daroussin void
roff_state_reset(struct roff_man * man)8337295610fSBaptiste Daroussin roff_state_reset(struct roff_man *man)
8347295610fSBaptiste Daroussin {
8357295610fSBaptiste Daroussin man->last = man->meta.first;
8367295610fSBaptiste Daroussin man->last_es = NULL;
8377295610fSBaptiste Daroussin man->flags = 0;
8387295610fSBaptiste Daroussin man->lastsec = man->lastnamed = SEC_NONE;
8397295610fSBaptiste Daroussin man->next = ROFF_NEXT_CHILD;
8407295610fSBaptiste Daroussin roff_setreg(man->roff, "nS", 0, '=');
84161d06d6bSBaptiste Daroussin }
84261d06d6bSBaptiste Daroussin
84361d06d6bSBaptiste Daroussin static void
roff_man_alloc1(struct roff_man * man)84461d06d6bSBaptiste Daroussin roff_man_alloc1(struct roff_man *man)
84561d06d6bSBaptiste Daroussin {
84661d06d6bSBaptiste Daroussin memset(&man->meta, 0, sizeof(man->meta));
8477295610fSBaptiste Daroussin man->meta.first = mandoc_calloc(1, sizeof(*man->meta.first));
8487295610fSBaptiste Daroussin man->meta.first->type = ROFFT_ROOT;
8497295610fSBaptiste Daroussin man->meta.macroset = MACROSET_NONE;
8507295610fSBaptiste Daroussin roff_state_reset(man);
85161d06d6bSBaptiste Daroussin }
85261d06d6bSBaptiste Daroussin
85361d06d6bSBaptiste Daroussin void
roff_man_reset(struct roff_man * man)85461d06d6bSBaptiste Daroussin roff_man_reset(struct roff_man *man)
85561d06d6bSBaptiste Daroussin {
85661d06d6bSBaptiste Daroussin roff_man_free1(man);
85761d06d6bSBaptiste Daroussin roff_man_alloc1(man);
85861d06d6bSBaptiste Daroussin }
85961d06d6bSBaptiste Daroussin
86061d06d6bSBaptiste Daroussin void
roff_man_free(struct roff_man * man)86161d06d6bSBaptiste Daroussin roff_man_free(struct roff_man *man)
86261d06d6bSBaptiste Daroussin {
86361d06d6bSBaptiste Daroussin roff_man_free1(man);
86461d06d6bSBaptiste Daroussin free(man);
86561d06d6bSBaptiste Daroussin }
86661d06d6bSBaptiste Daroussin
86761d06d6bSBaptiste Daroussin struct roff_man *
roff_man_alloc(struct roff * roff,const char * os_s,int quick)8687295610fSBaptiste Daroussin roff_man_alloc(struct roff *roff, const char *os_s, int quick)
86961d06d6bSBaptiste Daroussin {
87061d06d6bSBaptiste Daroussin struct roff_man *man;
87161d06d6bSBaptiste Daroussin
87261d06d6bSBaptiste Daroussin man = mandoc_calloc(1, sizeof(*man));
87361d06d6bSBaptiste Daroussin man->roff = roff;
87461d06d6bSBaptiste Daroussin man->os_s = os_s;
87561d06d6bSBaptiste Daroussin man->quick = quick;
87661d06d6bSBaptiste Daroussin roff_man_alloc1(man);
87761d06d6bSBaptiste Daroussin roff->man = man;
87861d06d6bSBaptiste Daroussin return man;
87961d06d6bSBaptiste Daroussin }
88061d06d6bSBaptiste Daroussin
88161d06d6bSBaptiste Daroussin /* --- syntax tree handling ----------------------------------------------- */
88261d06d6bSBaptiste Daroussin
88361d06d6bSBaptiste Daroussin struct roff_node *
roff_node_alloc(struct roff_man * man,int line,int pos,enum roff_type type,int tok)88461d06d6bSBaptiste Daroussin roff_node_alloc(struct roff_man *man, int line, int pos,
88561d06d6bSBaptiste Daroussin enum roff_type type, int tok)
88661d06d6bSBaptiste Daroussin {
88761d06d6bSBaptiste Daroussin struct roff_node *n;
88861d06d6bSBaptiste Daroussin
88961d06d6bSBaptiste Daroussin n = mandoc_calloc(1, sizeof(*n));
89061d06d6bSBaptiste Daroussin n->line = line;
89161d06d6bSBaptiste Daroussin n->pos = pos;
89261d06d6bSBaptiste Daroussin n->tok = tok;
89361d06d6bSBaptiste Daroussin n->type = type;
89461d06d6bSBaptiste Daroussin n->sec = man->lastsec;
89561d06d6bSBaptiste Daroussin
89661d06d6bSBaptiste Daroussin if (man->flags & MDOC_SYNOPSIS)
89761d06d6bSBaptiste Daroussin n->flags |= NODE_SYNPRETTY;
89861d06d6bSBaptiste Daroussin else
89961d06d6bSBaptiste Daroussin n->flags &= ~NODE_SYNPRETTY;
9007295610fSBaptiste Daroussin if ((man->flags & (ROFF_NOFILL | ROFF_NONOFILL)) == ROFF_NOFILL)
9017295610fSBaptiste Daroussin n->flags |= NODE_NOFILL;
9027295610fSBaptiste Daroussin else
9037295610fSBaptiste Daroussin n->flags &= ~NODE_NOFILL;
90461d06d6bSBaptiste Daroussin if (man->flags & MDOC_NEWLINE)
90561d06d6bSBaptiste Daroussin n->flags |= NODE_LINE;
90661d06d6bSBaptiste Daroussin man->flags &= ~MDOC_NEWLINE;
90761d06d6bSBaptiste Daroussin
90861d06d6bSBaptiste Daroussin return n;
90961d06d6bSBaptiste Daroussin }
91061d06d6bSBaptiste Daroussin
91161d06d6bSBaptiste Daroussin void
roff_node_append(struct roff_man * man,struct roff_node * n)91261d06d6bSBaptiste Daroussin roff_node_append(struct roff_man *man, struct roff_node *n)
91361d06d6bSBaptiste Daroussin {
91461d06d6bSBaptiste Daroussin
91561d06d6bSBaptiste Daroussin switch (man->next) {
91661d06d6bSBaptiste Daroussin case ROFF_NEXT_SIBLING:
91761d06d6bSBaptiste Daroussin if (man->last->next != NULL) {
91861d06d6bSBaptiste Daroussin n->next = man->last->next;
91961d06d6bSBaptiste Daroussin man->last->next->prev = n;
92061d06d6bSBaptiste Daroussin } else
92161d06d6bSBaptiste Daroussin man->last->parent->last = n;
92261d06d6bSBaptiste Daroussin man->last->next = n;
92361d06d6bSBaptiste Daroussin n->prev = man->last;
92461d06d6bSBaptiste Daroussin n->parent = man->last->parent;
92561d06d6bSBaptiste Daroussin break;
92661d06d6bSBaptiste Daroussin case ROFF_NEXT_CHILD:
92761d06d6bSBaptiste Daroussin if (man->last->child != NULL) {
92861d06d6bSBaptiste Daroussin n->next = man->last->child;
92961d06d6bSBaptiste Daroussin man->last->child->prev = n;
93061d06d6bSBaptiste Daroussin } else
93161d06d6bSBaptiste Daroussin man->last->last = n;
93261d06d6bSBaptiste Daroussin man->last->child = n;
93361d06d6bSBaptiste Daroussin n->parent = man->last;
93461d06d6bSBaptiste Daroussin break;
93561d06d6bSBaptiste Daroussin default:
93661d06d6bSBaptiste Daroussin abort();
93761d06d6bSBaptiste Daroussin }
93861d06d6bSBaptiste Daroussin man->last = n;
93961d06d6bSBaptiste Daroussin
94061d06d6bSBaptiste Daroussin switch (n->type) {
94161d06d6bSBaptiste Daroussin case ROFFT_HEAD:
94261d06d6bSBaptiste Daroussin n->parent->head = n;
94361d06d6bSBaptiste Daroussin break;
94461d06d6bSBaptiste Daroussin case ROFFT_BODY:
94561d06d6bSBaptiste Daroussin if (n->end != ENDBODY_NOT)
94661d06d6bSBaptiste Daroussin return;
94761d06d6bSBaptiste Daroussin n->parent->body = n;
94861d06d6bSBaptiste Daroussin break;
94961d06d6bSBaptiste Daroussin case ROFFT_TAIL:
95061d06d6bSBaptiste Daroussin n->parent->tail = n;
95161d06d6bSBaptiste Daroussin break;
95261d06d6bSBaptiste Daroussin default:
95361d06d6bSBaptiste Daroussin return;
95461d06d6bSBaptiste Daroussin }
95561d06d6bSBaptiste Daroussin
95661d06d6bSBaptiste Daroussin /*
95761d06d6bSBaptiste Daroussin * Copy over the normalised-data pointer of our parent. Not
95861d06d6bSBaptiste Daroussin * everybody has one, but copying a null pointer is fine.
95961d06d6bSBaptiste Daroussin */
96061d06d6bSBaptiste Daroussin
96161d06d6bSBaptiste Daroussin n->norm = n->parent->norm;
96261d06d6bSBaptiste Daroussin assert(n->parent->type == ROFFT_BLOCK);
96361d06d6bSBaptiste Daroussin }
96461d06d6bSBaptiste Daroussin
96561d06d6bSBaptiste Daroussin void
roff_word_alloc(struct roff_man * man,int line,int pos,const char * word)96661d06d6bSBaptiste Daroussin roff_word_alloc(struct roff_man *man, int line, int pos, const char *word)
96761d06d6bSBaptiste Daroussin {
96861d06d6bSBaptiste Daroussin struct roff_node *n;
96961d06d6bSBaptiste Daroussin
97061d06d6bSBaptiste Daroussin n = roff_node_alloc(man, line, pos, ROFFT_TEXT, TOKEN_NONE);
97161d06d6bSBaptiste Daroussin n->string = roff_strdup(man->roff, word);
97261d06d6bSBaptiste Daroussin roff_node_append(man, n);
97361d06d6bSBaptiste Daroussin n->flags |= NODE_VALID | NODE_ENDED;
97461d06d6bSBaptiste Daroussin man->next = ROFF_NEXT_SIBLING;
97561d06d6bSBaptiste Daroussin }
97661d06d6bSBaptiste Daroussin
97761d06d6bSBaptiste Daroussin void
roff_word_append(struct roff_man * man,const char * word)97861d06d6bSBaptiste Daroussin roff_word_append(struct roff_man *man, const char *word)
97961d06d6bSBaptiste Daroussin {
98061d06d6bSBaptiste Daroussin struct roff_node *n;
98161d06d6bSBaptiste Daroussin char *addstr, *newstr;
98261d06d6bSBaptiste Daroussin
98361d06d6bSBaptiste Daroussin n = man->last;
98461d06d6bSBaptiste Daroussin addstr = roff_strdup(man->roff, word);
98561d06d6bSBaptiste Daroussin mandoc_asprintf(&newstr, "%s %s", n->string, addstr);
98661d06d6bSBaptiste Daroussin free(addstr);
98761d06d6bSBaptiste Daroussin free(n->string);
98861d06d6bSBaptiste Daroussin n->string = newstr;
98961d06d6bSBaptiste Daroussin man->next = ROFF_NEXT_SIBLING;
99061d06d6bSBaptiste Daroussin }
99161d06d6bSBaptiste Daroussin
99261d06d6bSBaptiste Daroussin void
roff_elem_alloc(struct roff_man * man,int line,int pos,int tok)99361d06d6bSBaptiste Daroussin roff_elem_alloc(struct roff_man *man, int line, int pos, int tok)
99461d06d6bSBaptiste Daroussin {
99561d06d6bSBaptiste Daroussin struct roff_node *n;
99661d06d6bSBaptiste Daroussin
99761d06d6bSBaptiste Daroussin n = roff_node_alloc(man, line, pos, ROFFT_ELEM, tok);
99861d06d6bSBaptiste Daroussin roff_node_append(man, n);
99961d06d6bSBaptiste Daroussin man->next = ROFF_NEXT_CHILD;
100061d06d6bSBaptiste Daroussin }
100161d06d6bSBaptiste Daroussin
100261d06d6bSBaptiste Daroussin struct roff_node *
roff_block_alloc(struct roff_man * man,int line,int pos,int tok)100361d06d6bSBaptiste Daroussin roff_block_alloc(struct roff_man *man, int line, int pos, int tok)
100461d06d6bSBaptiste Daroussin {
100561d06d6bSBaptiste Daroussin struct roff_node *n;
100661d06d6bSBaptiste Daroussin
100761d06d6bSBaptiste Daroussin n = roff_node_alloc(man, line, pos, ROFFT_BLOCK, tok);
100861d06d6bSBaptiste Daroussin roff_node_append(man, n);
100961d06d6bSBaptiste Daroussin man->next = ROFF_NEXT_CHILD;
101061d06d6bSBaptiste Daroussin return n;
101161d06d6bSBaptiste Daroussin }
101261d06d6bSBaptiste Daroussin
101361d06d6bSBaptiste Daroussin struct roff_node *
roff_head_alloc(struct roff_man * man,int line,int pos,int tok)101461d06d6bSBaptiste Daroussin roff_head_alloc(struct roff_man *man, int line, int pos, int tok)
101561d06d6bSBaptiste Daroussin {
101661d06d6bSBaptiste Daroussin struct roff_node *n;
101761d06d6bSBaptiste Daroussin
101861d06d6bSBaptiste Daroussin n = roff_node_alloc(man, line, pos, ROFFT_HEAD, tok);
101961d06d6bSBaptiste Daroussin roff_node_append(man, n);
102061d06d6bSBaptiste Daroussin man->next = ROFF_NEXT_CHILD;
102161d06d6bSBaptiste Daroussin return n;
102261d06d6bSBaptiste Daroussin }
102361d06d6bSBaptiste Daroussin
102461d06d6bSBaptiste Daroussin struct roff_node *
roff_body_alloc(struct roff_man * man,int line,int pos,int tok)102561d06d6bSBaptiste Daroussin roff_body_alloc(struct roff_man *man, int line, int pos, int tok)
102661d06d6bSBaptiste Daroussin {
102761d06d6bSBaptiste Daroussin struct roff_node *n;
102861d06d6bSBaptiste Daroussin
102961d06d6bSBaptiste Daroussin n = roff_node_alloc(man, line, pos, ROFFT_BODY, tok);
103061d06d6bSBaptiste Daroussin roff_node_append(man, n);
103161d06d6bSBaptiste Daroussin man->next = ROFF_NEXT_CHILD;
103261d06d6bSBaptiste Daroussin return n;
103361d06d6bSBaptiste Daroussin }
103461d06d6bSBaptiste Daroussin
103561d06d6bSBaptiste Daroussin static void
roff_addtbl(struct roff_man * man,int line,struct tbl_node * tbl)10367295610fSBaptiste Daroussin roff_addtbl(struct roff_man *man, int line, struct tbl_node *tbl)
103761d06d6bSBaptiste Daroussin {
103861d06d6bSBaptiste Daroussin struct roff_node *n;
10397295610fSBaptiste Daroussin struct tbl_span *span;
104061d06d6bSBaptiste Daroussin
10417295610fSBaptiste Daroussin if (man->meta.macroset == MACROSET_MAN)
104261d06d6bSBaptiste Daroussin man_breakscope(man, ROFF_TS);
104361d06d6bSBaptiste Daroussin while ((span = tbl_span(tbl)) != NULL) {
10447295610fSBaptiste Daroussin n = roff_node_alloc(man, line, 0, ROFFT_TBL, TOKEN_NONE);
104561d06d6bSBaptiste Daroussin n->span = span;
104661d06d6bSBaptiste Daroussin roff_node_append(man, n);
104761d06d6bSBaptiste Daroussin n->flags |= NODE_VALID | NODE_ENDED;
104861d06d6bSBaptiste Daroussin man->next = ROFF_NEXT_SIBLING;
104961d06d6bSBaptiste Daroussin }
105061d06d6bSBaptiste Daroussin }
105161d06d6bSBaptiste Daroussin
105261d06d6bSBaptiste Daroussin void
roff_node_unlink(struct roff_man * man,struct roff_node * n)105361d06d6bSBaptiste Daroussin roff_node_unlink(struct roff_man *man, struct roff_node *n)
105461d06d6bSBaptiste Daroussin {
105561d06d6bSBaptiste Daroussin
105661d06d6bSBaptiste Daroussin /* Adjust siblings. */
105761d06d6bSBaptiste Daroussin
105861d06d6bSBaptiste Daroussin if (n->prev)
105961d06d6bSBaptiste Daroussin n->prev->next = n->next;
106061d06d6bSBaptiste Daroussin if (n->next)
106161d06d6bSBaptiste Daroussin n->next->prev = n->prev;
106261d06d6bSBaptiste Daroussin
106361d06d6bSBaptiste Daroussin /* Adjust parent. */
106461d06d6bSBaptiste Daroussin
106561d06d6bSBaptiste Daroussin if (n->parent != NULL) {
106661d06d6bSBaptiste Daroussin if (n->parent->child == n)
106761d06d6bSBaptiste Daroussin n->parent->child = n->next;
106861d06d6bSBaptiste Daroussin if (n->parent->last == n)
106961d06d6bSBaptiste Daroussin n->parent->last = n->prev;
107061d06d6bSBaptiste Daroussin }
107161d06d6bSBaptiste Daroussin
107261d06d6bSBaptiste Daroussin /* Adjust parse point. */
107361d06d6bSBaptiste Daroussin
107461d06d6bSBaptiste Daroussin if (man == NULL)
107561d06d6bSBaptiste Daroussin return;
107661d06d6bSBaptiste Daroussin if (man->last == n) {
107761d06d6bSBaptiste Daroussin if (n->prev == NULL) {
107861d06d6bSBaptiste Daroussin man->last = n->parent;
107961d06d6bSBaptiste Daroussin man->next = ROFF_NEXT_CHILD;
108061d06d6bSBaptiste Daroussin } else {
108161d06d6bSBaptiste Daroussin man->last = n->prev;
108261d06d6bSBaptiste Daroussin man->next = ROFF_NEXT_SIBLING;
108361d06d6bSBaptiste Daroussin }
108461d06d6bSBaptiste Daroussin }
10857295610fSBaptiste Daroussin if (man->meta.first == n)
10867295610fSBaptiste Daroussin man->meta.first = NULL;
10877295610fSBaptiste Daroussin }
10887295610fSBaptiste Daroussin
10897295610fSBaptiste Daroussin void
roff_node_relink(struct roff_man * man,struct roff_node * n)10907295610fSBaptiste Daroussin roff_node_relink(struct roff_man *man, struct roff_node *n)
10917295610fSBaptiste Daroussin {
10927295610fSBaptiste Daroussin roff_node_unlink(man, n);
10937295610fSBaptiste Daroussin n->prev = n->next = NULL;
10947295610fSBaptiste Daroussin roff_node_append(man, n);
109561d06d6bSBaptiste Daroussin }
109661d06d6bSBaptiste Daroussin
109761d06d6bSBaptiste Daroussin void
roff_node_free(struct roff_node * n)109861d06d6bSBaptiste Daroussin roff_node_free(struct roff_node *n)
109961d06d6bSBaptiste Daroussin {
110061d06d6bSBaptiste Daroussin
110161d06d6bSBaptiste Daroussin if (n->args != NULL)
110261d06d6bSBaptiste Daroussin mdoc_argv_free(n->args);
110361d06d6bSBaptiste Daroussin if (n->type == ROFFT_BLOCK || n->type == ROFFT_ELEM)
110461d06d6bSBaptiste Daroussin free(n->norm);
110561d06d6bSBaptiste Daroussin eqn_box_free(n->eqn);
110661d06d6bSBaptiste Daroussin free(n->string);
1107*6d38604fSBaptiste Daroussin free(n->tag);
110861d06d6bSBaptiste Daroussin free(n);
110961d06d6bSBaptiste Daroussin }
111061d06d6bSBaptiste Daroussin
111161d06d6bSBaptiste Daroussin void
roff_node_delete(struct roff_man * man,struct roff_node * n)111261d06d6bSBaptiste Daroussin roff_node_delete(struct roff_man *man, struct roff_node *n)
111361d06d6bSBaptiste Daroussin {
111461d06d6bSBaptiste Daroussin
111561d06d6bSBaptiste Daroussin while (n->child != NULL)
111661d06d6bSBaptiste Daroussin roff_node_delete(man, n->child);
111761d06d6bSBaptiste Daroussin roff_node_unlink(man, n);
111861d06d6bSBaptiste Daroussin roff_node_free(n);
111961d06d6bSBaptiste Daroussin }
112061d06d6bSBaptiste Daroussin
1121*6d38604fSBaptiste Daroussin int
roff_node_transparent(struct roff_node * n)1122*6d38604fSBaptiste Daroussin roff_node_transparent(struct roff_node *n)
1123*6d38604fSBaptiste Daroussin {
1124*6d38604fSBaptiste Daroussin if (n == NULL)
1125*6d38604fSBaptiste Daroussin return 0;
1126*6d38604fSBaptiste Daroussin if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
1127*6d38604fSBaptiste Daroussin return 1;
1128*6d38604fSBaptiste Daroussin return roff_tok_transparent(n->tok);
1129*6d38604fSBaptiste Daroussin }
1130*6d38604fSBaptiste Daroussin
1131*6d38604fSBaptiste Daroussin int
roff_tok_transparent(enum roff_tok tok)1132*6d38604fSBaptiste Daroussin roff_tok_transparent(enum roff_tok tok)
1133*6d38604fSBaptiste Daroussin {
1134*6d38604fSBaptiste Daroussin switch (tok) {
1135*6d38604fSBaptiste Daroussin case ROFF_ft:
1136*6d38604fSBaptiste Daroussin case ROFF_ll:
1137*6d38604fSBaptiste Daroussin case ROFF_mc:
1138*6d38604fSBaptiste Daroussin case ROFF_po:
1139*6d38604fSBaptiste Daroussin case ROFF_ta:
1140*6d38604fSBaptiste Daroussin case MDOC_Db:
1141*6d38604fSBaptiste Daroussin case MDOC_Es:
1142*6d38604fSBaptiste Daroussin case MDOC_Sm:
1143*6d38604fSBaptiste Daroussin case MDOC_Tg:
1144*6d38604fSBaptiste Daroussin case MAN_DT:
1145*6d38604fSBaptiste Daroussin case MAN_UC:
1146*6d38604fSBaptiste Daroussin case MAN_PD:
1147*6d38604fSBaptiste Daroussin case MAN_AT:
1148*6d38604fSBaptiste Daroussin return 1;
1149*6d38604fSBaptiste Daroussin default:
1150*6d38604fSBaptiste Daroussin return 0;
1151*6d38604fSBaptiste Daroussin }
1152*6d38604fSBaptiste Daroussin }
1153*6d38604fSBaptiste Daroussin
1154*6d38604fSBaptiste Daroussin struct roff_node *
roff_node_child(struct roff_node * n)1155*6d38604fSBaptiste Daroussin roff_node_child(struct roff_node *n)
1156*6d38604fSBaptiste Daroussin {
1157*6d38604fSBaptiste Daroussin for (n = n->child; roff_node_transparent(n); n = n->next)
1158*6d38604fSBaptiste Daroussin continue;
1159*6d38604fSBaptiste Daroussin return n;
1160*6d38604fSBaptiste Daroussin }
1161*6d38604fSBaptiste Daroussin
1162*6d38604fSBaptiste Daroussin struct roff_node *
roff_node_prev(struct roff_node * n)1163*6d38604fSBaptiste Daroussin roff_node_prev(struct roff_node *n)
1164*6d38604fSBaptiste Daroussin {
1165*6d38604fSBaptiste Daroussin do {
1166*6d38604fSBaptiste Daroussin n = n->prev;
1167*6d38604fSBaptiste Daroussin } while (roff_node_transparent(n));
1168*6d38604fSBaptiste Daroussin return n;
1169*6d38604fSBaptiste Daroussin }
1170*6d38604fSBaptiste Daroussin
1171*6d38604fSBaptiste Daroussin struct roff_node *
roff_node_next(struct roff_node * n)1172*6d38604fSBaptiste Daroussin roff_node_next(struct roff_node *n)
1173*6d38604fSBaptiste Daroussin {
1174*6d38604fSBaptiste Daroussin do {
1175*6d38604fSBaptiste Daroussin n = n->next;
1176*6d38604fSBaptiste Daroussin } while (roff_node_transparent(n));
1177*6d38604fSBaptiste Daroussin return n;
1178*6d38604fSBaptiste Daroussin }
1179*6d38604fSBaptiste Daroussin
118061d06d6bSBaptiste Daroussin void
deroff(char ** dest,const struct roff_node * n)118161d06d6bSBaptiste Daroussin deroff(char **dest, const struct roff_node *n)
118261d06d6bSBaptiste Daroussin {
118361d06d6bSBaptiste Daroussin char *cp;
118461d06d6bSBaptiste Daroussin size_t sz;
118561d06d6bSBaptiste Daroussin
1186*6d38604fSBaptiste Daroussin if (n->string == NULL) {
118761d06d6bSBaptiste Daroussin for (n = n->child; n != NULL; n = n->next)
118861d06d6bSBaptiste Daroussin deroff(dest, n);
118961d06d6bSBaptiste Daroussin return;
119061d06d6bSBaptiste Daroussin }
119161d06d6bSBaptiste Daroussin
119261d06d6bSBaptiste Daroussin /* Skip leading whitespace. */
119361d06d6bSBaptiste Daroussin
119461d06d6bSBaptiste Daroussin for (cp = n->string; *cp != '\0'; cp++) {
119561d06d6bSBaptiste Daroussin if (cp[0] == '\\' && cp[1] != '\0' &&
119661d06d6bSBaptiste Daroussin strchr(" %&0^|~", cp[1]) != NULL)
119761d06d6bSBaptiste Daroussin cp++;
119861d06d6bSBaptiste Daroussin else if ( ! isspace((unsigned char)*cp))
119961d06d6bSBaptiste Daroussin break;
120061d06d6bSBaptiste Daroussin }
120161d06d6bSBaptiste Daroussin
120261d06d6bSBaptiste Daroussin /* Skip trailing backslash. */
120361d06d6bSBaptiste Daroussin
120461d06d6bSBaptiste Daroussin sz = strlen(cp);
120561d06d6bSBaptiste Daroussin if (sz > 0 && cp[sz - 1] == '\\')
120661d06d6bSBaptiste Daroussin sz--;
120761d06d6bSBaptiste Daroussin
120861d06d6bSBaptiste Daroussin /* Skip trailing whitespace. */
120961d06d6bSBaptiste Daroussin
121061d06d6bSBaptiste Daroussin for (; sz; sz--)
121161d06d6bSBaptiste Daroussin if ( ! isspace((unsigned char)cp[sz-1]))
121261d06d6bSBaptiste Daroussin break;
121361d06d6bSBaptiste Daroussin
121461d06d6bSBaptiste Daroussin /* Skip empty strings. */
121561d06d6bSBaptiste Daroussin
121661d06d6bSBaptiste Daroussin if (sz == 0)
121761d06d6bSBaptiste Daroussin return;
121861d06d6bSBaptiste Daroussin
121961d06d6bSBaptiste Daroussin if (*dest == NULL) {
122061d06d6bSBaptiste Daroussin *dest = mandoc_strndup(cp, sz);
122161d06d6bSBaptiste Daroussin return;
122261d06d6bSBaptiste Daroussin }
122361d06d6bSBaptiste Daroussin
122461d06d6bSBaptiste Daroussin mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp);
122561d06d6bSBaptiste Daroussin free(*dest);
122661d06d6bSBaptiste Daroussin *dest = cp;
122761d06d6bSBaptiste Daroussin }
122861d06d6bSBaptiste Daroussin
122961d06d6bSBaptiste Daroussin /* --- main functions of the roff parser ---------------------------------- */
123061d06d6bSBaptiste Daroussin
123161d06d6bSBaptiste Daroussin /*
12327295610fSBaptiste Daroussin * In the current line, expand escape sequences that produce parsable
12337295610fSBaptiste Daroussin * input text. Also check the syntax of the remaining escape sequences,
12347295610fSBaptiste Daroussin * which typically produce output glyphs or change formatter state.
123561d06d6bSBaptiste Daroussin */
12367295610fSBaptiste Daroussin static int
roff_expand(struct roff * r,struct buf * buf,int ln,int pos,char newesc)12377295610fSBaptiste Daroussin roff_expand(struct roff *r, struct buf *buf, int ln, int pos, char newesc)
123861d06d6bSBaptiste Daroussin {
12397295610fSBaptiste Daroussin struct mctx *ctx; /* current macro call context */
124061d06d6bSBaptiste Daroussin char ubuf[24]; /* buffer to print the number */
124161d06d6bSBaptiste Daroussin struct roff_node *n; /* used for header comments */
124261d06d6bSBaptiste Daroussin const char *start; /* start of the string to process */
124361d06d6bSBaptiste Daroussin char *stesc; /* start of an escape sequence ('\\') */
12447295610fSBaptiste Daroussin const char *esct; /* type of esccape sequence */
124561d06d6bSBaptiste Daroussin char *ep; /* end of comment string */
124661d06d6bSBaptiste Daroussin const char *stnam; /* start of the name, after "[(*" */
124761d06d6bSBaptiste Daroussin const char *cp; /* end of the name, e.g. before ']' */
124861d06d6bSBaptiste Daroussin const char *res; /* the string to be substituted */
124961d06d6bSBaptiste Daroussin char *nbuf; /* new buffer to copy buf->buf to */
125061d06d6bSBaptiste Daroussin size_t maxl; /* expected length of the escape name */
125161d06d6bSBaptiste Daroussin size_t naml; /* actual length of the escape name */
12527295610fSBaptiste Daroussin size_t asz; /* length of the replacement */
12537295610fSBaptiste Daroussin size_t rsz; /* length of the rest of the string */
125461d06d6bSBaptiste Daroussin int inaml; /* length returned from mandoc_escape() */
125561d06d6bSBaptiste Daroussin int expand_count; /* to avoid infinite loops */
125661d06d6bSBaptiste Daroussin int npos; /* position in numeric expression */
125761d06d6bSBaptiste Daroussin int arg_complete; /* argument not interrupted by eol */
12587295610fSBaptiste Daroussin int quote_args; /* true for \\$@, false for \\$* */
125961d06d6bSBaptiste Daroussin int done; /* no more input available */
126061d06d6bSBaptiste Daroussin int deftype; /* type of definition to paste */
126161d06d6bSBaptiste Daroussin int rcsid; /* kind of RCS id seen */
12627295610fSBaptiste Daroussin enum mandocerr err; /* for escape sequence problems */
126361d06d6bSBaptiste Daroussin char sign; /* increment number register */
126461d06d6bSBaptiste Daroussin char term; /* character terminating the escape */
126561d06d6bSBaptiste Daroussin
126661d06d6bSBaptiste Daroussin /* Search forward for comments. */
126761d06d6bSBaptiste Daroussin
126861d06d6bSBaptiste Daroussin done = 0;
126961d06d6bSBaptiste Daroussin start = buf->buf + pos;
127061d06d6bSBaptiste Daroussin for (stesc = buf->buf + pos; *stesc != '\0'; stesc++) {
12717295610fSBaptiste Daroussin if (stesc[0] != newesc || stesc[1] == '\0')
127261d06d6bSBaptiste Daroussin continue;
127361d06d6bSBaptiste Daroussin stesc++;
127461d06d6bSBaptiste Daroussin if (*stesc != '"' && *stesc != '#')
127561d06d6bSBaptiste Daroussin continue;
127661d06d6bSBaptiste Daroussin
127761d06d6bSBaptiste Daroussin /* Comment found, look for RCS id. */
127861d06d6bSBaptiste Daroussin
127961d06d6bSBaptiste Daroussin rcsid = 0;
128061d06d6bSBaptiste Daroussin if ((cp = strstr(stesc, "$" "OpenBSD")) != NULL) {
128161d06d6bSBaptiste Daroussin rcsid = 1 << MANDOC_OS_OPENBSD;
128261d06d6bSBaptiste Daroussin cp += 8;
128361d06d6bSBaptiste Daroussin } else if ((cp = strstr(stesc, "$" "NetBSD")) != NULL) {
128461d06d6bSBaptiste Daroussin rcsid = 1 << MANDOC_OS_NETBSD;
128561d06d6bSBaptiste Daroussin cp += 7;
128661d06d6bSBaptiste Daroussin }
128761d06d6bSBaptiste Daroussin if (cp != NULL &&
128861d06d6bSBaptiste Daroussin isalnum((unsigned char)*cp) == 0 &&
128961d06d6bSBaptiste Daroussin strchr(cp, '$') != NULL) {
129061d06d6bSBaptiste Daroussin if (r->man->meta.rcsids & rcsid)
12917295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_RCS_REP, ln,
12927295610fSBaptiste Daroussin (int)(stesc - buf->buf) + 1,
12937295610fSBaptiste Daroussin "%s", stesc + 1);
129461d06d6bSBaptiste Daroussin r->man->meta.rcsids |= rcsid;
129561d06d6bSBaptiste Daroussin }
129661d06d6bSBaptiste Daroussin
129761d06d6bSBaptiste Daroussin /* Handle trailing whitespace. */
129861d06d6bSBaptiste Daroussin
129961d06d6bSBaptiste Daroussin ep = strchr(stesc--, '\0') - 1;
130061d06d6bSBaptiste Daroussin if (*ep == '\n') {
130161d06d6bSBaptiste Daroussin done = 1;
130261d06d6bSBaptiste Daroussin ep--;
130361d06d6bSBaptiste Daroussin }
130461d06d6bSBaptiste Daroussin if (*ep == ' ' || *ep == '\t')
13057295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_SPACE_EOL,
13067295610fSBaptiste Daroussin ln, (int)(ep - buf->buf), NULL);
130761d06d6bSBaptiste Daroussin
130861d06d6bSBaptiste Daroussin /*
130961d06d6bSBaptiste Daroussin * Save comments preceding the title macro
131061d06d6bSBaptiste Daroussin * in the syntax tree.
131161d06d6bSBaptiste Daroussin */
131261d06d6bSBaptiste Daroussin
1313*6d38604fSBaptiste Daroussin if (newesc != ASCII_ESC && r->options & MPARSE_COMMENT) {
131461d06d6bSBaptiste Daroussin while (*ep == ' ' || *ep == '\t')
131561d06d6bSBaptiste Daroussin ep--;
131661d06d6bSBaptiste Daroussin ep[1] = '\0';
131761d06d6bSBaptiste Daroussin n = roff_node_alloc(r->man,
131861d06d6bSBaptiste Daroussin ln, stesc + 1 - buf->buf,
131961d06d6bSBaptiste Daroussin ROFFT_COMMENT, TOKEN_NONE);
132061d06d6bSBaptiste Daroussin n->string = mandoc_strdup(stesc + 2);
132161d06d6bSBaptiste Daroussin roff_node_append(r->man, n);
132261d06d6bSBaptiste Daroussin n->flags |= NODE_VALID | NODE_ENDED;
132361d06d6bSBaptiste Daroussin r->man->next = ROFF_NEXT_SIBLING;
132461d06d6bSBaptiste Daroussin }
132561d06d6bSBaptiste Daroussin
13267295610fSBaptiste Daroussin /* Line continuation with comment. */
132761d06d6bSBaptiste Daroussin
13287295610fSBaptiste Daroussin if (stesc[1] == '#') {
13297295610fSBaptiste Daroussin *stesc = '\0';
13307295610fSBaptiste Daroussin return ROFF_IGN | ROFF_APPEND;
13317295610fSBaptiste Daroussin }
13327295610fSBaptiste Daroussin
13337295610fSBaptiste Daroussin /* Discard normal comments. */
13347295610fSBaptiste Daroussin
13357295610fSBaptiste Daroussin while (stesc > start && stesc[-1] == ' ' &&
13367295610fSBaptiste Daroussin (stesc == start + 1 || stesc[-2] != '\\'))
133761d06d6bSBaptiste Daroussin stesc--;
133861d06d6bSBaptiste Daroussin *stesc = '\0';
133961d06d6bSBaptiste Daroussin break;
134061d06d6bSBaptiste Daroussin }
134161d06d6bSBaptiste Daroussin if (stesc == start)
134261d06d6bSBaptiste Daroussin return ROFF_CONT;
134361d06d6bSBaptiste Daroussin stesc--;
134461d06d6bSBaptiste Daroussin
134561d06d6bSBaptiste Daroussin /* Notice the end of the input. */
134661d06d6bSBaptiste Daroussin
134761d06d6bSBaptiste Daroussin if (*stesc == '\n') {
134861d06d6bSBaptiste Daroussin *stesc-- = '\0';
134961d06d6bSBaptiste Daroussin done = 1;
135061d06d6bSBaptiste Daroussin }
135161d06d6bSBaptiste Daroussin
135261d06d6bSBaptiste Daroussin expand_count = 0;
135361d06d6bSBaptiste Daroussin while (stesc >= start) {
13547295610fSBaptiste Daroussin if (*stesc != newesc) {
135561d06d6bSBaptiste Daroussin
13567295610fSBaptiste Daroussin /*
13577295610fSBaptiste Daroussin * If we have a non-standard escape character,
13587295610fSBaptiste Daroussin * escape literal backslashes because all
13597295610fSBaptiste Daroussin * processing in subsequent functions uses
13607295610fSBaptiste Daroussin * the standard escaping rules.
13617295610fSBaptiste Daroussin */
136261d06d6bSBaptiste Daroussin
13637295610fSBaptiste Daroussin if (newesc != ASCII_ESC && *stesc == '\\') {
136461d06d6bSBaptiste Daroussin *stesc = '\0';
136561d06d6bSBaptiste Daroussin buf->sz = mandoc_asprintf(&nbuf, "%s\\e%s",
136661d06d6bSBaptiste Daroussin buf->buf, stesc + 1) + 1;
136761d06d6bSBaptiste Daroussin start = nbuf + pos;
136861d06d6bSBaptiste Daroussin stesc = nbuf + (stesc - buf->buf);
136961d06d6bSBaptiste Daroussin free(buf->buf);
137061d06d6bSBaptiste Daroussin buf->buf = nbuf;
137161d06d6bSBaptiste Daroussin }
13727295610fSBaptiste Daroussin
13737295610fSBaptiste Daroussin /* Search backwards for the next escape. */
13747295610fSBaptiste Daroussin
137561d06d6bSBaptiste Daroussin stesc--;
137661d06d6bSBaptiste Daroussin continue;
137761d06d6bSBaptiste Daroussin }
137861d06d6bSBaptiste Daroussin
137961d06d6bSBaptiste Daroussin /* If it is escaped, skip it. */
138061d06d6bSBaptiste Daroussin
138161d06d6bSBaptiste Daroussin for (cp = stesc - 1; cp >= start; cp--)
138261d06d6bSBaptiste Daroussin if (*cp != r->escape)
138361d06d6bSBaptiste Daroussin break;
138461d06d6bSBaptiste Daroussin
138561d06d6bSBaptiste Daroussin if ((stesc - cp) % 2 == 0) {
138661d06d6bSBaptiste Daroussin while (stesc > cp)
138761d06d6bSBaptiste Daroussin *stesc-- = '\\';
138861d06d6bSBaptiste Daroussin continue;
138961d06d6bSBaptiste Daroussin } else if (stesc[1] != '\0') {
139061d06d6bSBaptiste Daroussin *stesc = '\\';
139161d06d6bSBaptiste Daroussin } else {
139261d06d6bSBaptiste Daroussin *stesc-- = '\0';
139361d06d6bSBaptiste Daroussin if (done)
139461d06d6bSBaptiste Daroussin continue;
139561d06d6bSBaptiste Daroussin else
13967295610fSBaptiste Daroussin return ROFF_IGN | ROFF_APPEND;
139761d06d6bSBaptiste Daroussin }
139861d06d6bSBaptiste Daroussin
139961d06d6bSBaptiste Daroussin /* Decide whether to expand or to check only. */
140061d06d6bSBaptiste Daroussin
140161d06d6bSBaptiste Daroussin term = '\0';
140261d06d6bSBaptiste Daroussin cp = stesc + 1;
14037295610fSBaptiste Daroussin if (*cp == 'E')
14047295610fSBaptiste Daroussin cp++;
14057295610fSBaptiste Daroussin esct = cp;
14067295610fSBaptiste Daroussin switch (*esct) {
140761d06d6bSBaptiste Daroussin case '*':
14087295610fSBaptiste Daroussin case '$':
140961d06d6bSBaptiste Daroussin res = NULL;
141061d06d6bSBaptiste Daroussin break;
141161d06d6bSBaptiste Daroussin case 'B':
141261d06d6bSBaptiste Daroussin case 'w':
141361d06d6bSBaptiste Daroussin term = cp[1];
141461d06d6bSBaptiste Daroussin /* FALLTHROUGH */
141561d06d6bSBaptiste Daroussin case 'n':
141661d06d6bSBaptiste Daroussin sign = cp[1];
141761d06d6bSBaptiste Daroussin if (sign == '+' || sign == '-')
141861d06d6bSBaptiste Daroussin cp++;
141961d06d6bSBaptiste Daroussin res = ubuf;
142061d06d6bSBaptiste Daroussin break;
142161d06d6bSBaptiste Daroussin default:
14227295610fSBaptiste Daroussin err = MANDOCERR_OK;
14237295610fSBaptiste Daroussin switch(mandoc_escape(&cp, &stnam, &inaml)) {
14247295610fSBaptiste Daroussin case ESCAPE_SPECIAL:
14257295610fSBaptiste Daroussin if (mchars_spec2cp(stnam, inaml) >= 0)
14267295610fSBaptiste Daroussin break;
14277295610fSBaptiste Daroussin /* FALLTHROUGH */
14287295610fSBaptiste Daroussin case ESCAPE_ERROR:
14297295610fSBaptiste Daroussin err = MANDOCERR_ESC_BAD;
14307295610fSBaptiste Daroussin break;
14317295610fSBaptiste Daroussin case ESCAPE_UNDEF:
14327295610fSBaptiste Daroussin err = MANDOCERR_ESC_UNDEF;
14337295610fSBaptiste Daroussin break;
14347295610fSBaptiste Daroussin case ESCAPE_UNSUPP:
14357295610fSBaptiste Daroussin err = MANDOCERR_ESC_UNSUPP;
14367295610fSBaptiste Daroussin break;
14377295610fSBaptiste Daroussin default:
14387295610fSBaptiste Daroussin break;
14397295610fSBaptiste Daroussin }
14407295610fSBaptiste Daroussin if (err != MANDOCERR_OK)
14417295610fSBaptiste Daroussin mandoc_msg(err, ln, (int)(stesc - buf->buf),
144261d06d6bSBaptiste Daroussin "%.*s", (int)(cp - stesc), stesc);
144361d06d6bSBaptiste Daroussin stesc--;
144461d06d6bSBaptiste Daroussin continue;
144561d06d6bSBaptiste Daroussin }
144661d06d6bSBaptiste Daroussin
144761d06d6bSBaptiste Daroussin if (EXPAND_LIMIT < ++expand_count) {
14487295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ROFFLOOP,
144961d06d6bSBaptiste Daroussin ln, (int)(stesc - buf->buf), NULL);
145061d06d6bSBaptiste Daroussin return ROFF_IGN;
145161d06d6bSBaptiste Daroussin }
145261d06d6bSBaptiste Daroussin
145361d06d6bSBaptiste Daroussin /*
145461d06d6bSBaptiste Daroussin * The third character decides the length
145561d06d6bSBaptiste Daroussin * of the name of the string or register.
145661d06d6bSBaptiste Daroussin * Save a pointer to the name.
145761d06d6bSBaptiste Daroussin */
145861d06d6bSBaptiste Daroussin
145961d06d6bSBaptiste Daroussin if (term == '\0') {
146061d06d6bSBaptiste Daroussin switch (*++cp) {
146161d06d6bSBaptiste Daroussin case '\0':
146261d06d6bSBaptiste Daroussin maxl = 0;
146361d06d6bSBaptiste Daroussin break;
146461d06d6bSBaptiste Daroussin case '(':
146561d06d6bSBaptiste Daroussin cp++;
146661d06d6bSBaptiste Daroussin maxl = 2;
146761d06d6bSBaptiste Daroussin break;
146861d06d6bSBaptiste Daroussin case '[':
146961d06d6bSBaptiste Daroussin cp++;
147061d06d6bSBaptiste Daroussin term = ']';
147161d06d6bSBaptiste Daroussin maxl = 0;
147261d06d6bSBaptiste Daroussin break;
147361d06d6bSBaptiste Daroussin default:
147461d06d6bSBaptiste Daroussin maxl = 1;
147561d06d6bSBaptiste Daroussin break;
147661d06d6bSBaptiste Daroussin }
147761d06d6bSBaptiste Daroussin } else {
147861d06d6bSBaptiste Daroussin cp += 2;
147961d06d6bSBaptiste Daroussin maxl = 0;
148061d06d6bSBaptiste Daroussin }
148161d06d6bSBaptiste Daroussin stnam = cp;
148261d06d6bSBaptiste Daroussin
148361d06d6bSBaptiste Daroussin /* Advance to the end of the name. */
148461d06d6bSBaptiste Daroussin
148561d06d6bSBaptiste Daroussin naml = 0;
148661d06d6bSBaptiste Daroussin arg_complete = 1;
148761d06d6bSBaptiste Daroussin while (maxl == 0 || naml < maxl) {
148861d06d6bSBaptiste Daroussin if (*cp == '\0') {
14897295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ESC_BAD, ln,
14907295610fSBaptiste Daroussin (int)(stesc - buf->buf), "%s", stesc);
149161d06d6bSBaptiste Daroussin arg_complete = 0;
149261d06d6bSBaptiste Daroussin break;
149361d06d6bSBaptiste Daroussin }
149461d06d6bSBaptiste Daroussin if (maxl == 0 && *cp == term) {
149561d06d6bSBaptiste Daroussin cp++;
149661d06d6bSBaptiste Daroussin break;
149761d06d6bSBaptiste Daroussin }
14987295610fSBaptiste Daroussin if (*cp++ != '\\' || *esct != 'w') {
149961d06d6bSBaptiste Daroussin naml++;
150061d06d6bSBaptiste Daroussin continue;
150161d06d6bSBaptiste Daroussin }
150261d06d6bSBaptiste Daroussin switch (mandoc_escape(&cp, NULL, NULL)) {
150361d06d6bSBaptiste Daroussin case ESCAPE_SPECIAL:
150461d06d6bSBaptiste Daroussin case ESCAPE_UNICODE:
150561d06d6bSBaptiste Daroussin case ESCAPE_NUMBERED:
15067295610fSBaptiste Daroussin case ESCAPE_UNDEF:
150761d06d6bSBaptiste Daroussin case ESCAPE_OVERSTRIKE:
150861d06d6bSBaptiste Daroussin naml++;
150961d06d6bSBaptiste Daroussin break;
151061d06d6bSBaptiste Daroussin default:
151161d06d6bSBaptiste Daroussin break;
151261d06d6bSBaptiste Daroussin }
151361d06d6bSBaptiste Daroussin }
151461d06d6bSBaptiste Daroussin
151561d06d6bSBaptiste Daroussin /*
151661d06d6bSBaptiste Daroussin * Retrieve the replacement string; if it is
151761d06d6bSBaptiste Daroussin * undefined, resume searching for escapes.
151861d06d6bSBaptiste Daroussin */
151961d06d6bSBaptiste Daroussin
15207295610fSBaptiste Daroussin switch (*esct) {
152161d06d6bSBaptiste Daroussin case '*':
152261d06d6bSBaptiste Daroussin if (arg_complete) {
152361d06d6bSBaptiste Daroussin deftype = ROFFDEF_USER | ROFFDEF_PRE;
152461d06d6bSBaptiste Daroussin res = roff_getstrn(r, stnam, naml, &deftype);
15257295610fSBaptiste Daroussin
15267295610fSBaptiste Daroussin /*
15277295610fSBaptiste Daroussin * If not overriden, let \*(.T
15287295610fSBaptiste Daroussin * through to the formatters.
15297295610fSBaptiste Daroussin */
15307295610fSBaptiste Daroussin
15317295610fSBaptiste Daroussin if (res == NULL && naml == 2 &&
15327295610fSBaptiste Daroussin stnam[0] == '.' && stnam[1] == 'T') {
15337295610fSBaptiste Daroussin roff_setstrn(&r->strtab,
15347295610fSBaptiste Daroussin ".T", 2, NULL, 0, 0);
15357295610fSBaptiste Daroussin stesc--;
15367295610fSBaptiste Daroussin continue;
15377295610fSBaptiste Daroussin }
153861d06d6bSBaptiste Daroussin }
153961d06d6bSBaptiste Daroussin break;
15407295610fSBaptiste Daroussin case '$':
15417295610fSBaptiste Daroussin if (r->mstackpos < 0) {
15427295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_UNDEF, ln,
15437295610fSBaptiste Daroussin (int)(stesc - buf->buf), "%.3s", stesc);
15447295610fSBaptiste Daroussin break;
15457295610fSBaptiste Daroussin }
15467295610fSBaptiste Daroussin ctx = r->mstack + r->mstackpos;
15477295610fSBaptiste Daroussin npos = esct[1] - '1';
15487295610fSBaptiste Daroussin if (npos >= 0 && npos <= 8) {
15497295610fSBaptiste Daroussin res = npos < ctx->argc ?
15507295610fSBaptiste Daroussin ctx->argv[npos] : "";
15517295610fSBaptiste Daroussin break;
15527295610fSBaptiste Daroussin }
15537295610fSBaptiste Daroussin if (esct[1] == '*')
15547295610fSBaptiste Daroussin quote_args = 0;
15557295610fSBaptiste Daroussin else if (esct[1] == '@')
15567295610fSBaptiste Daroussin quote_args = 1;
15577295610fSBaptiste Daroussin else {
15587295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_NONUM, ln,
15597295610fSBaptiste Daroussin (int)(stesc - buf->buf), "%.3s", stesc);
15607295610fSBaptiste Daroussin break;
15617295610fSBaptiste Daroussin }
15627295610fSBaptiste Daroussin asz = 0;
15637295610fSBaptiste Daroussin for (npos = 0; npos < ctx->argc; npos++) {
15647295610fSBaptiste Daroussin if (npos)
15657295610fSBaptiste Daroussin asz++; /* blank */
15667295610fSBaptiste Daroussin if (quote_args)
15677295610fSBaptiste Daroussin asz += 2; /* quotes */
15687295610fSBaptiste Daroussin asz += strlen(ctx->argv[npos]);
15697295610fSBaptiste Daroussin }
15707295610fSBaptiste Daroussin if (asz != 3) {
15717295610fSBaptiste Daroussin rsz = buf->sz - (stesc - buf->buf) - 3;
15727295610fSBaptiste Daroussin if (asz < 3)
15737295610fSBaptiste Daroussin memmove(stesc + asz, stesc + 3, rsz);
15747295610fSBaptiste Daroussin buf->sz += asz - 3;
15757295610fSBaptiste Daroussin nbuf = mandoc_realloc(buf->buf, buf->sz);
15767295610fSBaptiste Daroussin start = nbuf + pos;
15777295610fSBaptiste Daroussin stesc = nbuf + (stesc - buf->buf);
15787295610fSBaptiste Daroussin buf->buf = nbuf;
15797295610fSBaptiste Daroussin if (asz > 3)
15807295610fSBaptiste Daroussin memmove(stesc + asz, stesc + 3, rsz);
15817295610fSBaptiste Daroussin }
15827295610fSBaptiste Daroussin for (npos = 0; npos < ctx->argc; npos++) {
15837295610fSBaptiste Daroussin if (npos)
15847295610fSBaptiste Daroussin *stesc++ = ' ';
15857295610fSBaptiste Daroussin if (quote_args)
15867295610fSBaptiste Daroussin *stesc++ = '"';
15877295610fSBaptiste Daroussin cp = ctx->argv[npos];
15887295610fSBaptiste Daroussin while (*cp != '\0')
15897295610fSBaptiste Daroussin *stesc++ = *cp++;
15907295610fSBaptiste Daroussin if (quote_args)
15917295610fSBaptiste Daroussin *stesc++ = '"';
15927295610fSBaptiste Daroussin }
15937295610fSBaptiste Daroussin continue;
159461d06d6bSBaptiste Daroussin case 'B':
159561d06d6bSBaptiste Daroussin npos = 0;
159661d06d6bSBaptiste Daroussin ubuf[0] = arg_complete &&
159761d06d6bSBaptiste Daroussin roff_evalnum(r, ln, stnam, &npos,
159861d06d6bSBaptiste Daroussin NULL, ROFFNUM_SCALE) &&
159961d06d6bSBaptiste Daroussin stnam + npos + 1 == cp ? '1' : '0';
160061d06d6bSBaptiste Daroussin ubuf[1] = '\0';
160161d06d6bSBaptiste Daroussin break;
160261d06d6bSBaptiste Daroussin case 'n':
160361d06d6bSBaptiste Daroussin if (arg_complete)
160461d06d6bSBaptiste Daroussin (void)snprintf(ubuf, sizeof(ubuf), "%d",
160561d06d6bSBaptiste Daroussin roff_getregn(r, stnam, naml, sign));
160661d06d6bSBaptiste Daroussin else
160761d06d6bSBaptiste Daroussin ubuf[0] = '\0';
160861d06d6bSBaptiste Daroussin break;
160961d06d6bSBaptiste Daroussin case 'w':
161061d06d6bSBaptiste Daroussin /* use even incomplete args */
161161d06d6bSBaptiste Daroussin (void)snprintf(ubuf, sizeof(ubuf), "%d",
161261d06d6bSBaptiste Daroussin 24 * (int)naml);
161361d06d6bSBaptiste Daroussin break;
161461d06d6bSBaptiste Daroussin }
161561d06d6bSBaptiste Daroussin
161661d06d6bSBaptiste Daroussin if (res == NULL) {
16177295610fSBaptiste Daroussin if (*esct == '*')
16187295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_STR_UNDEF,
16197295610fSBaptiste Daroussin ln, (int)(stesc - buf->buf),
162061d06d6bSBaptiste Daroussin "%.*s", (int)naml, stnam);
162161d06d6bSBaptiste Daroussin res = "";
162261d06d6bSBaptiste Daroussin } else if (buf->sz + strlen(res) > SHRT_MAX) {
16237295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ROFFLOOP,
162461d06d6bSBaptiste Daroussin ln, (int)(stesc - buf->buf), NULL);
162561d06d6bSBaptiste Daroussin return ROFF_IGN;
162661d06d6bSBaptiste Daroussin }
162761d06d6bSBaptiste Daroussin
162861d06d6bSBaptiste Daroussin /* Replace the escape sequence by the string. */
162961d06d6bSBaptiste Daroussin
163061d06d6bSBaptiste Daroussin *stesc = '\0';
163161d06d6bSBaptiste Daroussin buf->sz = mandoc_asprintf(&nbuf, "%s%s%s",
163261d06d6bSBaptiste Daroussin buf->buf, res, cp) + 1;
163361d06d6bSBaptiste Daroussin
163461d06d6bSBaptiste Daroussin /* Prepare for the next replacement. */
163561d06d6bSBaptiste Daroussin
163661d06d6bSBaptiste Daroussin start = nbuf + pos;
163761d06d6bSBaptiste Daroussin stesc = nbuf + (stesc - buf->buf) + strlen(res);
163861d06d6bSBaptiste Daroussin free(buf->buf);
163961d06d6bSBaptiste Daroussin buf->buf = nbuf;
164061d06d6bSBaptiste Daroussin }
164161d06d6bSBaptiste Daroussin return ROFF_CONT;
164261d06d6bSBaptiste Daroussin }
164361d06d6bSBaptiste Daroussin
164461d06d6bSBaptiste Daroussin /*
16457295610fSBaptiste Daroussin * Parse a quoted or unquoted roff-style request or macro argument.
16467295610fSBaptiste Daroussin * Return a pointer to the parsed argument, which is either the original
16477295610fSBaptiste Daroussin * pointer or advanced by one byte in case the argument is quoted.
16487295610fSBaptiste Daroussin * NUL-terminate the argument in place.
16497295610fSBaptiste Daroussin * Collapse pairs of quotes inside quoted arguments.
16507295610fSBaptiste Daroussin * Advance the argument pointer to the next argument,
16517295610fSBaptiste Daroussin * or to the NUL byte terminating the argument line.
16527295610fSBaptiste Daroussin */
16537295610fSBaptiste Daroussin char *
roff_getarg(struct roff * r,char ** cpp,int ln,int * pos)16547295610fSBaptiste Daroussin roff_getarg(struct roff *r, char **cpp, int ln, int *pos)
16557295610fSBaptiste Daroussin {
16567295610fSBaptiste Daroussin struct buf buf;
16577295610fSBaptiste Daroussin char *cp, *start;
16587295610fSBaptiste Daroussin int newesc, pairs, quoted, white;
16597295610fSBaptiste Daroussin
16607295610fSBaptiste Daroussin /* Quoting can only start with a new word. */
16617295610fSBaptiste Daroussin start = *cpp;
16627295610fSBaptiste Daroussin quoted = 0;
16637295610fSBaptiste Daroussin if ('"' == *start) {
16647295610fSBaptiste Daroussin quoted = 1;
16657295610fSBaptiste Daroussin start++;
16667295610fSBaptiste Daroussin }
16677295610fSBaptiste Daroussin
16687295610fSBaptiste Daroussin newesc = pairs = white = 0;
16697295610fSBaptiste Daroussin for (cp = start; '\0' != *cp; cp++) {
16707295610fSBaptiste Daroussin
16717295610fSBaptiste Daroussin /*
16727295610fSBaptiste Daroussin * Move the following text left
16737295610fSBaptiste Daroussin * after quoted quotes and after "\\" and "\t".
16747295610fSBaptiste Daroussin */
16757295610fSBaptiste Daroussin if (pairs)
16767295610fSBaptiste Daroussin cp[-pairs] = cp[0];
16777295610fSBaptiste Daroussin
16787295610fSBaptiste Daroussin if ('\\' == cp[0]) {
16797295610fSBaptiste Daroussin /*
16807295610fSBaptiste Daroussin * In copy mode, translate double to single
16817295610fSBaptiste Daroussin * backslashes and backslash-t to literal tabs.
16827295610fSBaptiste Daroussin */
16837295610fSBaptiste Daroussin switch (cp[1]) {
16847295610fSBaptiste Daroussin case 'a':
16857295610fSBaptiste Daroussin case 't':
16867295610fSBaptiste Daroussin cp[-pairs] = '\t';
16877295610fSBaptiste Daroussin pairs++;
16887295610fSBaptiste Daroussin cp++;
16897295610fSBaptiste Daroussin break;
16907295610fSBaptiste Daroussin case '\\':
16917295610fSBaptiste Daroussin newesc = 1;
16927295610fSBaptiste Daroussin cp[-pairs] = ASCII_ESC;
16937295610fSBaptiste Daroussin pairs++;
16947295610fSBaptiste Daroussin cp++;
16957295610fSBaptiste Daroussin break;
16967295610fSBaptiste Daroussin case ' ':
16977295610fSBaptiste Daroussin /* Skip escaped blanks. */
16987295610fSBaptiste Daroussin if (0 == quoted)
16997295610fSBaptiste Daroussin cp++;
17007295610fSBaptiste Daroussin break;
17017295610fSBaptiste Daroussin default:
17027295610fSBaptiste Daroussin break;
17037295610fSBaptiste Daroussin }
17047295610fSBaptiste Daroussin } else if (0 == quoted) {
17057295610fSBaptiste Daroussin if (' ' == cp[0]) {
17067295610fSBaptiste Daroussin /* Unescaped blanks end unquoted args. */
17077295610fSBaptiste Daroussin white = 1;
17087295610fSBaptiste Daroussin break;
17097295610fSBaptiste Daroussin }
17107295610fSBaptiste Daroussin } else if ('"' == cp[0]) {
17117295610fSBaptiste Daroussin if ('"' == cp[1]) {
17127295610fSBaptiste Daroussin /* Quoted quotes collapse. */
17137295610fSBaptiste Daroussin pairs++;
17147295610fSBaptiste Daroussin cp++;
17157295610fSBaptiste Daroussin } else {
17167295610fSBaptiste Daroussin /* Unquoted quotes end quoted args. */
17177295610fSBaptiste Daroussin quoted = 2;
17187295610fSBaptiste Daroussin break;
17197295610fSBaptiste Daroussin }
17207295610fSBaptiste Daroussin }
17217295610fSBaptiste Daroussin }
17227295610fSBaptiste Daroussin
17237295610fSBaptiste Daroussin /* Quoted argument without a closing quote. */
17247295610fSBaptiste Daroussin if (1 == quoted)
17257295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_QUOTE, ln, *pos, NULL);
17267295610fSBaptiste Daroussin
17277295610fSBaptiste Daroussin /* NUL-terminate this argument and move to the next one. */
17287295610fSBaptiste Daroussin if (pairs)
17297295610fSBaptiste Daroussin cp[-pairs] = '\0';
17307295610fSBaptiste Daroussin if ('\0' != *cp) {
17317295610fSBaptiste Daroussin *cp++ = '\0';
17327295610fSBaptiste Daroussin while (' ' == *cp)
17337295610fSBaptiste Daroussin cp++;
17347295610fSBaptiste Daroussin }
17357295610fSBaptiste Daroussin *pos += (int)(cp - start) + (quoted ? 1 : 0);
17367295610fSBaptiste Daroussin *cpp = cp;
17377295610fSBaptiste Daroussin
17387295610fSBaptiste Daroussin if ('\0' == *cp && (white || ' ' == cp[-1]))
17397295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_SPACE_EOL, ln, *pos, NULL);
17407295610fSBaptiste Daroussin
17417295610fSBaptiste Daroussin start = mandoc_strdup(start);
17427295610fSBaptiste Daroussin if (newesc == 0)
17437295610fSBaptiste Daroussin return start;
17447295610fSBaptiste Daroussin
17457295610fSBaptiste Daroussin buf.buf = start;
17467295610fSBaptiste Daroussin buf.sz = strlen(start) + 1;
17477295610fSBaptiste Daroussin buf.next = NULL;
17487295610fSBaptiste Daroussin if (roff_expand(r, &buf, ln, 0, ASCII_ESC) & ROFF_IGN) {
17497295610fSBaptiste Daroussin free(buf.buf);
17507295610fSBaptiste Daroussin buf.buf = mandoc_strdup("");
17517295610fSBaptiste Daroussin }
17527295610fSBaptiste Daroussin return buf.buf;
17537295610fSBaptiste Daroussin }
17547295610fSBaptiste Daroussin
17557295610fSBaptiste Daroussin
17567295610fSBaptiste Daroussin /*
175761d06d6bSBaptiste Daroussin * Process text streams.
175861d06d6bSBaptiste Daroussin */
17597295610fSBaptiste Daroussin static int
roff_parsetext(struct roff * r,struct buf * buf,int pos,int * offs)176061d06d6bSBaptiste Daroussin roff_parsetext(struct roff *r, struct buf *buf, int pos, int *offs)
176161d06d6bSBaptiste Daroussin {
176261d06d6bSBaptiste Daroussin size_t sz;
176361d06d6bSBaptiste Daroussin const char *start;
176461d06d6bSBaptiste Daroussin char *p;
176561d06d6bSBaptiste Daroussin int isz;
176661d06d6bSBaptiste Daroussin enum mandoc_esc esc;
176761d06d6bSBaptiste Daroussin
176861d06d6bSBaptiste Daroussin /* Spring the input line trap. */
176961d06d6bSBaptiste Daroussin
177061d06d6bSBaptiste Daroussin if (roffit_lines == 1) {
177161d06d6bSBaptiste Daroussin isz = mandoc_asprintf(&p, "%s\n.%s", buf->buf, roffit_macro);
177261d06d6bSBaptiste Daroussin free(buf->buf);
177361d06d6bSBaptiste Daroussin buf->buf = p;
177461d06d6bSBaptiste Daroussin buf->sz = isz + 1;
177561d06d6bSBaptiste Daroussin *offs = 0;
177661d06d6bSBaptiste Daroussin free(roffit_macro);
177761d06d6bSBaptiste Daroussin roffit_lines = 0;
177861d06d6bSBaptiste Daroussin return ROFF_REPARSE;
177961d06d6bSBaptiste Daroussin } else if (roffit_lines > 1)
178061d06d6bSBaptiste Daroussin --roffit_lines;
178161d06d6bSBaptiste Daroussin
178261d06d6bSBaptiste Daroussin if (roffce_node != NULL && buf->buf[pos] != '\0') {
178361d06d6bSBaptiste Daroussin if (roffce_lines < 1) {
178461d06d6bSBaptiste Daroussin r->man->last = roffce_node;
178561d06d6bSBaptiste Daroussin r->man->next = ROFF_NEXT_SIBLING;
178661d06d6bSBaptiste Daroussin roffce_lines = 0;
178761d06d6bSBaptiste Daroussin roffce_node = NULL;
178861d06d6bSBaptiste Daroussin } else
178961d06d6bSBaptiste Daroussin roffce_lines--;
179061d06d6bSBaptiste Daroussin }
179161d06d6bSBaptiste Daroussin
179261d06d6bSBaptiste Daroussin /* Convert all breakable hyphens into ASCII_HYPH. */
179361d06d6bSBaptiste Daroussin
179461d06d6bSBaptiste Daroussin start = p = buf->buf + pos;
179561d06d6bSBaptiste Daroussin
179661d06d6bSBaptiste Daroussin while (*p != '\0') {
179761d06d6bSBaptiste Daroussin sz = strcspn(p, "-\\");
179861d06d6bSBaptiste Daroussin p += sz;
179961d06d6bSBaptiste Daroussin
180061d06d6bSBaptiste Daroussin if (*p == '\0')
180161d06d6bSBaptiste Daroussin break;
180261d06d6bSBaptiste Daroussin
180361d06d6bSBaptiste Daroussin if (*p == '\\') {
180461d06d6bSBaptiste Daroussin /* Skip over escapes. */
180561d06d6bSBaptiste Daroussin p++;
180661d06d6bSBaptiste Daroussin esc = mandoc_escape((const char **)&p, NULL, NULL);
180761d06d6bSBaptiste Daroussin if (esc == ESCAPE_ERROR)
180861d06d6bSBaptiste Daroussin break;
180961d06d6bSBaptiste Daroussin while (*p == '-')
181061d06d6bSBaptiste Daroussin p++;
181161d06d6bSBaptiste Daroussin continue;
181261d06d6bSBaptiste Daroussin } else if (p == start) {
181361d06d6bSBaptiste Daroussin p++;
181461d06d6bSBaptiste Daroussin continue;
181561d06d6bSBaptiste Daroussin }
181661d06d6bSBaptiste Daroussin
181761d06d6bSBaptiste Daroussin if (isalpha((unsigned char)p[-1]) &&
181861d06d6bSBaptiste Daroussin isalpha((unsigned char)p[1]))
181961d06d6bSBaptiste Daroussin *p = ASCII_HYPH;
182061d06d6bSBaptiste Daroussin p++;
182161d06d6bSBaptiste Daroussin }
182261d06d6bSBaptiste Daroussin return ROFF_CONT;
182361d06d6bSBaptiste Daroussin }
182461d06d6bSBaptiste Daroussin
18257295610fSBaptiste Daroussin int
roff_parseln(struct roff * r,int ln,struct buf * buf,int * offs,size_t len)1826*6d38604fSBaptiste Daroussin roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs, size_t len)
182761d06d6bSBaptiste Daroussin {
182861d06d6bSBaptiste Daroussin enum roff_tok t;
18297295610fSBaptiste Daroussin int e;
183061d06d6bSBaptiste Daroussin int pos; /* parse point */
183161d06d6bSBaptiste Daroussin int spos; /* saved parse point for messages */
183261d06d6bSBaptiste Daroussin int ppos; /* original offset in buf->buf */
183361d06d6bSBaptiste Daroussin int ctl; /* macro line (boolean) */
183461d06d6bSBaptiste Daroussin
183561d06d6bSBaptiste Daroussin ppos = pos = *offs;
183661d06d6bSBaptiste Daroussin
1837*6d38604fSBaptiste Daroussin if (len > 80 && r->tbl == NULL && r->eqn == NULL &&
1838*6d38604fSBaptiste Daroussin (r->man->flags & ROFF_NOFILL) == 0 &&
1839*6d38604fSBaptiste Daroussin strchr(" .\\", buf->buf[pos]) == NULL &&
1840*6d38604fSBaptiste Daroussin buf->buf[pos] != r->control &&
1841*6d38604fSBaptiste Daroussin strcspn(buf->buf, " ") < 80)
1842*6d38604fSBaptiste Daroussin mandoc_msg(MANDOCERR_TEXT_LONG, ln, (int)len - 1,
1843*6d38604fSBaptiste Daroussin "%.20s...", buf->buf + pos);
1844*6d38604fSBaptiste Daroussin
184561d06d6bSBaptiste Daroussin /* Handle in-line equation delimiters. */
184661d06d6bSBaptiste Daroussin
184761d06d6bSBaptiste Daroussin if (r->tbl == NULL &&
184861d06d6bSBaptiste Daroussin r->last_eqn != NULL && r->last_eqn->delim &&
184961d06d6bSBaptiste Daroussin (r->eqn == NULL || r->eqn_inline)) {
185061d06d6bSBaptiste Daroussin e = roff_eqndelim(r, buf, pos);
185161d06d6bSBaptiste Daroussin if (e == ROFF_REPARSE)
185261d06d6bSBaptiste Daroussin return e;
185361d06d6bSBaptiste Daroussin assert(e == ROFF_CONT);
185461d06d6bSBaptiste Daroussin }
185561d06d6bSBaptiste Daroussin
185661d06d6bSBaptiste Daroussin /* Expand some escape sequences. */
185761d06d6bSBaptiste Daroussin
18587295610fSBaptiste Daroussin e = roff_expand(r, buf, ln, pos, r->escape);
18597295610fSBaptiste Daroussin if ((e & ROFF_MASK) == ROFF_IGN)
186061d06d6bSBaptiste Daroussin return e;
186161d06d6bSBaptiste Daroussin assert(e == ROFF_CONT);
186261d06d6bSBaptiste Daroussin
186361d06d6bSBaptiste Daroussin ctl = roff_getcontrol(r, buf->buf, &pos);
186461d06d6bSBaptiste Daroussin
186561d06d6bSBaptiste Daroussin /*
186661d06d6bSBaptiste Daroussin * First, if a scope is open and we're not a macro, pass the
186761d06d6bSBaptiste Daroussin * text through the macro's filter.
186861d06d6bSBaptiste Daroussin * Equations process all content themselves.
186961d06d6bSBaptiste Daroussin * Tables process almost all content themselves, but we want
187061d06d6bSBaptiste Daroussin * to warn about macros before passing it there.
187161d06d6bSBaptiste Daroussin */
187261d06d6bSBaptiste Daroussin
187361d06d6bSBaptiste Daroussin if (r->last != NULL && ! ctl) {
187461d06d6bSBaptiste Daroussin t = r->last->tok;
187561d06d6bSBaptiste Daroussin e = (*roffs[t].text)(r, t, buf, ln, pos, pos, offs);
18767295610fSBaptiste Daroussin if ((e & ROFF_MASK) == ROFF_IGN)
187761d06d6bSBaptiste Daroussin return e;
18787295610fSBaptiste Daroussin e &= ~ROFF_MASK;
18797295610fSBaptiste Daroussin } else
18807295610fSBaptiste Daroussin e = ROFF_IGN;
188161d06d6bSBaptiste Daroussin if (r->eqn != NULL && strncmp(buf->buf + ppos, ".EN", 3)) {
188261d06d6bSBaptiste Daroussin eqn_read(r->eqn, buf->buf + ppos);
18837295610fSBaptiste Daroussin return e;
188461d06d6bSBaptiste Daroussin }
188561d06d6bSBaptiste Daroussin if (r->tbl != NULL && (ctl == 0 || buf->buf[pos] == '\0')) {
188661d06d6bSBaptiste Daroussin tbl_read(r->tbl, ln, buf->buf, ppos);
18877295610fSBaptiste Daroussin roff_addtbl(r->man, ln, r->tbl);
18887295610fSBaptiste Daroussin return e;
188961d06d6bSBaptiste Daroussin }
1890*6d38604fSBaptiste Daroussin if ( ! ctl) {
1891*6d38604fSBaptiste Daroussin r->options &= ~MPARSE_COMMENT;
18927295610fSBaptiste Daroussin return roff_parsetext(r, buf, pos, offs) | e;
1893*6d38604fSBaptiste Daroussin }
189461d06d6bSBaptiste Daroussin
189561d06d6bSBaptiste Daroussin /* Skip empty request lines. */
189661d06d6bSBaptiste Daroussin
189761d06d6bSBaptiste Daroussin if (buf->buf[pos] == '"') {
18987295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_COMMENT_BAD, ln, pos, NULL);
189961d06d6bSBaptiste Daroussin return ROFF_IGN;
190061d06d6bSBaptiste Daroussin } else if (buf->buf[pos] == '\0')
190161d06d6bSBaptiste Daroussin return ROFF_IGN;
190261d06d6bSBaptiste Daroussin
190361d06d6bSBaptiste Daroussin /*
190461d06d6bSBaptiste Daroussin * If a scope is open, go to the child handler for that macro,
190561d06d6bSBaptiste Daroussin * as it may want to preprocess before doing anything with it.
190661d06d6bSBaptiste Daroussin * Don't do so if an equation is open.
190761d06d6bSBaptiste Daroussin */
190861d06d6bSBaptiste Daroussin
190961d06d6bSBaptiste Daroussin if (r->last) {
191061d06d6bSBaptiste Daroussin t = r->last->tok;
191161d06d6bSBaptiste Daroussin return (*roffs[t].sub)(r, t, buf, ln, ppos, pos, offs);
191261d06d6bSBaptiste Daroussin }
191361d06d6bSBaptiste Daroussin
191461d06d6bSBaptiste Daroussin /* No scope is open. This is a new request or macro. */
191561d06d6bSBaptiste Daroussin
1916*6d38604fSBaptiste Daroussin r->options &= ~MPARSE_COMMENT;
191761d06d6bSBaptiste Daroussin spos = pos;
191861d06d6bSBaptiste Daroussin t = roff_parse(r, buf->buf, &pos, ln, ppos);
191961d06d6bSBaptiste Daroussin
192061d06d6bSBaptiste Daroussin /* Tables ignore most macros. */
192161d06d6bSBaptiste Daroussin
192261d06d6bSBaptiste Daroussin if (r->tbl != NULL && (t == TOKEN_NONE || t == ROFF_TS ||
192361d06d6bSBaptiste Daroussin t == ROFF_br || t == ROFF_ce || t == ROFF_rj || t == ROFF_sp)) {
19247295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_TBLMACRO,
19257295610fSBaptiste Daroussin ln, pos, "%s", buf->buf + spos);
192661d06d6bSBaptiste Daroussin if (t != TOKEN_NONE)
192761d06d6bSBaptiste Daroussin return ROFF_IGN;
192861d06d6bSBaptiste Daroussin while (buf->buf[pos] != '\0' && buf->buf[pos] != ' ')
192961d06d6bSBaptiste Daroussin pos++;
193061d06d6bSBaptiste Daroussin while (buf->buf[pos] == ' ')
193161d06d6bSBaptiste Daroussin pos++;
193261d06d6bSBaptiste Daroussin tbl_read(r->tbl, ln, buf->buf, pos);
19337295610fSBaptiste Daroussin roff_addtbl(r->man, ln, r->tbl);
193461d06d6bSBaptiste Daroussin return ROFF_IGN;
193561d06d6bSBaptiste Daroussin }
193661d06d6bSBaptiste Daroussin
193761d06d6bSBaptiste Daroussin /* For now, let high level macros abort .ce mode. */
193861d06d6bSBaptiste Daroussin
193961d06d6bSBaptiste Daroussin if (ctl && roffce_node != NULL &&
194061d06d6bSBaptiste Daroussin (t == TOKEN_NONE || t == ROFF_Dd || t == ROFF_EQ ||
194161d06d6bSBaptiste Daroussin t == ROFF_TH || t == ROFF_TS)) {
194261d06d6bSBaptiste Daroussin r->man->last = roffce_node;
194361d06d6bSBaptiste Daroussin r->man->next = ROFF_NEXT_SIBLING;
194461d06d6bSBaptiste Daroussin roffce_lines = 0;
194561d06d6bSBaptiste Daroussin roffce_node = NULL;
194661d06d6bSBaptiste Daroussin }
194761d06d6bSBaptiste Daroussin
194861d06d6bSBaptiste Daroussin /*
194961d06d6bSBaptiste Daroussin * This is neither a roff request nor a user-defined macro.
195061d06d6bSBaptiste Daroussin * Let the standard macro set parsers handle it.
195161d06d6bSBaptiste Daroussin */
195261d06d6bSBaptiste Daroussin
195361d06d6bSBaptiste Daroussin if (t == TOKEN_NONE)
195461d06d6bSBaptiste Daroussin return ROFF_CONT;
195561d06d6bSBaptiste Daroussin
195661d06d6bSBaptiste Daroussin /* Execute a roff request or a user defined macro. */
195761d06d6bSBaptiste Daroussin
195861d06d6bSBaptiste Daroussin return (*roffs[t].proc)(r, t, buf, ln, spos, pos, offs);
195961d06d6bSBaptiste Daroussin }
196061d06d6bSBaptiste Daroussin
19617295610fSBaptiste Daroussin /*
19627295610fSBaptiste Daroussin * Internal interface function to tell the roff parser that execution
19637295610fSBaptiste Daroussin * of the current macro ended. This is required because macro
19647295610fSBaptiste Daroussin * definitions usually do not end with a .return request.
19657295610fSBaptiste Daroussin */
19667295610fSBaptiste Daroussin void
roff_userret(struct roff * r)19677295610fSBaptiste Daroussin roff_userret(struct roff *r)
19687295610fSBaptiste Daroussin {
19697295610fSBaptiste Daroussin struct mctx *ctx;
19707295610fSBaptiste Daroussin int i;
19717295610fSBaptiste Daroussin
19727295610fSBaptiste Daroussin assert(r->mstackpos >= 0);
19737295610fSBaptiste Daroussin ctx = r->mstack + r->mstackpos;
19747295610fSBaptiste Daroussin for (i = 0; i < ctx->argc; i++)
19757295610fSBaptiste Daroussin free(ctx->argv[i]);
19767295610fSBaptiste Daroussin ctx->argc = 0;
19777295610fSBaptiste Daroussin r->mstackpos--;
19787295610fSBaptiste Daroussin }
19797295610fSBaptiste Daroussin
198061d06d6bSBaptiste Daroussin void
roff_endparse(struct roff * r)198161d06d6bSBaptiste Daroussin roff_endparse(struct roff *r)
198261d06d6bSBaptiste Daroussin {
198361d06d6bSBaptiste Daroussin if (r->last != NULL)
19847295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_NOEND, r->last->line,
19857295610fSBaptiste Daroussin r->last->col, "%s", roff_name[r->last->tok]);
198661d06d6bSBaptiste Daroussin
198761d06d6bSBaptiste Daroussin if (r->eqn != NULL) {
19887295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_NOEND,
198961d06d6bSBaptiste Daroussin r->eqn->node->line, r->eqn->node->pos, "EQ");
199061d06d6bSBaptiste Daroussin eqn_parse(r->eqn);
199161d06d6bSBaptiste Daroussin r->eqn = NULL;
199261d06d6bSBaptiste Daroussin }
199361d06d6bSBaptiste Daroussin
199461d06d6bSBaptiste Daroussin if (r->tbl != NULL) {
19957295610fSBaptiste Daroussin tbl_end(r->tbl, 1);
199661d06d6bSBaptiste Daroussin r->tbl = NULL;
199761d06d6bSBaptiste Daroussin }
199861d06d6bSBaptiste Daroussin }
199961d06d6bSBaptiste Daroussin
200061d06d6bSBaptiste Daroussin /*
200161d06d6bSBaptiste Daroussin * Parse a roff node's type from the input buffer. This must be in the
200261d06d6bSBaptiste Daroussin * form of ".foo xxx" in the usual way.
200361d06d6bSBaptiste Daroussin */
200461d06d6bSBaptiste Daroussin static enum roff_tok
roff_parse(struct roff * r,char * buf,int * pos,int ln,int ppos)200561d06d6bSBaptiste Daroussin roff_parse(struct roff *r, char *buf, int *pos, int ln, int ppos)
200661d06d6bSBaptiste Daroussin {
200761d06d6bSBaptiste Daroussin char *cp;
200861d06d6bSBaptiste Daroussin const char *mac;
200961d06d6bSBaptiste Daroussin size_t maclen;
201061d06d6bSBaptiste Daroussin int deftype;
201161d06d6bSBaptiste Daroussin enum roff_tok t;
201261d06d6bSBaptiste Daroussin
201361d06d6bSBaptiste Daroussin cp = buf + *pos;
201461d06d6bSBaptiste Daroussin
201561d06d6bSBaptiste Daroussin if ('\0' == *cp || '"' == *cp || '\t' == *cp || ' ' == *cp)
201661d06d6bSBaptiste Daroussin return TOKEN_NONE;
201761d06d6bSBaptiste Daroussin
201861d06d6bSBaptiste Daroussin mac = cp;
201961d06d6bSBaptiste Daroussin maclen = roff_getname(r, &cp, ln, ppos);
202061d06d6bSBaptiste Daroussin
202161d06d6bSBaptiste Daroussin deftype = ROFFDEF_USER | ROFFDEF_REN;
202261d06d6bSBaptiste Daroussin r->current_string = roff_getstrn(r, mac, maclen, &deftype);
202361d06d6bSBaptiste Daroussin switch (deftype) {
202461d06d6bSBaptiste Daroussin case ROFFDEF_USER:
202561d06d6bSBaptiste Daroussin t = ROFF_USERDEF;
202661d06d6bSBaptiste Daroussin break;
202761d06d6bSBaptiste Daroussin case ROFFDEF_REN:
202861d06d6bSBaptiste Daroussin t = ROFF_RENAMED;
202961d06d6bSBaptiste Daroussin break;
203061d06d6bSBaptiste Daroussin default:
203161d06d6bSBaptiste Daroussin t = roffhash_find(r->reqtab, mac, maclen);
203261d06d6bSBaptiste Daroussin break;
203361d06d6bSBaptiste Daroussin }
203461d06d6bSBaptiste Daroussin if (t != TOKEN_NONE)
203561d06d6bSBaptiste Daroussin *pos = cp - buf;
203661d06d6bSBaptiste Daroussin else if (deftype == ROFFDEF_UNDEF) {
203761d06d6bSBaptiste Daroussin /* Using an undefined macro defines it to be empty. */
203861d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, mac, maclen, "", 0, 0);
203961d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, mac, maclen, NULL, 0, 0);
204061d06d6bSBaptiste Daroussin }
204161d06d6bSBaptiste Daroussin return t;
204261d06d6bSBaptiste Daroussin }
204361d06d6bSBaptiste Daroussin
204461d06d6bSBaptiste Daroussin /* --- handling of request blocks ----------------------------------------- */
204561d06d6bSBaptiste Daroussin
2046*6d38604fSBaptiste Daroussin /*
2047*6d38604fSBaptiste Daroussin * Close a macro definition block or an "ignore" block.
2048*6d38604fSBaptiste Daroussin */
20497295610fSBaptiste Daroussin static int
roff_cblock(ROFF_ARGS)205061d06d6bSBaptiste Daroussin roff_cblock(ROFF_ARGS)
205161d06d6bSBaptiste Daroussin {
2052*6d38604fSBaptiste Daroussin int rr;
205361d06d6bSBaptiste Daroussin
205461d06d6bSBaptiste Daroussin if (r->last == NULL) {
20557295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "..");
205661d06d6bSBaptiste Daroussin return ROFF_IGN;
205761d06d6bSBaptiste Daroussin }
205861d06d6bSBaptiste Daroussin
205961d06d6bSBaptiste Daroussin switch (r->last->tok) {
206061d06d6bSBaptiste Daroussin case ROFF_am:
206161d06d6bSBaptiste Daroussin case ROFF_ami:
206261d06d6bSBaptiste Daroussin case ROFF_de:
206361d06d6bSBaptiste Daroussin case ROFF_dei:
206461d06d6bSBaptiste Daroussin case ROFF_ig:
206561d06d6bSBaptiste Daroussin break;
2066*6d38604fSBaptiste Daroussin case ROFF_am1:
2067*6d38604fSBaptiste Daroussin case ROFF_de1:
2068*6d38604fSBaptiste Daroussin /* Remapped in roff_block(). */
2069*6d38604fSBaptiste Daroussin abort();
207061d06d6bSBaptiste Daroussin default:
20717295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "..");
207261d06d6bSBaptiste Daroussin return ROFF_IGN;
207361d06d6bSBaptiste Daroussin }
207461d06d6bSBaptiste Daroussin
2075*6d38604fSBaptiste Daroussin roffnode_pop(r);
2076*6d38604fSBaptiste Daroussin roffnode_cleanscope(r);
2077*6d38604fSBaptiste Daroussin
2078*6d38604fSBaptiste Daroussin /*
2079*6d38604fSBaptiste Daroussin * If a conditional block with braces is still open,
2080*6d38604fSBaptiste Daroussin * check for "\}" block end markers.
2081*6d38604fSBaptiste Daroussin */
2082*6d38604fSBaptiste Daroussin
2083*6d38604fSBaptiste Daroussin if (r->last != NULL && r->last->endspan < 0) {
2084*6d38604fSBaptiste Daroussin rr = 1; /* If arguments follow "\}", warn about them. */
2085*6d38604fSBaptiste Daroussin roff_cond_checkend(r, tok, buf, ln, ppos, pos, &rr);
2086*6d38604fSBaptiste Daroussin }
2087*6d38604fSBaptiste Daroussin
208861d06d6bSBaptiste Daroussin if (buf->buf[pos] != '\0')
20897295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos,
209061d06d6bSBaptiste Daroussin ".. %s", buf->buf + pos);
209161d06d6bSBaptiste Daroussin
209261d06d6bSBaptiste Daroussin return ROFF_IGN;
209361d06d6bSBaptiste Daroussin }
209461d06d6bSBaptiste Daroussin
209545a5aec3SBaptiste Daroussin /*
209645a5aec3SBaptiste Daroussin * Pop all nodes ending at the end of the current input line.
209745a5aec3SBaptiste Daroussin * Return the number of loops ended.
209845a5aec3SBaptiste Daroussin */
20997295610fSBaptiste Daroussin static int
roffnode_cleanscope(struct roff * r)210061d06d6bSBaptiste Daroussin roffnode_cleanscope(struct roff *r)
210161d06d6bSBaptiste Daroussin {
21027295610fSBaptiste Daroussin int inloop;
210361d06d6bSBaptiste Daroussin
21047295610fSBaptiste Daroussin inloop = 0;
2105*6d38604fSBaptiste Daroussin while (r->last != NULL && r->last->endspan > 0) {
210661d06d6bSBaptiste Daroussin if (--r->last->endspan != 0)
210761d06d6bSBaptiste Daroussin break;
21087295610fSBaptiste Daroussin inloop += roffnode_pop(r);
210961d06d6bSBaptiste Daroussin }
21107295610fSBaptiste Daroussin return inloop;
211161d06d6bSBaptiste Daroussin }
211261d06d6bSBaptiste Daroussin
211345a5aec3SBaptiste Daroussin /*
2114*6d38604fSBaptiste Daroussin * Handle the closing "\}" of a conditional block.
211545a5aec3SBaptiste Daroussin * Apart from generating warnings, this only pops nodes.
211645a5aec3SBaptiste Daroussin * Return the number of loops ended.
211745a5aec3SBaptiste Daroussin */
21187295610fSBaptiste Daroussin static int
roff_ccond(struct roff * r,int ln,int ppos)211961d06d6bSBaptiste Daroussin roff_ccond(struct roff *r, int ln, int ppos)
212061d06d6bSBaptiste Daroussin {
212161d06d6bSBaptiste Daroussin if (NULL == r->last) {
21227295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "\\}");
21237295610fSBaptiste Daroussin return 0;
212461d06d6bSBaptiste Daroussin }
212561d06d6bSBaptiste Daroussin
212661d06d6bSBaptiste Daroussin switch (r->last->tok) {
212761d06d6bSBaptiste Daroussin case ROFF_el:
212861d06d6bSBaptiste Daroussin case ROFF_ie:
212961d06d6bSBaptiste Daroussin case ROFF_if:
21307295610fSBaptiste Daroussin case ROFF_while:
213161d06d6bSBaptiste Daroussin break;
213261d06d6bSBaptiste Daroussin default:
21337295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "\\}");
21347295610fSBaptiste Daroussin return 0;
213561d06d6bSBaptiste Daroussin }
213661d06d6bSBaptiste Daroussin
213761d06d6bSBaptiste Daroussin if (r->last->endspan > -1) {
21387295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "\\}");
21397295610fSBaptiste Daroussin return 0;
214061d06d6bSBaptiste Daroussin }
214161d06d6bSBaptiste Daroussin
21427295610fSBaptiste Daroussin return roffnode_pop(r) + roffnode_cleanscope(r);
214361d06d6bSBaptiste Daroussin }
214461d06d6bSBaptiste Daroussin
21457295610fSBaptiste Daroussin static int
roff_block(ROFF_ARGS)214661d06d6bSBaptiste Daroussin roff_block(ROFF_ARGS)
214761d06d6bSBaptiste Daroussin {
214861d06d6bSBaptiste Daroussin const char *name, *value;
214961d06d6bSBaptiste Daroussin char *call, *cp, *iname, *rname;
215061d06d6bSBaptiste Daroussin size_t csz, namesz, rsz;
215161d06d6bSBaptiste Daroussin int deftype;
215261d06d6bSBaptiste Daroussin
215361d06d6bSBaptiste Daroussin /* Ignore groff compatibility mode for now. */
215461d06d6bSBaptiste Daroussin
215561d06d6bSBaptiste Daroussin if (tok == ROFF_de1)
215661d06d6bSBaptiste Daroussin tok = ROFF_de;
215761d06d6bSBaptiste Daroussin else if (tok == ROFF_dei1)
215861d06d6bSBaptiste Daroussin tok = ROFF_dei;
215961d06d6bSBaptiste Daroussin else if (tok == ROFF_am1)
216061d06d6bSBaptiste Daroussin tok = ROFF_am;
216161d06d6bSBaptiste Daroussin else if (tok == ROFF_ami1)
216261d06d6bSBaptiste Daroussin tok = ROFF_ami;
216361d06d6bSBaptiste Daroussin
216461d06d6bSBaptiste Daroussin /* Parse the macro name argument. */
216561d06d6bSBaptiste Daroussin
216661d06d6bSBaptiste Daroussin cp = buf->buf + pos;
216761d06d6bSBaptiste Daroussin if (tok == ROFF_ig) {
216861d06d6bSBaptiste Daroussin iname = NULL;
216961d06d6bSBaptiste Daroussin namesz = 0;
217061d06d6bSBaptiste Daroussin } else {
217161d06d6bSBaptiste Daroussin iname = cp;
217261d06d6bSBaptiste Daroussin namesz = roff_getname(r, &cp, ln, ppos);
217361d06d6bSBaptiste Daroussin iname[namesz] = '\0';
217461d06d6bSBaptiste Daroussin }
217561d06d6bSBaptiste Daroussin
217661d06d6bSBaptiste Daroussin /* Resolve the macro name argument if it is indirect. */
217761d06d6bSBaptiste Daroussin
217861d06d6bSBaptiste Daroussin if (namesz && (tok == ROFF_dei || tok == ROFF_ami)) {
217961d06d6bSBaptiste Daroussin deftype = ROFFDEF_USER;
218061d06d6bSBaptiste Daroussin name = roff_getstrn(r, iname, namesz, &deftype);
218161d06d6bSBaptiste Daroussin if (name == NULL) {
21827295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_STR_UNDEF,
21837295610fSBaptiste Daroussin ln, (int)(iname - buf->buf),
218461d06d6bSBaptiste Daroussin "%.*s", (int)namesz, iname);
218561d06d6bSBaptiste Daroussin namesz = 0;
218661d06d6bSBaptiste Daroussin } else
218761d06d6bSBaptiste Daroussin namesz = strlen(name);
218861d06d6bSBaptiste Daroussin } else
218961d06d6bSBaptiste Daroussin name = iname;
219061d06d6bSBaptiste Daroussin
219161d06d6bSBaptiste Daroussin if (namesz == 0 && tok != ROFF_ig) {
21927295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_REQ_EMPTY,
21937295610fSBaptiste Daroussin ln, ppos, "%s", roff_name[tok]);
219461d06d6bSBaptiste Daroussin return ROFF_IGN;
219561d06d6bSBaptiste Daroussin }
219661d06d6bSBaptiste Daroussin
219761d06d6bSBaptiste Daroussin roffnode_push(r, tok, name, ln, ppos);
219861d06d6bSBaptiste Daroussin
219961d06d6bSBaptiste Daroussin /*
220061d06d6bSBaptiste Daroussin * At the beginning of a `de' macro, clear the existing string
220161d06d6bSBaptiste Daroussin * with the same name, if there is one. New content will be
220261d06d6bSBaptiste Daroussin * appended from roff_block_text() in multiline mode.
220361d06d6bSBaptiste Daroussin */
220461d06d6bSBaptiste Daroussin
220561d06d6bSBaptiste Daroussin if (tok == ROFF_de || tok == ROFF_dei) {
220661d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, name, namesz, "", 0, 0);
220761d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0);
220861d06d6bSBaptiste Daroussin } else if (tok == ROFF_am || tok == ROFF_ami) {
220961d06d6bSBaptiste Daroussin deftype = ROFFDEF_ANY;
221061d06d6bSBaptiste Daroussin value = roff_getstrn(r, iname, namesz, &deftype);
221161d06d6bSBaptiste Daroussin switch (deftype) { /* Before appending, ... */
221261d06d6bSBaptiste Daroussin case ROFFDEF_PRE: /* copy predefined to user-defined. */
221361d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, name, namesz,
221461d06d6bSBaptiste Daroussin value, strlen(value), 0);
221561d06d6bSBaptiste Daroussin break;
221661d06d6bSBaptiste Daroussin case ROFFDEF_REN: /* call original standard macro. */
221761d06d6bSBaptiste Daroussin csz = mandoc_asprintf(&call, ".%.*s \\$* \\\"\n",
221861d06d6bSBaptiste Daroussin (int)strlen(value), value);
221961d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, name, namesz, call, csz, 0);
222061d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0);
222161d06d6bSBaptiste Daroussin free(call);
222261d06d6bSBaptiste Daroussin break;
222361d06d6bSBaptiste Daroussin case ROFFDEF_STD: /* rename and call standard macro. */
222461d06d6bSBaptiste Daroussin rsz = mandoc_asprintf(&rname, "__%s_renamed", name);
222561d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, rname, rsz, name, namesz, 0);
222661d06d6bSBaptiste Daroussin csz = mandoc_asprintf(&call, ".%.*s \\$* \\\"\n",
222761d06d6bSBaptiste Daroussin (int)rsz, rname);
222861d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, name, namesz, call, csz, 0);
222961d06d6bSBaptiste Daroussin free(call);
223061d06d6bSBaptiste Daroussin free(rname);
223161d06d6bSBaptiste Daroussin break;
223261d06d6bSBaptiste Daroussin default:
223361d06d6bSBaptiste Daroussin break;
223461d06d6bSBaptiste Daroussin }
223561d06d6bSBaptiste Daroussin }
223661d06d6bSBaptiste Daroussin
223761d06d6bSBaptiste Daroussin if (*cp == '\0')
223861d06d6bSBaptiste Daroussin return ROFF_IGN;
223961d06d6bSBaptiste Daroussin
224061d06d6bSBaptiste Daroussin /* Get the custom end marker. */
224161d06d6bSBaptiste Daroussin
224261d06d6bSBaptiste Daroussin iname = cp;
224361d06d6bSBaptiste Daroussin namesz = roff_getname(r, &cp, ln, ppos);
224461d06d6bSBaptiste Daroussin
224561d06d6bSBaptiste Daroussin /* Resolve the end marker if it is indirect. */
224661d06d6bSBaptiste Daroussin
224761d06d6bSBaptiste Daroussin if (namesz && (tok == ROFF_dei || tok == ROFF_ami)) {
224861d06d6bSBaptiste Daroussin deftype = ROFFDEF_USER;
224961d06d6bSBaptiste Daroussin name = roff_getstrn(r, iname, namesz, &deftype);
225061d06d6bSBaptiste Daroussin if (name == NULL) {
22517295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_STR_UNDEF,
22527295610fSBaptiste Daroussin ln, (int)(iname - buf->buf),
225361d06d6bSBaptiste Daroussin "%.*s", (int)namesz, iname);
225461d06d6bSBaptiste Daroussin namesz = 0;
225561d06d6bSBaptiste Daroussin } else
225661d06d6bSBaptiste Daroussin namesz = strlen(name);
225761d06d6bSBaptiste Daroussin } else
225861d06d6bSBaptiste Daroussin name = iname;
225961d06d6bSBaptiste Daroussin
226061d06d6bSBaptiste Daroussin if (namesz)
226161d06d6bSBaptiste Daroussin r->last->end = mandoc_strndup(name, namesz);
226261d06d6bSBaptiste Daroussin
226361d06d6bSBaptiste Daroussin if (*cp != '\0')
22647295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_EXCESS,
226561d06d6bSBaptiste Daroussin ln, pos, ".%s ... %s", roff_name[tok], cp);
226661d06d6bSBaptiste Daroussin
226761d06d6bSBaptiste Daroussin return ROFF_IGN;
226861d06d6bSBaptiste Daroussin }
226961d06d6bSBaptiste Daroussin
22707295610fSBaptiste Daroussin static int
roff_block_sub(ROFF_ARGS)227161d06d6bSBaptiste Daroussin roff_block_sub(ROFF_ARGS)
227261d06d6bSBaptiste Daroussin {
227361d06d6bSBaptiste Daroussin enum roff_tok t;
227461d06d6bSBaptiste Daroussin int i, j;
227561d06d6bSBaptiste Daroussin
227661d06d6bSBaptiste Daroussin /*
227761d06d6bSBaptiste Daroussin * First check whether a custom macro exists at this level. If
227861d06d6bSBaptiste Daroussin * it does, then check against it. This is some of groff's
227961d06d6bSBaptiste Daroussin * stranger behaviours. If we encountered a custom end-scope
228061d06d6bSBaptiste Daroussin * tag and that tag also happens to be a "real" macro, then we
228161d06d6bSBaptiste Daroussin * need to try interpreting it again as a real macro. If it's
228261d06d6bSBaptiste Daroussin * not, then return ignore. Else continue.
228361d06d6bSBaptiste Daroussin */
228461d06d6bSBaptiste Daroussin
228561d06d6bSBaptiste Daroussin if (r->last->end) {
228661d06d6bSBaptiste Daroussin for (i = pos, j = 0; r->last->end[j]; j++, i++)
228761d06d6bSBaptiste Daroussin if (buf->buf[i] != r->last->end[j])
228861d06d6bSBaptiste Daroussin break;
228961d06d6bSBaptiste Daroussin
229061d06d6bSBaptiste Daroussin if (r->last->end[j] == '\0' &&
229161d06d6bSBaptiste Daroussin (buf->buf[i] == '\0' ||
229261d06d6bSBaptiste Daroussin buf->buf[i] == ' ' ||
229361d06d6bSBaptiste Daroussin buf->buf[i] == '\t')) {
229461d06d6bSBaptiste Daroussin roffnode_pop(r);
229561d06d6bSBaptiste Daroussin roffnode_cleanscope(r);
229661d06d6bSBaptiste Daroussin
229761d06d6bSBaptiste Daroussin while (buf->buf[i] == ' ' || buf->buf[i] == '\t')
229861d06d6bSBaptiste Daroussin i++;
229961d06d6bSBaptiste Daroussin
230061d06d6bSBaptiste Daroussin pos = i;
230161d06d6bSBaptiste Daroussin if (roff_parse(r, buf->buf, &pos, ln, ppos) !=
230261d06d6bSBaptiste Daroussin TOKEN_NONE)
230361d06d6bSBaptiste Daroussin return ROFF_RERUN;
230461d06d6bSBaptiste Daroussin return ROFF_IGN;
230561d06d6bSBaptiste Daroussin }
230661d06d6bSBaptiste Daroussin }
230761d06d6bSBaptiste Daroussin
230861d06d6bSBaptiste Daroussin /*
230961d06d6bSBaptiste Daroussin * If we have no custom end-query or lookup failed, then try
231061d06d6bSBaptiste Daroussin * pulling it out of the hashtable.
231161d06d6bSBaptiste Daroussin */
231261d06d6bSBaptiste Daroussin
231361d06d6bSBaptiste Daroussin t = roff_parse(r, buf->buf, &pos, ln, ppos);
231461d06d6bSBaptiste Daroussin
231561d06d6bSBaptiste Daroussin if (t != ROFF_cblock) {
231661d06d6bSBaptiste Daroussin if (tok != ROFF_ig)
231761d06d6bSBaptiste Daroussin roff_setstr(r, r->last->name, buf->buf + ppos, 2);
231861d06d6bSBaptiste Daroussin return ROFF_IGN;
231961d06d6bSBaptiste Daroussin }
232061d06d6bSBaptiste Daroussin
232161d06d6bSBaptiste Daroussin return (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs);
232261d06d6bSBaptiste Daroussin }
232361d06d6bSBaptiste Daroussin
23247295610fSBaptiste Daroussin static int
roff_block_text(ROFF_ARGS)232561d06d6bSBaptiste Daroussin roff_block_text(ROFF_ARGS)
232661d06d6bSBaptiste Daroussin {
232761d06d6bSBaptiste Daroussin
232861d06d6bSBaptiste Daroussin if (tok != ROFF_ig)
232961d06d6bSBaptiste Daroussin roff_setstr(r, r->last->name, buf->buf + pos, 2);
233061d06d6bSBaptiste Daroussin
233161d06d6bSBaptiste Daroussin return ROFF_IGN;
233261d06d6bSBaptiste Daroussin }
233361d06d6bSBaptiste Daroussin
2334*6d38604fSBaptiste Daroussin /*
2335*6d38604fSBaptiste Daroussin * Check for a closing "\}" and handle it.
2336*6d38604fSBaptiste Daroussin * In this function, the final "int *offs" argument is used for
2337*6d38604fSBaptiste Daroussin * different purposes than elsewhere:
2338*6d38604fSBaptiste Daroussin * Input: *offs == 0: caller wants to discard arguments following \}
2339*6d38604fSBaptiste Daroussin * *offs == 1: caller wants to preserve text following \}
2340*6d38604fSBaptiste Daroussin * Output: *offs = 0: tell caller to discard input line
2341*6d38604fSBaptiste Daroussin * *offs = 1: tell caller to use input line
2342*6d38604fSBaptiste Daroussin */
23437295610fSBaptiste Daroussin static int
roff_cond_checkend(ROFF_ARGS)2344*6d38604fSBaptiste Daroussin roff_cond_checkend(ROFF_ARGS)
234561d06d6bSBaptiste Daroussin {
234661d06d6bSBaptiste Daroussin char *ep;
23477295610fSBaptiste Daroussin int endloop, irc, rr;
234861d06d6bSBaptiste Daroussin
23497295610fSBaptiste Daroussin irc = ROFF_IGN;
235061d06d6bSBaptiste Daroussin rr = r->last->rule;
23517295610fSBaptiste Daroussin endloop = tok != ROFF_while ? ROFF_IGN :
23527295610fSBaptiste Daroussin rr ? ROFF_LOOPCONT : ROFF_LOOPEXIT;
23537295610fSBaptiste Daroussin if (roffnode_cleanscope(r))
23547295610fSBaptiste Daroussin irc |= endloop;
235561d06d6bSBaptiste Daroussin
235661d06d6bSBaptiste Daroussin /*
2357*6d38604fSBaptiste Daroussin * If "\}" occurs on a macro line without a preceding macro or
2358*6d38604fSBaptiste Daroussin * a text line contains nothing else, drop the line completely.
235961d06d6bSBaptiste Daroussin */
236061d06d6bSBaptiste Daroussin
236161d06d6bSBaptiste Daroussin ep = buf->buf + pos;
2362*6d38604fSBaptiste Daroussin if (ep[0] == '\\' && ep[1] == '}' && (ep[2] == '\0' || *offs == 0))
236361d06d6bSBaptiste Daroussin rr = 0;
236461d06d6bSBaptiste Daroussin
23657295610fSBaptiste Daroussin /*
2366*6d38604fSBaptiste Daroussin * The closing delimiter "\}" rewinds the conditional scope
23677295610fSBaptiste Daroussin * but is otherwise ignored when interpreting the line.
23687295610fSBaptiste Daroussin */
236961d06d6bSBaptiste Daroussin
237061d06d6bSBaptiste Daroussin while ((ep = strchr(ep, '\\')) != NULL) {
237161d06d6bSBaptiste Daroussin switch (ep[1]) {
237261d06d6bSBaptiste Daroussin case '}':
2373*6d38604fSBaptiste Daroussin if (ep[2] == '\0')
2374*6d38604fSBaptiste Daroussin ep[0] = '\0';
2375*6d38604fSBaptiste Daroussin else if (rr)
2376*6d38604fSBaptiste Daroussin ep[1] = '&';
2377*6d38604fSBaptiste Daroussin else
237861d06d6bSBaptiste Daroussin memmove(ep, ep + 2, strlen(ep + 2) + 1);
23797295610fSBaptiste Daroussin if (roff_ccond(r, ln, ep - buf->buf))
23807295610fSBaptiste Daroussin irc |= endloop;
238161d06d6bSBaptiste Daroussin break;
238261d06d6bSBaptiste Daroussin case '\0':
238361d06d6bSBaptiste Daroussin ++ep;
238461d06d6bSBaptiste Daroussin break;
238561d06d6bSBaptiste Daroussin default:
238661d06d6bSBaptiste Daroussin ep += 2;
238761d06d6bSBaptiste Daroussin break;
238861d06d6bSBaptiste Daroussin }
238961d06d6bSBaptiste Daroussin }
2390*6d38604fSBaptiste Daroussin *offs = rr;
2391*6d38604fSBaptiste Daroussin return irc;
2392*6d38604fSBaptiste Daroussin }
2393*6d38604fSBaptiste Daroussin
2394*6d38604fSBaptiste Daroussin /*
2395*6d38604fSBaptiste Daroussin * Parse and process a request or macro line in conditional scope.
2396*6d38604fSBaptiste Daroussin */
2397*6d38604fSBaptiste Daroussin static int
roff_cond_sub(ROFF_ARGS)2398*6d38604fSBaptiste Daroussin roff_cond_sub(ROFF_ARGS)
2399*6d38604fSBaptiste Daroussin {
2400*6d38604fSBaptiste Daroussin struct roffnode *bl;
2401*6d38604fSBaptiste Daroussin int irc, rr;
2402*6d38604fSBaptiste Daroussin enum roff_tok t;
2403*6d38604fSBaptiste Daroussin
2404*6d38604fSBaptiste Daroussin rr = 0; /* If arguments follow "\}", skip them. */
2405*6d38604fSBaptiste Daroussin irc = roff_cond_checkend(r, tok, buf, ln, ppos, pos, &rr);
2406*6d38604fSBaptiste Daroussin t = roff_parse(r, buf->buf, &pos, ln, ppos);
2407*6d38604fSBaptiste Daroussin
2408*6d38604fSBaptiste Daroussin /* For now, let high level macros abort .ce mode. */
2409*6d38604fSBaptiste Daroussin
2410*6d38604fSBaptiste Daroussin if (roffce_node != NULL &&
2411*6d38604fSBaptiste Daroussin (t == TOKEN_NONE || t == ROFF_Dd || t == ROFF_EQ ||
2412*6d38604fSBaptiste Daroussin t == ROFF_TH || t == ROFF_TS)) {
2413*6d38604fSBaptiste Daroussin r->man->last = roffce_node;
2414*6d38604fSBaptiste Daroussin r->man->next = ROFF_NEXT_SIBLING;
2415*6d38604fSBaptiste Daroussin roffce_lines = 0;
2416*6d38604fSBaptiste Daroussin roffce_node = NULL;
2417*6d38604fSBaptiste Daroussin }
241861d06d6bSBaptiste Daroussin
241961d06d6bSBaptiste Daroussin /*
242061d06d6bSBaptiste Daroussin * Fully handle known macros when they are structurally
242161d06d6bSBaptiste Daroussin * required or when the conditional evaluated to true.
242261d06d6bSBaptiste Daroussin */
242361d06d6bSBaptiste Daroussin
242445a5aec3SBaptiste Daroussin if (t == ROFF_break) {
242545a5aec3SBaptiste Daroussin if (irc & ROFF_LOOPMASK)
242645a5aec3SBaptiste Daroussin irc = ROFF_IGN | ROFF_LOOPEXIT;
242745a5aec3SBaptiste Daroussin else if (rr) {
242845a5aec3SBaptiste Daroussin for (bl = r->last; bl != NULL; bl = bl->parent) {
242945a5aec3SBaptiste Daroussin bl->rule = 0;
243045a5aec3SBaptiste Daroussin if (bl->tok == ROFF_while)
243145a5aec3SBaptiste Daroussin break;
243245a5aec3SBaptiste Daroussin }
243345a5aec3SBaptiste Daroussin }
243445a5aec3SBaptiste Daroussin } else if (t != TOKEN_NONE &&
243545a5aec3SBaptiste Daroussin (rr || roffs[t].flags & ROFFMAC_STRUCT))
243645a5aec3SBaptiste Daroussin irc |= (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs);
243745a5aec3SBaptiste Daroussin else
243845a5aec3SBaptiste Daroussin irc |= rr ? ROFF_CONT : ROFF_IGN;
24397295610fSBaptiste Daroussin return irc;
244061d06d6bSBaptiste Daroussin }
244161d06d6bSBaptiste Daroussin
2442*6d38604fSBaptiste Daroussin /*
2443*6d38604fSBaptiste Daroussin * Parse and process a text line in conditional scope.
2444*6d38604fSBaptiste Daroussin */
24457295610fSBaptiste Daroussin static int
roff_cond_text(ROFF_ARGS)244661d06d6bSBaptiste Daroussin roff_cond_text(ROFF_ARGS)
244761d06d6bSBaptiste Daroussin {
2448*6d38604fSBaptiste Daroussin int irc, rr;
244961d06d6bSBaptiste Daroussin
2450*6d38604fSBaptiste Daroussin rr = 1; /* If arguments follow "\}", preserve them. */
2451*6d38604fSBaptiste Daroussin irc = roff_cond_checkend(r, tok, buf, ln, ppos, pos, &rr);
24527295610fSBaptiste Daroussin if (rr)
24537295610fSBaptiste Daroussin irc |= ROFF_CONT;
24547295610fSBaptiste Daroussin return irc;
245561d06d6bSBaptiste Daroussin }
245661d06d6bSBaptiste Daroussin
245761d06d6bSBaptiste Daroussin /* --- handling of numeric and conditional expressions -------------------- */
245861d06d6bSBaptiste Daroussin
245961d06d6bSBaptiste Daroussin /*
246061d06d6bSBaptiste Daroussin * Parse a single signed integer number. Stop at the first non-digit.
246161d06d6bSBaptiste Daroussin * If there is at least one digit, return success and advance the
246261d06d6bSBaptiste Daroussin * parse point, else return failure and let the parse point unchanged.
246361d06d6bSBaptiste Daroussin * Ignore overflows, treat them just like the C language.
246461d06d6bSBaptiste Daroussin */
246561d06d6bSBaptiste Daroussin static int
roff_getnum(const char * v,int * pos,int * res,int flags)246661d06d6bSBaptiste Daroussin roff_getnum(const char *v, int *pos, int *res, int flags)
246761d06d6bSBaptiste Daroussin {
246861d06d6bSBaptiste Daroussin int myres, scaled, n, p;
246961d06d6bSBaptiste Daroussin
247061d06d6bSBaptiste Daroussin if (NULL == res)
247161d06d6bSBaptiste Daroussin res = &myres;
247261d06d6bSBaptiste Daroussin
247361d06d6bSBaptiste Daroussin p = *pos;
247461d06d6bSBaptiste Daroussin n = v[p] == '-';
247561d06d6bSBaptiste Daroussin if (n || v[p] == '+')
247661d06d6bSBaptiste Daroussin p++;
247761d06d6bSBaptiste Daroussin
247861d06d6bSBaptiste Daroussin if (flags & ROFFNUM_WHITE)
247961d06d6bSBaptiste Daroussin while (isspace((unsigned char)v[p]))
248061d06d6bSBaptiste Daroussin p++;
248161d06d6bSBaptiste Daroussin
248261d06d6bSBaptiste Daroussin for (*res = 0; isdigit((unsigned char)v[p]); p++)
248361d06d6bSBaptiste Daroussin *res = 10 * *res + v[p] - '0';
248461d06d6bSBaptiste Daroussin if (p == *pos + n)
248561d06d6bSBaptiste Daroussin return 0;
248661d06d6bSBaptiste Daroussin
248761d06d6bSBaptiste Daroussin if (n)
248861d06d6bSBaptiste Daroussin *res = -*res;
248961d06d6bSBaptiste Daroussin
249061d06d6bSBaptiste Daroussin /* Each number may be followed by one optional scaling unit. */
249161d06d6bSBaptiste Daroussin
249261d06d6bSBaptiste Daroussin switch (v[p]) {
249361d06d6bSBaptiste Daroussin case 'f':
249461d06d6bSBaptiste Daroussin scaled = *res * 65536;
249561d06d6bSBaptiste Daroussin break;
249661d06d6bSBaptiste Daroussin case 'i':
249761d06d6bSBaptiste Daroussin scaled = *res * 240;
249861d06d6bSBaptiste Daroussin break;
249961d06d6bSBaptiste Daroussin case 'c':
250061d06d6bSBaptiste Daroussin scaled = *res * 240 / 2.54;
250161d06d6bSBaptiste Daroussin break;
250261d06d6bSBaptiste Daroussin case 'v':
250361d06d6bSBaptiste Daroussin case 'P':
250461d06d6bSBaptiste Daroussin scaled = *res * 40;
250561d06d6bSBaptiste Daroussin break;
250661d06d6bSBaptiste Daroussin case 'm':
250761d06d6bSBaptiste Daroussin case 'n':
250861d06d6bSBaptiste Daroussin scaled = *res * 24;
250961d06d6bSBaptiste Daroussin break;
251061d06d6bSBaptiste Daroussin case 'p':
251161d06d6bSBaptiste Daroussin scaled = *res * 10 / 3;
251261d06d6bSBaptiste Daroussin break;
251361d06d6bSBaptiste Daroussin case 'u':
251461d06d6bSBaptiste Daroussin scaled = *res;
251561d06d6bSBaptiste Daroussin break;
251661d06d6bSBaptiste Daroussin case 'M':
251761d06d6bSBaptiste Daroussin scaled = *res * 6 / 25;
251861d06d6bSBaptiste Daroussin break;
251961d06d6bSBaptiste Daroussin default:
252061d06d6bSBaptiste Daroussin scaled = *res;
252161d06d6bSBaptiste Daroussin p--;
252261d06d6bSBaptiste Daroussin break;
252361d06d6bSBaptiste Daroussin }
252461d06d6bSBaptiste Daroussin if (flags & ROFFNUM_SCALE)
252561d06d6bSBaptiste Daroussin *res = scaled;
252661d06d6bSBaptiste Daroussin
252761d06d6bSBaptiste Daroussin *pos = p + 1;
252861d06d6bSBaptiste Daroussin return 1;
252961d06d6bSBaptiste Daroussin }
253061d06d6bSBaptiste Daroussin
253161d06d6bSBaptiste Daroussin /*
253261d06d6bSBaptiste Daroussin * Evaluate a string comparison condition.
253361d06d6bSBaptiste Daroussin * The first character is the delimiter.
253461d06d6bSBaptiste Daroussin * Succeed if the string up to its second occurrence
253561d06d6bSBaptiste Daroussin * matches the string up to its third occurence.
253661d06d6bSBaptiste Daroussin * Advance the cursor after the third occurrence
253761d06d6bSBaptiste Daroussin * or lacking that, to the end of the line.
253861d06d6bSBaptiste Daroussin */
253961d06d6bSBaptiste Daroussin static int
roff_evalstrcond(const char * v,int * pos)254061d06d6bSBaptiste Daroussin roff_evalstrcond(const char *v, int *pos)
254161d06d6bSBaptiste Daroussin {
254261d06d6bSBaptiste Daroussin const char *s1, *s2, *s3;
254361d06d6bSBaptiste Daroussin int match;
254461d06d6bSBaptiste Daroussin
254561d06d6bSBaptiste Daroussin match = 0;
254661d06d6bSBaptiste Daroussin s1 = v + *pos; /* initial delimiter */
254761d06d6bSBaptiste Daroussin s2 = s1 + 1; /* for scanning the first string */
254861d06d6bSBaptiste Daroussin s3 = strchr(s2, *s1); /* for scanning the second string */
254961d06d6bSBaptiste Daroussin
255061d06d6bSBaptiste Daroussin if (NULL == s3) /* found no middle delimiter */
255161d06d6bSBaptiste Daroussin goto out;
255261d06d6bSBaptiste Daroussin
255361d06d6bSBaptiste Daroussin while ('\0' != *++s3) {
255461d06d6bSBaptiste Daroussin if (*s2 != *s3) { /* mismatch */
255561d06d6bSBaptiste Daroussin s3 = strchr(s3, *s1);
255661d06d6bSBaptiste Daroussin break;
255761d06d6bSBaptiste Daroussin }
255861d06d6bSBaptiste Daroussin if (*s3 == *s1) { /* found the final delimiter */
255961d06d6bSBaptiste Daroussin match = 1;
256061d06d6bSBaptiste Daroussin break;
256161d06d6bSBaptiste Daroussin }
256261d06d6bSBaptiste Daroussin s2++;
256361d06d6bSBaptiste Daroussin }
256461d06d6bSBaptiste Daroussin
256561d06d6bSBaptiste Daroussin out:
256661d06d6bSBaptiste Daroussin if (NULL == s3)
256761d06d6bSBaptiste Daroussin s3 = strchr(s2, '\0');
256861d06d6bSBaptiste Daroussin else if (*s3 != '\0')
256961d06d6bSBaptiste Daroussin s3++;
257061d06d6bSBaptiste Daroussin *pos = s3 - v;
257161d06d6bSBaptiste Daroussin return match;
257261d06d6bSBaptiste Daroussin }
257361d06d6bSBaptiste Daroussin
257461d06d6bSBaptiste Daroussin /*
257561d06d6bSBaptiste Daroussin * Evaluate an optionally negated single character, numerical,
257661d06d6bSBaptiste Daroussin * or string condition.
257761d06d6bSBaptiste Daroussin */
257861d06d6bSBaptiste Daroussin static int
roff_evalcond(struct roff * r,int ln,char * v,int * pos)257961d06d6bSBaptiste Daroussin roff_evalcond(struct roff *r, int ln, char *v, int *pos)
258061d06d6bSBaptiste Daroussin {
25817295610fSBaptiste Daroussin const char *start, *end;
258261d06d6bSBaptiste Daroussin char *cp, *name;
258361d06d6bSBaptiste Daroussin size_t sz;
25847295610fSBaptiste Daroussin int deftype, len, number, savepos, istrue, wanttrue;
258561d06d6bSBaptiste Daroussin
258661d06d6bSBaptiste Daroussin if ('!' == v[*pos]) {
258761d06d6bSBaptiste Daroussin wanttrue = 0;
258861d06d6bSBaptiste Daroussin (*pos)++;
258961d06d6bSBaptiste Daroussin } else
259061d06d6bSBaptiste Daroussin wanttrue = 1;
259161d06d6bSBaptiste Daroussin
259261d06d6bSBaptiste Daroussin switch (v[*pos]) {
259361d06d6bSBaptiste Daroussin case '\0':
259461d06d6bSBaptiste Daroussin return 0;
259561d06d6bSBaptiste Daroussin case 'n':
259661d06d6bSBaptiste Daroussin case 'o':
259761d06d6bSBaptiste Daroussin (*pos)++;
259861d06d6bSBaptiste Daroussin return wanttrue;
259961d06d6bSBaptiste Daroussin case 'e':
260061d06d6bSBaptiste Daroussin case 't':
260161d06d6bSBaptiste Daroussin case 'v':
260261d06d6bSBaptiste Daroussin (*pos)++;
260361d06d6bSBaptiste Daroussin return !wanttrue;
26047295610fSBaptiste Daroussin case 'c':
26057295610fSBaptiste Daroussin do {
26067295610fSBaptiste Daroussin (*pos)++;
26077295610fSBaptiste Daroussin } while (v[*pos] == ' ');
26087295610fSBaptiste Daroussin
26097295610fSBaptiste Daroussin /*
26107295610fSBaptiste Daroussin * Quirk for groff compatibility:
26117295610fSBaptiste Daroussin * The horizontal tab is neither available nor unavailable.
26127295610fSBaptiste Daroussin */
26137295610fSBaptiste Daroussin
26147295610fSBaptiste Daroussin if (v[*pos] == '\t') {
26157295610fSBaptiste Daroussin (*pos)++;
26167295610fSBaptiste Daroussin return 0;
26177295610fSBaptiste Daroussin }
26187295610fSBaptiste Daroussin
26197295610fSBaptiste Daroussin /* Printable ASCII characters are available. */
26207295610fSBaptiste Daroussin
26217295610fSBaptiste Daroussin if (v[*pos] != '\\') {
26227295610fSBaptiste Daroussin (*pos)++;
26237295610fSBaptiste Daroussin return wanttrue;
26247295610fSBaptiste Daroussin }
26257295610fSBaptiste Daroussin
26267295610fSBaptiste Daroussin end = v + ++*pos;
26277295610fSBaptiste Daroussin switch (mandoc_escape(&end, &start, &len)) {
26287295610fSBaptiste Daroussin case ESCAPE_SPECIAL:
26297295610fSBaptiste Daroussin istrue = mchars_spec2cp(start, len) != -1;
26307295610fSBaptiste Daroussin break;
26317295610fSBaptiste Daroussin case ESCAPE_UNICODE:
26327295610fSBaptiste Daroussin istrue = 1;
26337295610fSBaptiste Daroussin break;
26347295610fSBaptiste Daroussin case ESCAPE_NUMBERED:
26357295610fSBaptiste Daroussin istrue = mchars_num2char(start, len) != -1;
26367295610fSBaptiste Daroussin break;
26377295610fSBaptiste Daroussin default:
26387295610fSBaptiste Daroussin istrue = !wanttrue;
26397295610fSBaptiste Daroussin break;
26407295610fSBaptiste Daroussin }
26417295610fSBaptiste Daroussin *pos = end - v;
26427295610fSBaptiste Daroussin return istrue == wanttrue;
264361d06d6bSBaptiste Daroussin case 'd':
264461d06d6bSBaptiste Daroussin case 'r':
264561d06d6bSBaptiste Daroussin cp = v + *pos + 1;
264661d06d6bSBaptiste Daroussin while (*cp == ' ')
264761d06d6bSBaptiste Daroussin cp++;
264861d06d6bSBaptiste Daroussin name = cp;
264961d06d6bSBaptiste Daroussin sz = roff_getname(r, &cp, ln, cp - v);
265061d06d6bSBaptiste Daroussin if (sz == 0)
265161d06d6bSBaptiste Daroussin istrue = 0;
265261d06d6bSBaptiste Daroussin else if (v[*pos] == 'r')
265361d06d6bSBaptiste Daroussin istrue = roff_hasregn(r, name, sz);
265461d06d6bSBaptiste Daroussin else {
265561d06d6bSBaptiste Daroussin deftype = ROFFDEF_ANY;
265661d06d6bSBaptiste Daroussin roff_getstrn(r, name, sz, &deftype);
265761d06d6bSBaptiste Daroussin istrue = !!deftype;
265861d06d6bSBaptiste Daroussin }
26597295610fSBaptiste Daroussin *pos = (name + sz) - v;
266061d06d6bSBaptiste Daroussin return istrue == wanttrue;
266161d06d6bSBaptiste Daroussin default:
266261d06d6bSBaptiste Daroussin break;
266361d06d6bSBaptiste Daroussin }
266461d06d6bSBaptiste Daroussin
266561d06d6bSBaptiste Daroussin savepos = *pos;
266661d06d6bSBaptiste Daroussin if (roff_evalnum(r, ln, v, pos, &number, ROFFNUM_SCALE))
266761d06d6bSBaptiste Daroussin return (number > 0) == wanttrue;
266861d06d6bSBaptiste Daroussin else if (*pos == savepos)
266961d06d6bSBaptiste Daroussin return roff_evalstrcond(v, pos) == wanttrue;
267061d06d6bSBaptiste Daroussin else
267161d06d6bSBaptiste Daroussin return 0;
267261d06d6bSBaptiste Daroussin }
267361d06d6bSBaptiste Daroussin
26747295610fSBaptiste Daroussin static int
roff_line_ignore(ROFF_ARGS)267561d06d6bSBaptiste Daroussin roff_line_ignore(ROFF_ARGS)
267661d06d6bSBaptiste Daroussin {
267761d06d6bSBaptiste Daroussin
267861d06d6bSBaptiste Daroussin return ROFF_IGN;
267961d06d6bSBaptiste Daroussin }
268061d06d6bSBaptiste Daroussin
26817295610fSBaptiste Daroussin static int
roff_insec(ROFF_ARGS)268261d06d6bSBaptiste Daroussin roff_insec(ROFF_ARGS)
268361d06d6bSBaptiste Daroussin {
268461d06d6bSBaptiste Daroussin
26857295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_REQ_INSEC, ln, ppos, "%s", roff_name[tok]);
268661d06d6bSBaptiste Daroussin return ROFF_IGN;
268761d06d6bSBaptiste Daroussin }
268861d06d6bSBaptiste Daroussin
26897295610fSBaptiste Daroussin static int
roff_unsupp(ROFF_ARGS)269061d06d6bSBaptiste Daroussin roff_unsupp(ROFF_ARGS)
269161d06d6bSBaptiste Daroussin {
269261d06d6bSBaptiste Daroussin
26937295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_REQ_UNSUPP, ln, ppos, "%s", roff_name[tok]);
269461d06d6bSBaptiste Daroussin return ROFF_IGN;
269561d06d6bSBaptiste Daroussin }
269661d06d6bSBaptiste Daroussin
26977295610fSBaptiste Daroussin static int
roff_cond(ROFF_ARGS)269861d06d6bSBaptiste Daroussin roff_cond(ROFF_ARGS)
269961d06d6bSBaptiste Daroussin {
27007295610fSBaptiste Daroussin int irc;
270161d06d6bSBaptiste Daroussin
270261d06d6bSBaptiste Daroussin roffnode_push(r, tok, NULL, ln, ppos);
270361d06d6bSBaptiste Daroussin
270461d06d6bSBaptiste Daroussin /*
270561d06d6bSBaptiste Daroussin * An `.el' has no conditional body: it will consume the value
270661d06d6bSBaptiste Daroussin * of the current rstack entry set in prior `ie' calls or
270761d06d6bSBaptiste Daroussin * defaults to DENY.
270861d06d6bSBaptiste Daroussin *
270961d06d6bSBaptiste Daroussin * If we're not an `el', however, then evaluate the conditional.
271061d06d6bSBaptiste Daroussin */
271161d06d6bSBaptiste Daroussin
271261d06d6bSBaptiste Daroussin r->last->rule = tok == ROFF_el ?
271361d06d6bSBaptiste Daroussin (r->rstackpos < 0 ? 0 : r->rstack[r->rstackpos--]) :
271461d06d6bSBaptiste Daroussin roff_evalcond(r, ln, buf->buf, &pos);
271561d06d6bSBaptiste Daroussin
271661d06d6bSBaptiste Daroussin /*
271761d06d6bSBaptiste Daroussin * An if-else will put the NEGATION of the current evaluated
271861d06d6bSBaptiste Daroussin * conditional into the stack of rules.
271961d06d6bSBaptiste Daroussin */
272061d06d6bSBaptiste Daroussin
272161d06d6bSBaptiste Daroussin if (tok == ROFF_ie) {
272261d06d6bSBaptiste Daroussin if (r->rstackpos + 1 == r->rstacksz) {
272361d06d6bSBaptiste Daroussin r->rstacksz += 16;
272461d06d6bSBaptiste Daroussin r->rstack = mandoc_reallocarray(r->rstack,
272561d06d6bSBaptiste Daroussin r->rstacksz, sizeof(int));
272661d06d6bSBaptiste Daroussin }
272761d06d6bSBaptiste Daroussin r->rstack[++r->rstackpos] = !r->last->rule;
272861d06d6bSBaptiste Daroussin }
272961d06d6bSBaptiste Daroussin
273061d06d6bSBaptiste Daroussin /* If the parent has false as its rule, then so do we. */
273161d06d6bSBaptiste Daroussin
273261d06d6bSBaptiste Daroussin if (r->last->parent && !r->last->parent->rule)
273361d06d6bSBaptiste Daroussin r->last->rule = 0;
273461d06d6bSBaptiste Daroussin
273561d06d6bSBaptiste Daroussin /*
273661d06d6bSBaptiste Daroussin * Determine scope.
273761d06d6bSBaptiste Daroussin * If there is nothing on the line after the conditional,
273861d06d6bSBaptiste Daroussin * not even whitespace, use next-line scope.
27397295610fSBaptiste Daroussin * Except that .while does not support next-line scope.
274061d06d6bSBaptiste Daroussin */
274161d06d6bSBaptiste Daroussin
27427295610fSBaptiste Daroussin if (buf->buf[pos] == '\0' && tok != ROFF_while) {
274361d06d6bSBaptiste Daroussin r->last->endspan = 2;
274461d06d6bSBaptiste Daroussin goto out;
274561d06d6bSBaptiste Daroussin }
274661d06d6bSBaptiste Daroussin
274761d06d6bSBaptiste Daroussin while (buf->buf[pos] == ' ')
274861d06d6bSBaptiste Daroussin pos++;
274961d06d6bSBaptiste Daroussin
275061d06d6bSBaptiste Daroussin /* An opening brace requests multiline scope. */
275161d06d6bSBaptiste Daroussin
275261d06d6bSBaptiste Daroussin if (buf->buf[pos] == '\\' && buf->buf[pos + 1] == '{') {
275361d06d6bSBaptiste Daroussin r->last->endspan = -1;
275461d06d6bSBaptiste Daroussin pos += 2;
275561d06d6bSBaptiste Daroussin while (buf->buf[pos] == ' ')
275661d06d6bSBaptiste Daroussin pos++;
275761d06d6bSBaptiste Daroussin goto out;
275861d06d6bSBaptiste Daroussin }
275961d06d6bSBaptiste Daroussin
276061d06d6bSBaptiste Daroussin /*
276161d06d6bSBaptiste Daroussin * Anything else following the conditional causes
276261d06d6bSBaptiste Daroussin * single-line scope. Warn if the scope contains
276361d06d6bSBaptiste Daroussin * nothing but trailing whitespace.
276461d06d6bSBaptiste Daroussin */
276561d06d6bSBaptiste Daroussin
276661d06d6bSBaptiste Daroussin if (buf->buf[pos] == '\0')
27677295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_COND_EMPTY,
27687295610fSBaptiste Daroussin ln, ppos, "%s", roff_name[tok]);
276961d06d6bSBaptiste Daroussin
277061d06d6bSBaptiste Daroussin r->last->endspan = 1;
277161d06d6bSBaptiste Daroussin
277261d06d6bSBaptiste Daroussin out:
277361d06d6bSBaptiste Daroussin *offs = pos;
27747295610fSBaptiste Daroussin irc = ROFF_RERUN;
27757295610fSBaptiste Daroussin if (tok == ROFF_while)
27767295610fSBaptiste Daroussin irc |= ROFF_WHILE;
27777295610fSBaptiste Daroussin return irc;
277861d06d6bSBaptiste Daroussin }
277961d06d6bSBaptiste Daroussin
27807295610fSBaptiste Daroussin static int
roff_ds(ROFF_ARGS)278161d06d6bSBaptiste Daroussin roff_ds(ROFF_ARGS)
278261d06d6bSBaptiste Daroussin {
278361d06d6bSBaptiste Daroussin char *string;
278461d06d6bSBaptiste Daroussin const char *name;
278561d06d6bSBaptiste Daroussin size_t namesz;
278661d06d6bSBaptiste Daroussin
278761d06d6bSBaptiste Daroussin /* Ignore groff compatibility mode for now. */
278861d06d6bSBaptiste Daroussin
278961d06d6bSBaptiste Daroussin if (tok == ROFF_ds1)
279061d06d6bSBaptiste Daroussin tok = ROFF_ds;
279161d06d6bSBaptiste Daroussin else if (tok == ROFF_as1)
279261d06d6bSBaptiste Daroussin tok = ROFF_as;
279361d06d6bSBaptiste Daroussin
279461d06d6bSBaptiste Daroussin /*
279561d06d6bSBaptiste Daroussin * The first word is the name of the string.
279661d06d6bSBaptiste Daroussin * If it is empty or terminated by an escape sequence,
279761d06d6bSBaptiste Daroussin * abort the `ds' request without defining anything.
279861d06d6bSBaptiste Daroussin */
279961d06d6bSBaptiste Daroussin
280061d06d6bSBaptiste Daroussin name = string = buf->buf + pos;
280161d06d6bSBaptiste Daroussin if (*name == '\0')
280261d06d6bSBaptiste Daroussin return ROFF_IGN;
280361d06d6bSBaptiste Daroussin
280461d06d6bSBaptiste Daroussin namesz = roff_getname(r, &string, ln, pos);
28057295610fSBaptiste Daroussin switch (name[namesz]) {
28067295610fSBaptiste Daroussin case '\\':
280761d06d6bSBaptiste Daroussin return ROFF_IGN;
28087295610fSBaptiste Daroussin case '\t':
28097295610fSBaptiste Daroussin string = buf->buf + pos + namesz;
28107295610fSBaptiste Daroussin break;
28117295610fSBaptiste Daroussin default:
28127295610fSBaptiste Daroussin break;
28137295610fSBaptiste Daroussin }
281461d06d6bSBaptiste Daroussin
281561d06d6bSBaptiste Daroussin /* Read past the initial double-quote, if any. */
281661d06d6bSBaptiste Daroussin if (*string == '"')
281761d06d6bSBaptiste Daroussin string++;
281861d06d6bSBaptiste Daroussin
281961d06d6bSBaptiste Daroussin /* The rest is the value. */
282061d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, name, namesz, string, strlen(string),
282161d06d6bSBaptiste Daroussin ROFF_as == tok);
282261d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0);
282361d06d6bSBaptiste Daroussin return ROFF_IGN;
282461d06d6bSBaptiste Daroussin }
282561d06d6bSBaptiste Daroussin
282661d06d6bSBaptiste Daroussin /*
282761d06d6bSBaptiste Daroussin * Parse a single operator, one or two characters long.
282861d06d6bSBaptiste Daroussin * If the operator is recognized, return success and advance the
282961d06d6bSBaptiste Daroussin * parse point, else return failure and let the parse point unchanged.
283061d06d6bSBaptiste Daroussin */
283161d06d6bSBaptiste Daroussin static int
roff_getop(const char * v,int * pos,char * res)283261d06d6bSBaptiste Daroussin roff_getop(const char *v, int *pos, char *res)
283361d06d6bSBaptiste Daroussin {
283461d06d6bSBaptiste Daroussin
283561d06d6bSBaptiste Daroussin *res = v[*pos];
283661d06d6bSBaptiste Daroussin
283761d06d6bSBaptiste Daroussin switch (*res) {
283861d06d6bSBaptiste Daroussin case '+':
283961d06d6bSBaptiste Daroussin case '-':
284061d06d6bSBaptiste Daroussin case '*':
284161d06d6bSBaptiste Daroussin case '/':
284261d06d6bSBaptiste Daroussin case '%':
284361d06d6bSBaptiste Daroussin case '&':
284461d06d6bSBaptiste Daroussin case ':':
284561d06d6bSBaptiste Daroussin break;
284661d06d6bSBaptiste Daroussin case '<':
284761d06d6bSBaptiste Daroussin switch (v[*pos + 1]) {
284861d06d6bSBaptiste Daroussin case '=':
284961d06d6bSBaptiste Daroussin *res = 'l';
285061d06d6bSBaptiste Daroussin (*pos)++;
285161d06d6bSBaptiste Daroussin break;
285261d06d6bSBaptiste Daroussin case '>':
285361d06d6bSBaptiste Daroussin *res = '!';
285461d06d6bSBaptiste Daroussin (*pos)++;
285561d06d6bSBaptiste Daroussin break;
285661d06d6bSBaptiste Daroussin case '?':
285761d06d6bSBaptiste Daroussin *res = 'i';
285861d06d6bSBaptiste Daroussin (*pos)++;
285961d06d6bSBaptiste Daroussin break;
286061d06d6bSBaptiste Daroussin default:
286161d06d6bSBaptiste Daroussin break;
286261d06d6bSBaptiste Daroussin }
286361d06d6bSBaptiste Daroussin break;
286461d06d6bSBaptiste Daroussin case '>':
286561d06d6bSBaptiste Daroussin switch (v[*pos + 1]) {
286661d06d6bSBaptiste Daroussin case '=':
286761d06d6bSBaptiste Daroussin *res = 'g';
286861d06d6bSBaptiste Daroussin (*pos)++;
286961d06d6bSBaptiste Daroussin break;
287061d06d6bSBaptiste Daroussin case '?':
287161d06d6bSBaptiste Daroussin *res = 'a';
287261d06d6bSBaptiste Daroussin (*pos)++;
287361d06d6bSBaptiste Daroussin break;
287461d06d6bSBaptiste Daroussin default:
287561d06d6bSBaptiste Daroussin break;
287661d06d6bSBaptiste Daroussin }
287761d06d6bSBaptiste Daroussin break;
287861d06d6bSBaptiste Daroussin case '=':
287961d06d6bSBaptiste Daroussin if ('=' == v[*pos + 1])
288061d06d6bSBaptiste Daroussin (*pos)++;
288161d06d6bSBaptiste Daroussin break;
288261d06d6bSBaptiste Daroussin default:
288361d06d6bSBaptiste Daroussin return 0;
288461d06d6bSBaptiste Daroussin }
288561d06d6bSBaptiste Daroussin (*pos)++;
288661d06d6bSBaptiste Daroussin
288761d06d6bSBaptiste Daroussin return *res;
288861d06d6bSBaptiste Daroussin }
288961d06d6bSBaptiste Daroussin
289061d06d6bSBaptiste Daroussin /*
289161d06d6bSBaptiste Daroussin * Evaluate either a parenthesized numeric expression
289261d06d6bSBaptiste Daroussin * or a single signed integer number.
289361d06d6bSBaptiste Daroussin */
289461d06d6bSBaptiste Daroussin static int
roff_evalpar(struct roff * r,int ln,const char * v,int * pos,int * res,int flags)289561d06d6bSBaptiste Daroussin roff_evalpar(struct roff *r, int ln,
289661d06d6bSBaptiste Daroussin const char *v, int *pos, int *res, int flags)
289761d06d6bSBaptiste Daroussin {
289861d06d6bSBaptiste Daroussin
289961d06d6bSBaptiste Daroussin if ('(' != v[*pos])
290061d06d6bSBaptiste Daroussin return roff_getnum(v, pos, res, flags);
290161d06d6bSBaptiste Daroussin
290261d06d6bSBaptiste Daroussin (*pos)++;
290361d06d6bSBaptiste Daroussin if ( ! roff_evalnum(r, ln, v, pos, res, flags | ROFFNUM_WHITE))
290461d06d6bSBaptiste Daroussin return 0;
290561d06d6bSBaptiste Daroussin
290661d06d6bSBaptiste Daroussin /*
290761d06d6bSBaptiste Daroussin * Omission of the closing parenthesis
290861d06d6bSBaptiste Daroussin * is an error in validation mode,
290961d06d6bSBaptiste Daroussin * but ignored in evaluation mode.
291061d06d6bSBaptiste Daroussin */
291161d06d6bSBaptiste Daroussin
291261d06d6bSBaptiste Daroussin if (')' == v[*pos])
291361d06d6bSBaptiste Daroussin (*pos)++;
291461d06d6bSBaptiste Daroussin else if (NULL == res)
291561d06d6bSBaptiste Daroussin return 0;
291661d06d6bSBaptiste Daroussin
291761d06d6bSBaptiste Daroussin return 1;
291861d06d6bSBaptiste Daroussin }
291961d06d6bSBaptiste Daroussin
292061d06d6bSBaptiste Daroussin /*
292161d06d6bSBaptiste Daroussin * Evaluate a complete numeric expression.
292261d06d6bSBaptiste Daroussin * Proceed left to right, there is no concept of precedence.
292361d06d6bSBaptiste Daroussin */
292461d06d6bSBaptiste Daroussin static int
roff_evalnum(struct roff * r,int ln,const char * v,int * pos,int * res,int flags)292561d06d6bSBaptiste Daroussin roff_evalnum(struct roff *r, int ln, const char *v,
292661d06d6bSBaptiste Daroussin int *pos, int *res, int flags)
292761d06d6bSBaptiste Daroussin {
292861d06d6bSBaptiste Daroussin int mypos, operand2;
292961d06d6bSBaptiste Daroussin char operator;
293061d06d6bSBaptiste Daroussin
293161d06d6bSBaptiste Daroussin if (NULL == pos) {
293261d06d6bSBaptiste Daroussin mypos = 0;
293361d06d6bSBaptiste Daroussin pos = &mypos;
293461d06d6bSBaptiste Daroussin }
293561d06d6bSBaptiste Daroussin
293661d06d6bSBaptiste Daroussin if (flags & ROFFNUM_WHITE)
293761d06d6bSBaptiste Daroussin while (isspace((unsigned char)v[*pos]))
293861d06d6bSBaptiste Daroussin (*pos)++;
293961d06d6bSBaptiste Daroussin
294061d06d6bSBaptiste Daroussin if ( ! roff_evalpar(r, ln, v, pos, res, flags))
294161d06d6bSBaptiste Daroussin return 0;
294261d06d6bSBaptiste Daroussin
294361d06d6bSBaptiste Daroussin while (1) {
294461d06d6bSBaptiste Daroussin if (flags & ROFFNUM_WHITE)
294561d06d6bSBaptiste Daroussin while (isspace((unsigned char)v[*pos]))
294661d06d6bSBaptiste Daroussin (*pos)++;
294761d06d6bSBaptiste Daroussin
294861d06d6bSBaptiste Daroussin if ( ! roff_getop(v, pos, &operator))
294961d06d6bSBaptiste Daroussin break;
295061d06d6bSBaptiste Daroussin
295161d06d6bSBaptiste Daroussin if (flags & ROFFNUM_WHITE)
295261d06d6bSBaptiste Daroussin while (isspace((unsigned char)v[*pos]))
295361d06d6bSBaptiste Daroussin (*pos)++;
295461d06d6bSBaptiste Daroussin
295561d06d6bSBaptiste Daroussin if ( ! roff_evalpar(r, ln, v, pos, &operand2, flags))
295661d06d6bSBaptiste Daroussin return 0;
295761d06d6bSBaptiste Daroussin
295861d06d6bSBaptiste Daroussin if (flags & ROFFNUM_WHITE)
295961d06d6bSBaptiste Daroussin while (isspace((unsigned char)v[*pos]))
296061d06d6bSBaptiste Daroussin (*pos)++;
296161d06d6bSBaptiste Daroussin
296261d06d6bSBaptiste Daroussin if (NULL == res)
296361d06d6bSBaptiste Daroussin continue;
296461d06d6bSBaptiste Daroussin
296561d06d6bSBaptiste Daroussin switch (operator) {
296661d06d6bSBaptiste Daroussin case '+':
296761d06d6bSBaptiste Daroussin *res += operand2;
296861d06d6bSBaptiste Daroussin break;
296961d06d6bSBaptiste Daroussin case '-':
297061d06d6bSBaptiste Daroussin *res -= operand2;
297161d06d6bSBaptiste Daroussin break;
297261d06d6bSBaptiste Daroussin case '*':
297361d06d6bSBaptiste Daroussin *res *= operand2;
297461d06d6bSBaptiste Daroussin break;
297561d06d6bSBaptiste Daroussin case '/':
297661d06d6bSBaptiste Daroussin if (operand2 == 0) {
297761d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_DIVZERO,
29787295610fSBaptiste Daroussin ln, *pos, "%s", v);
297961d06d6bSBaptiste Daroussin *res = 0;
298061d06d6bSBaptiste Daroussin break;
298161d06d6bSBaptiste Daroussin }
298261d06d6bSBaptiste Daroussin *res /= operand2;
298361d06d6bSBaptiste Daroussin break;
298461d06d6bSBaptiste Daroussin case '%':
298561d06d6bSBaptiste Daroussin if (operand2 == 0) {
298661d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_DIVZERO,
29877295610fSBaptiste Daroussin ln, *pos, "%s", v);
298861d06d6bSBaptiste Daroussin *res = 0;
298961d06d6bSBaptiste Daroussin break;
299061d06d6bSBaptiste Daroussin }
299161d06d6bSBaptiste Daroussin *res %= operand2;
299261d06d6bSBaptiste Daroussin break;
299361d06d6bSBaptiste Daroussin case '<':
299461d06d6bSBaptiste Daroussin *res = *res < operand2;
299561d06d6bSBaptiste Daroussin break;
299661d06d6bSBaptiste Daroussin case '>':
299761d06d6bSBaptiste Daroussin *res = *res > operand2;
299861d06d6bSBaptiste Daroussin break;
299961d06d6bSBaptiste Daroussin case 'l':
300061d06d6bSBaptiste Daroussin *res = *res <= operand2;
300161d06d6bSBaptiste Daroussin break;
300261d06d6bSBaptiste Daroussin case 'g':
300361d06d6bSBaptiste Daroussin *res = *res >= operand2;
300461d06d6bSBaptiste Daroussin break;
300561d06d6bSBaptiste Daroussin case '=':
300661d06d6bSBaptiste Daroussin *res = *res == operand2;
300761d06d6bSBaptiste Daroussin break;
300861d06d6bSBaptiste Daroussin case '!':
300961d06d6bSBaptiste Daroussin *res = *res != operand2;
301061d06d6bSBaptiste Daroussin break;
301161d06d6bSBaptiste Daroussin case '&':
301261d06d6bSBaptiste Daroussin *res = *res && operand2;
301361d06d6bSBaptiste Daroussin break;
301461d06d6bSBaptiste Daroussin case ':':
301561d06d6bSBaptiste Daroussin *res = *res || operand2;
301661d06d6bSBaptiste Daroussin break;
301761d06d6bSBaptiste Daroussin case 'i':
301861d06d6bSBaptiste Daroussin if (operand2 < *res)
301961d06d6bSBaptiste Daroussin *res = operand2;
302061d06d6bSBaptiste Daroussin break;
302161d06d6bSBaptiste Daroussin case 'a':
302261d06d6bSBaptiste Daroussin if (operand2 > *res)
302361d06d6bSBaptiste Daroussin *res = operand2;
302461d06d6bSBaptiste Daroussin break;
302561d06d6bSBaptiste Daroussin default:
302661d06d6bSBaptiste Daroussin abort();
302761d06d6bSBaptiste Daroussin }
302861d06d6bSBaptiste Daroussin }
302961d06d6bSBaptiste Daroussin return 1;
303061d06d6bSBaptiste Daroussin }
303161d06d6bSBaptiste Daroussin
303261d06d6bSBaptiste Daroussin /* --- register management ------------------------------------------------ */
303361d06d6bSBaptiste Daroussin
303461d06d6bSBaptiste Daroussin void
roff_setreg(struct roff * r,const char * name,int val,char sign)303561d06d6bSBaptiste Daroussin roff_setreg(struct roff *r, const char *name, int val, char sign)
303661d06d6bSBaptiste Daroussin {
303761d06d6bSBaptiste Daroussin roff_setregn(r, name, strlen(name), val, sign, INT_MIN);
303861d06d6bSBaptiste Daroussin }
303961d06d6bSBaptiste Daroussin
304061d06d6bSBaptiste Daroussin static void
roff_setregn(struct roff * r,const char * name,size_t len,int val,char sign,int step)304161d06d6bSBaptiste Daroussin roff_setregn(struct roff *r, const char *name, size_t len,
304261d06d6bSBaptiste Daroussin int val, char sign, int step)
304361d06d6bSBaptiste Daroussin {
304461d06d6bSBaptiste Daroussin struct roffreg *reg;
304561d06d6bSBaptiste Daroussin
304661d06d6bSBaptiste Daroussin /* Search for an existing register with the same name. */
304761d06d6bSBaptiste Daroussin reg = r->regtab;
304861d06d6bSBaptiste Daroussin
304961d06d6bSBaptiste Daroussin while (reg != NULL && (reg->key.sz != len ||
305061d06d6bSBaptiste Daroussin strncmp(reg->key.p, name, len) != 0))
305161d06d6bSBaptiste Daroussin reg = reg->next;
305261d06d6bSBaptiste Daroussin
305361d06d6bSBaptiste Daroussin if (NULL == reg) {
305461d06d6bSBaptiste Daroussin /* Create a new register. */
305561d06d6bSBaptiste Daroussin reg = mandoc_malloc(sizeof(struct roffreg));
305661d06d6bSBaptiste Daroussin reg->key.p = mandoc_strndup(name, len);
305761d06d6bSBaptiste Daroussin reg->key.sz = len;
305861d06d6bSBaptiste Daroussin reg->val = 0;
305961d06d6bSBaptiste Daroussin reg->step = 0;
306061d06d6bSBaptiste Daroussin reg->next = r->regtab;
306161d06d6bSBaptiste Daroussin r->regtab = reg;
306261d06d6bSBaptiste Daroussin }
306361d06d6bSBaptiste Daroussin
306461d06d6bSBaptiste Daroussin if ('+' == sign)
306561d06d6bSBaptiste Daroussin reg->val += val;
306661d06d6bSBaptiste Daroussin else if ('-' == sign)
306761d06d6bSBaptiste Daroussin reg->val -= val;
306861d06d6bSBaptiste Daroussin else
306961d06d6bSBaptiste Daroussin reg->val = val;
307061d06d6bSBaptiste Daroussin if (step != INT_MIN)
307161d06d6bSBaptiste Daroussin reg->step = step;
307261d06d6bSBaptiste Daroussin }
307361d06d6bSBaptiste Daroussin
307461d06d6bSBaptiste Daroussin /*
307561d06d6bSBaptiste Daroussin * Handle some predefined read-only number registers.
307661d06d6bSBaptiste Daroussin * For now, return -1 if the requested register is not predefined;
307761d06d6bSBaptiste Daroussin * in case a predefined read-only register having the value -1
307861d06d6bSBaptiste Daroussin * were to turn up, another special value would have to be chosen.
307961d06d6bSBaptiste Daroussin */
308061d06d6bSBaptiste Daroussin static int
roff_getregro(const struct roff * r,const char * name)308161d06d6bSBaptiste Daroussin roff_getregro(const struct roff *r, const char *name)
308261d06d6bSBaptiste Daroussin {
308361d06d6bSBaptiste Daroussin
308461d06d6bSBaptiste Daroussin switch (*name) {
308561d06d6bSBaptiste Daroussin case '$': /* Number of arguments of the last macro evaluated. */
30867295610fSBaptiste Daroussin return r->mstackpos < 0 ? 0 : r->mstack[r->mstackpos].argc;
308761d06d6bSBaptiste Daroussin case 'A': /* ASCII approximation mode is always off. */
308861d06d6bSBaptiste Daroussin return 0;
308961d06d6bSBaptiste Daroussin case 'g': /* Groff compatibility mode is always on. */
309061d06d6bSBaptiste Daroussin return 1;
309161d06d6bSBaptiste Daroussin case 'H': /* Fixed horizontal resolution. */
309261d06d6bSBaptiste Daroussin return 24;
309361d06d6bSBaptiste Daroussin case 'j': /* Always adjust left margin only. */
309461d06d6bSBaptiste Daroussin return 0;
309561d06d6bSBaptiste Daroussin case 'T': /* Some output device is always defined. */
309661d06d6bSBaptiste Daroussin return 1;
309761d06d6bSBaptiste Daroussin case 'V': /* Fixed vertical resolution. */
309861d06d6bSBaptiste Daroussin return 40;
309961d06d6bSBaptiste Daroussin default:
310061d06d6bSBaptiste Daroussin return -1;
310161d06d6bSBaptiste Daroussin }
310261d06d6bSBaptiste Daroussin }
310361d06d6bSBaptiste Daroussin
310461d06d6bSBaptiste Daroussin int
roff_getreg(struct roff * r,const char * name)310561d06d6bSBaptiste Daroussin roff_getreg(struct roff *r, const char *name)
310661d06d6bSBaptiste Daroussin {
310761d06d6bSBaptiste Daroussin return roff_getregn(r, name, strlen(name), '\0');
310861d06d6bSBaptiste Daroussin }
310961d06d6bSBaptiste Daroussin
311061d06d6bSBaptiste Daroussin static int
roff_getregn(struct roff * r,const char * name,size_t len,char sign)311161d06d6bSBaptiste Daroussin roff_getregn(struct roff *r, const char *name, size_t len, char sign)
311261d06d6bSBaptiste Daroussin {
311361d06d6bSBaptiste Daroussin struct roffreg *reg;
311461d06d6bSBaptiste Daroussin int val;
311561d06d6bSBaptiste Daroussin
311661d06d6bSBaptiste Daroussin if ('.' == name[0] && 2 == len) {
311761d06d6bSBaptiste Daroussin val = roff_getregro(r, name + 1);
311861d06d6bSBaptiste Daroussin if (-1 != val)
311961d06d6bSBaptiste Daroussin return val;
312061d06d6bSBaptiste Daroussin }
312161d06d6bSBaptiste Daroussin
312261d06d6bSBaptiste Daroussin for (reg = r->regtab; reg; reg = reg->next) {
312361d06d6bSBaptiste Daroussin if (len == reg->key.sz &&
312461d06d6bSBaptiste Daroussin 0 == strncmp(name, reg->key.p, len)) {
312561d06d6bSBaptiste Daroussin switch (sign) {
312661d06d6bSBaptiste Daroussin case '+':
312761d06d6bSBaptiste Daroussin reg->val += reg->step;
312861d06d6bSBaptiste Daroussin break;
312961d06d6bSBaptiste Daroussin case '-':
313061d06d6bSBaptiste Daroussin reg->val -= reg->step;
313161d06d6bSBaptiste Daroussin break;
313261d06d6bSBaptiste Daroussin default:
313361d06d6bSBaptiste Daroussin break;
313461d06d6bSBaptiste Daroussin }
313561d06d6bSBaptiste Daroussin return reg->val;
313661d06d6bSBaptiste Daroussin }
313761d06d6bSBaptiste Daroussin }
313861d06d6bSBaptiste Daroussin
313961d06d6bSBaptiste Daroussin roff_setregn(r, name, len, 0, '\0', INT_MIN);
314061d06d6bSBaptiste Daroussin return 0;
314161d06d6bSBaptiste Daroussin }
314261d06d6bSBaptiste Daroussin
314361d06d6bSBaptiste Daroussin static int
roff_hasregn(const struct roff * r,const char * name,size_t len)314461d06d6bSBaptiste Daroussin roff_hasregn(const struct roff *r, const char *name, size_t len)
314561d06d6bSBaptiste Daroussin {
314661d06d6bSBaptiste Daroussin struct roffreg *reg;
314761d06d6bSBaptiste Daroussin int val;
314861d06d6bSBaptiste Daroussin
314961d06d6bSBaptiste Daroussin if ('.' == name[0] && 2 == len) {
315061d06d6bSBaptiste Daroussin val = roff_getregro(r, name + 1);
315161d06d6bSBaptiste Daroussin if (-1 != val)
315261d06d6bSBaptiste Daroussin return 1;
315361d06d6bSBaptiste Daroussin }
315461d06d6bSBaptiste Daroussin
315561d06d6bSBaptiste Daroussin for (reg = r->regtab; reg; reg = reg->next)
315661d06d6bSBaptiste Daroussin if (len == reg->key.sz &&
315761d06d6bSBaptiste Daroussin 0 == strncmp(name, reg->key.p, len))
315861d06d6bSBaptiste Daroussin return 1;
315961d06d6bSBaptiste Daroussin
316061d06d6bSBaptiste Daroussin return 0;
316161d06d6bSBaptiste Daroussin }
316261d06d6bSBaptiste Daroussin
316361d06d6bSBaptiste Daroussin static void
roff_freereg(struct roffreg * reg)316461d06d6bSBaptiste Daroussin roff_freereg(struct roffreg *reg)
316561d06d6bSBaptiste Daroussin {
316661d06d6bSBaptiste Daroussin struct roffreg *old_reg;
316761d06d6bSBaptiste Daroussin
316861d06d6bSBaptiste Daroussin while (NULL != reg) {
316961d06d6bSBaptiste Daroussin free(reg->key.p);
317061d06d6bSBaptiste Daroussin old_reg = reg;
317161d06d6bSBaptiste Daroussin reg = reg->next;
317261d06d6bSBaptiste Daroussin free(old_reg);
317361d06d6bSBaptiste Daroussin }
317461d06d6bSBaptiste Daroussin }
317561d06d6bSBaptiste Daroussin
31767295610fSBaptiste Daroussin static int
roff_nr(ROFF_ARGS)317761d06d6bSBaptiste Daroussin roff_nr(ROFF_ARGS)
317861d06d6bSBaptiste Daroussin {
317961d06d6bSBaptiste Daroussin char *key, *val, *step;
318061d06d6bSBaptiste Daroussin size_t keysz;
318161d06d6bSBaptiste Daroussin int iv, is, len;
318261d06d6bSBaptiste Daroussin char sign;
318361d06d6bSBaptiste Daroussin
318461d06d6bSBaptiste Daroussin key = val = buf->buf + pos;
318561d06d6bSBaptiste Daroussin if (*key == '\0')
318661d06d6bSBaptiste Daroussin return ROFF_IGN;
318761d06d6bSBaptiste Daroussin
318861d06d6bSBaptiste Daroussin keysz = roff_getname(r, &val, ln, pos);
31897295610fSBaptiste Daroussin if (key[keysz] == '\\' || key[keysz] == '\t')
319061d06d6bSBaptiste Daroussin return ROFF_IGN;
319161d06d6bSBaptiste Daroussin
319261d06d6bSBaptiste Daroussin sign = *val;
319361d06d6bSBaptiste Daroussin if (sign == '+' || sign == '-')
319461d06d6bSBaptiste Daroussin val++;
319561d06d6bSBaptiste Daroussin
319661d06d6bSBaptiste Daroussin len = 0;
319761d06d6bSBaptiste Daroussin if (roff_evalnum(r, ln, val, &len, &iv, ROFFNUM_SCALE) == 0)
319861d06d6bSBaptiste Daroussin return ROFF_IGN;
319961d06d6bSBaptiste Daroussin
320061d06d6bSBaptiste Daroussin step = val + len;
320161d06d6bSBaptiste Daroussin while (isspace((unsigned char)*step))
320261d06d6bSBaptiste Daroussin step++;
320361d06d6bSBaptiste Daroussin if (roff_evalnum(r, ln, step, NULL, &is, 0) == 0)
320461d06d6bSBaptiste Daroussin is = INT_MIN;
320561d06d6bSBaptiste Daroussin
320661d06d6bSBaptiste Daroussin roff_setregn(r, key, keysz, iv, sign, is);
320761d06d6bSBaptiste Daroussin return ROFF_IGN;
320861d06d6bSBaptiste Daroussin }
320961d06d6bSBaptiste Daroussin
32107295610fSBaptiste Daroussin static int
roff_rr(ROFF_ARGS)321161d06d6bSBaptiste Daroussin roff_rr(ROFF_ARGS)
321261d06d6bSBaptiste Daroussin {
321361d06d6bSBaptiste Daroussin struct roffreg *reg, **prev;
321461d06d6bSBaptiste Daroussin char *name, *cp;
321561d06d6bSBaptiste Daroussin size_t namesz;
321661d06d6bSBaptiste Daroussin
321761d06d6bSBaptiste Daroussin name = cp = buf->buf + pos;
321861d06d6bSBaptiste Daroussin if (*name == '\0')
321961d06d6bSBaptiste Daroussin return ROFF_IGN;
322061d06d6bSBaptiste Daroussin namesz = roff_getname(r, &cp, ln, pos);
322161d06d6bSBaptiste Daroussin name[namesz] = '\0';
322261d06d6bSBaptiste Daroussin
322361d06d6bSBaptiste Daroussin prev = &r->regtab;
322461d06d6bSBaptiste Daroussin while (1) {
322561d06d6bSBaptiste Daroussin reg = *prev;
322661d06d6bSBaptiste Daroussin if (reg == NULL || !strcmp(name, reg->key.p))
322761d06d6bSBaptiste Daroussin break;
322861d06d6bSBaptiste Daroussin prev = ®->next;
322961d06d6bSBaptiste Daroussin }
323061d06d6bSBaptiste Daroussin if (reg != NULL) {
323161d06d6bSBaptiste Daroussin *prev = reg->next;
323261d06d6bSBaptiste Daroussin free(reg->key.p);
323361d06d6bSBaptiste Daroussin free(reg);
323461d06d6bSBaptiste Daroussin }
323561d06d6bSBaptiste Daroussin return ROFF_IGN;
323661d06d6bSBaptiste Daroussin }
323761d06d6bSBaptiste Daroussin
323861d06d6bSBaptiste Daroussin /* --- handler functions for roff requests -------------------------------- */
323961d06d6bSBaptiste Daroussin
32407295610fSBaptiste Daroussin static int
roff_rm(ROFF_ARGS)324161d06d6bSBaptiste Daroussin roff_rm(ROFF_ARGS)
324261d06d6bSBaptiste Daroussin {
324361d06d6bSBaptiste Daroussin const char *name;
324461d06d6bSBaptiste Daroussin char *cp;
324561d06d6bSBaptiste Daroussin size_t namesz;
324661d06d6bSBaptiste Daroussin
324761d06d6bSBaptiste Daroussin cp = buf->buf + pos;
324861d06d6bSBaptiste Daroussin while (*cp != '\0') {
324961d06d6bSBaptiste Daroussin name = cp;
325061d06d6bSBaptiste Daroussin namesz = roff_getname(r, &cp, ln, (int)(cp - buf->buf));
325161d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, name, namesz, NULL, 0, 0);
325261d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0);
32537295610fSBaptiste Daroussin if (name[namesz] == '\\' || name[namesz] == '\t')
325461d06d6bSBaptiste Daroussin break;
325561d06d6bSBaptiste Daroussin }
325661d06d6bSBaptiste Daroussin return ROFF_IGN;
325761d06d6bSBaptiste Daroussin }
325861d06d6bSBaptiste Daroussin
32597295610fSBaptiste Daroussin static int
roff_it(ROFF_ARGS)326061d06d6bSBaptiste Daroussin roff_it(ROFF_ARGS)
326161d06d6bSBaptiste Daroussin {
326261d06d6bSBaptiste Daroussin int iv;
326361d06d6bSBaptiste Daroussin
326461d06d6bSBaptiste Daroussin /* Parse the number of lines. */
326561d06d6bSBaptiste Daroussin
326661d06d6bSBaptiste Daroussin if ( ! roff_evalnum(r, ln, buf->buf, &pos, &iv, 0)) {
32677295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_IT_NONUM,
32687295610fSBaptiste Daroussin ln, ppos, "%s", buf->buf + 1);
326961d06d6bSBaptiste Daroussin return ROFF_IGN;
327061d06d6bSBaptiste Daroussin }
327161d06d6bSBaptiste Daroussin
327261d06d6bSBaptiste Daroussin while (isspace((unsigned char)buf->buf[pos]))
327361d06d6bSBaptiste Daroussin pos++;
327461d06d6bSBaptiste Daroussin
327561d06d6bSBaptiste Daroussin /*
327661d06d6bSBaptiste Daroussin * Arm the input line trap.
327761d06d6bSBaptiste Daroussin * Special-casing "an-trap" is an ugly workaround to cope
327861d06d6bSBaptiste Daroussin * with DocBook stupidly fiddling with man(7) internals.
327961d06d6bSBaptiste Daroussin */
328061d06d6bSBaptiste Daroussin
328161d06d6bSBaptiste Daroussin roffit_lines = iv;
328261d06d6bSBaptiste Daroussin roffit_macro = mandoc_strdup(iv != 1 ||
328361d06d6bSBaptiste Daroussin strcmp(buf->buf + pos, "an-trap") ?
328461d06d6bSBaptiste Daroussin buf->buf + pos : "br");
328561d06d6bSBaptiste Daroussin return ROFF_IGN;
328661d06d6bSBaptiste Daroussin }
328761d06d6bSBaptiste Daroussin
32887295610fSBaptiste Daroussin static int
roff_Dd(ROFF_ARGS)328961d06d6bSBaptiste Daroussin roff_Dd(ROFF_ARGS)
329061d06d6bSBaptiste Daroussin {
329161d06d6bSBaptiste Daroussin int mask;
329261d06d6bSBaptiste Daroussin enum roff_tok t, te;
329361d06d6bSBaptiste Daroussin
329461d06d6bSBaptiste Daroussin switch (tok) {
329561d06d6bSBaptiste Daroussin case ROFF_Dd:
329661d06d6bSBaptiste Daroussin tok = MDOC_Dd;
329761d06d6bSBaptiste Daroussin te = MDOC_MAX;
329861d06d6bSBaptiste Daroussin if (r->format == 0)
329961d06d6bSBaptiste Daroussin r->format = MPARSE_MDOC;
330061d06d6bSBaptiste Daroussin mask = MPARSE_MDOC | MPARSE_QUICK;
330161d06d6bSBaptiste Daroussin break;
330261d06d6bSBaptiste Daroussin case ROFF_TH:
330361d06d6bSBaptiste Daroussin tok = MAN_TH;
330461d06d6bSBaptiste Daroussin te = MAN_MAX;
330561d06d6bSBaptiste Daroussin if (r->format == 0)
330661d06d6bSBaptiste Daroussin r->format = MPARSE_MAN;
330761d06d6bSBaptiste Daroussin mask = MPARSE_QUICK;
330861d06d6bSBaptiste Daroussin break;
330961d06d6bSBaptiste Daroussin default:
331061d06d6bSBaptiste Daroussin abort();
331161d06d6bSBaptiste Daroussin }
331261d06d6bSBaptiste Daroussin if ((r->options & mask) == 0)
331361d06d6bSBaptiste Daroussin for (t = tok; t < te; t++)
331461d06d6bSBaptiste Daroussin roff_setstr(r, roff_name[t], NULL, 0);
331561d06d6bSBaptiste Daroussin return ROFF_CONT;
331661d06d6bSBaptiste Daroussin }
331761d06d6bSBaptiste Daroussin
33187295610fSBaptiste Daroussin static int
roff_TE(ROFF_ARGS)331961d06d6bSBaptiste Daroussin roff_TE(ROFF_ARGS)
332061d06d6bSBaptiste Daroussin {
33217295610fSBaptiste Daroussin r->man->flags &= ~ROFF_NONOFILL;
332261d06d6bSBaptiste Daroussin if (r->tbl == NULL) {
33237295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "TE");
332461d06d6bSBaptiste Daroussin return ROFF_IGN;
332561d06d6bSBaptiste Daroussin }
33267295610fSBaptiste Daroussin if (tbl_end(r->tbl, 0) == 0) {
332761d06d6bSBaptiste Daroussin r->tbl = NULL;
332861d06d6bSBaptiste Daroussin free(buf->buf);
332961d06d6bSBaptiste Daroussin buf->buf = mandoc_strdup(".sp");
333061d06d6bSBaptiste Daroussin buf->sz = 4;
333161d06d6bSBaptiste Daroussin *offs = 0;
333261d06d6bSBaptiste Daroussin return ROFF_REPARSE;
333361d06d6bSBaptiste Daroussin }
333461d06d6bSBaptiste Daroussin r->tbl = NULL;
333561d06d6bSBaptiste Daroussin return ROFF_IGN;
333661d06d6bSBaptiste Daroussin }
333761d06d6bSBaptiste Daroussin
33387295610fSBaptiste Daroussin static int
roff_T_(ROFF_ARGS)333961d06d6bSBaptiste Daroussin roff_T_(ROFF_ARGS)
334061d06d6bSBaptiste Daroussin {
334161d06d6bSBaptiste Daroussin
334261d06d6bSBaptiste Daroussin if (NULL == r->tbl)
33437295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "T&");
334461d06d6bSBaptiste Daroussin else
334561d06d6bSBaptiste Daroussin tbl_restart(ln, ppos, r->tbl);
334661d06d6bSBaptiste Daroussin
334761d06d6bSBaptiste Daroussin return ROFF_IGN;
334861d06d6bSBaptiste Daroussin }
334961d06d6bSBaptiste Daroussin
335061d06d6bSBaptiste Daroussin /*
335161d06d6bSBaptiste Daroussin * Handle in-line equation delimiters.
335261d06d6bSBaptiste Daroussin */
33537295610fSBaptiste Daroussin static int
roff_eqndelim(struct roff * r,struct buf * buf,int pos)335461d06d6bSBaptiste Daroussin roff_eqndelim(struct roff *r, struct buf *buf, int pos)
335561d06d6bSBaptiste Daroussin {
335661d06d6bSBaptiste Daroussin char *cp1, *cp2;
335761d06d6bSBaptiste Daroussin const char *bef_pr, *bef_nl, *mac, *aft_nl, *aft_pr;
335861d06d6bSBaptiste Daroussin
335961d06d6bSBaptiste Daroussin /*
336061d06d6bSBaptiste Daroussin * Outside equations, look for an opening delimiter.
336161d06d6bSBaptiste Daroussin * If we are inside an equation, we already know it is
336261d06d6bSBaptiste Daroussin * in-line, or this function wouldn't have been called;
336361d06d6bSBaptiste Daroussin * so look for a closing delimiter.
336461d06d6bSBaptiste Daroussin */
336561d06d6bSBaptiste Daroussin
336661d06d6bSBaptiste Daroussin cp1 = buf->buf + pos;
336761d06d6bSBaptiste Daroussin cp2 = strchr(cp1, r->eqn == NULL ?
336861d06d6bSBaptiste Daroussin r->last_eqn->odelim : r->last_eqn->cdelim);
336961d06d6bSBaptiste Daroussin if (cp2 == NULL)
337061d06d6bSBaptiste Daroussin return ROFF_CONT;
337161d06d6bSBaptiste Daroussin
337261d06d6bSBaptiste Daroussin *cp2++ = '\0';
337361d06d6bSBaptiste Daroussin bef_pr = bef_nl = aft_nl = aft_pr = "";
337461d06d6bSBaptiste Daroussin
337561d06d6bSBaptiste Daroussin /* Handle preceding text, protecting whitespace. */
337661d06d6bSBaptiste Daroussin
337761d06d6bSBaptiste Daroussin if (*buf->buf != '\0') {
337861d06d6bSBaptiste Daroussin if (r->eqn == NULL)
337961d06d6bSBaptiste Daroussin bef_pr = "\\&";
338061d06d6bSBaptiste Daroussin bef_nl = "\n";
338161d06d6bSBaptiste Daroussin }
338261d06d6bSBaptiste Daroussin
338361d06d6bSBaptiste Daroussin /*
338461d06d6bSBaptiste Daroussin * Prepare replacing the delimiter with an equation macro
338561d06d6bSBaptiste Daroussin * and drop leading white space from the equation.
338661d06d6bSBaptiste Daroussin */
338761d06d6bSBaptiste Daroussin
338861d06d6bSBaptiste Daroussin if (r->eqn == NULL) {
338961d06d6bSBaptiste Daroussin while (*cp2 == ' ')
339061d06d6bSBaptiste Daroussin cp2++;
339161d06d6bSBaptiste Daroussin mac = ".EQ";
339261d06d6bSBaptiste Daroussin } else
339361d06d6bSBaptiste Daroussin mac = ".EN";
339461d06d6bSBaptiste Daroussin
339561d06d6bSBaptiste Daroussin /* Handle following text, protecting whitespace. */
339661d06d6bSBaptiste Daroussin
339761d06d6bSBaptiste Daroussin if (*cp2 != '\0') {
339861d06d6bSBaptiste Daroussin aft_nl = "\n";
339961d06d6bSBaptiste Daroussin if (r->eqn != NULL)
340061d06d6bSBaptiste Daroussin aft_pr = "\\&";
340161d06d6bSBaptiste Daroussin }
340261d06d6bSBaptiste Daroussin
340361d06d6bSBaptiste Daroussin /* Do the actual replacement. */
340461d06d6bSBaptiste Daroussin
340561d06d6bSBaptiste Daroussin buf->sz = mandoc_asprintf(&cp1, "%s%s%s%s%s%s%s", buf->buf,
340661d06d6bSBaptiste Daroussin bef_pr, bef_nl, mac, aft_nl, aft_pr, cp2) + 1;
340761d06d6bSBaptiste Daroussin free(buf->buf);
340861d06d6bSBaptiste Daroussin buf->buf = cp1;
340961d06d6bSBaptiste Daroussin
341061d06d6bSBaptiste Daroussin /* Toggle the in-line state of the eqn subsystem. */
341161d06d6bSBaptiste Daroussin
341261d06d6bSBaptiste Daroussin r->eqn_inline = r->eqn == NULL;
341361d06d6bSBaptiste Daroussin return ROFF_REPARSE;
341461d06d6bSBaptiste Daroussin }
341561d06d6bSBaptiste Daroussin
34167295610fSBaptiste Daroussin static int
roff_EQ(ROFF_ARGS)341761d06d6bSBaptiste Daroussin roff_EQ(ROFF_ARGS)
341861d06d6bSBaptiste Daroussin {
341961d06d6bSBaptiste Daroussin struct roff_node *n;
342061d06d6bSBaptiste Daroussin
34217295610fSBaptiste Daroussin if (r->man->meta.macroset == MACROSET_MAN)
342261d06d6bSBaptiste Daroussin man_breakscope(r->man, ROFF_EQ);
342361d06d6bSBaptiste Daroussin n = roff_node_alloc(r->man, ln, ppos, ROFFT_EQN, TOKEN_NONE);
342461d06d6bSBaptiste Daroussin if (ln > r->man->last->line)
342561d06d6bSBaptiste Daroussin n->flags |= NODE_LINE;
34267295610fSBaptiste Daroussin n->eqn = eqn_box_new();
342761d06d6bSBaptiste Daroussin roff_node_append(r->man, n);
342861d06d6bSBaptiste Daroussin r->man->next = ROFF_NEXT_SIBLING;
342961d06d6bSBaptiste Daroussin
343061d06d6bSBaptiste Daroussin assert(r->eqn == NULL);
343161d06d6bSBaptiste Daroussin if (r->last_eqn == NULL)
34327295610fSBaptiste Daroussin r->last_eqn = eqn_alloc();
343361d06d6bSBaptiste Daroussin else
343461d06d6bSBaptiste Daroussin eqn_reset(r->last_eqn);
343561d06d6bSBaptiste Daroussin r->eqn = r->last_eqn;
343661d06d6bSBaptiste Daroussin r->eqn->node = n;
343761d06d6bSBaptiste Daroussin
343861d06d6bSBaptiste Daroussin if (buf->buf[pos] != '\0')
34397295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos,
344061d06d6bSBaptiste Daroussin ".EQ %s", buf->buf + pos);
344161d06d6bSBaptiste Daroussin
344261d06d6bSBaptiste Daroussin return ROFF_IGN;
344361d06d6bSBaptiste Daroussin }
344461d06d6bSBaptiste Daroussin
34457295610fSBaptiste Daroussin static int
roff_EN(ROFF_ARGS)344661d06d6bSBaptiste Daroussin roff_EN(ROFF_ARGS)
344761d06d6bSBaptiste Daroussin {
344861d06d6bSBaptiste Daroussin if (r->eqn != NULL) {
344961d06d6bSBaptiste Daroussin eqn_parse(r->eqn);
345061d06d6bSBaptiste Daroussin r->eqn = NULL;
345161d06d6bSBaptiste Daroussin } else
34527295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "EN");
345361d06d6bSBaptiste Daroussin if (buf->buf[pos] != '\0')
34547295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos,
345561d06d6bSBaptiste Daroussin "EN %s", buf->buf + pos);
345661d06d6bSBaptiste Daroussin return ROFF_IGN;
345761d06d6bSBaptiste Daroussin }
345861d06d6bSBaptiste Daroussin
34597295610fSBaptiste Daroussin static int
roff_TS(ROFF_ARGS)346061d06d6bSBaptiste Daroussin roff_TS(ROFF_ARGS)
346161d06d6bSBaptiste Daroussin {
346261d06d6bSBaptiste Daroussin if (r->tbl != NULL) {
34637295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_BROKEN, ln, ppos, "TS breaks TS");
34647295610fSBaptiste Daroussin tbl_end(r->tbl, 0);
346561d06d6bSBaptiste Daroussin }
34667295610fSBaptiste Daroussin r->man->flags |= ROFF_NONOFILL;
34677295610fSBaptiste Daroussin r->tbl = tbl_alloc(ppos, ln, r->last_tbl);
34687295610fSBaptiste Daroussin if (r->last_tbl == NULL)
346961d06d6bSBaptiste Daroussin r->first_tbl = r->tbl;
347061d06d6bSBaptiste Daroussin r->last_tbl = r->tbl;
347161d06d6bSBaptiste Daroussin return ROFF_IGN;
347261d06d6bSBaptiste Daroussin }
347361d06d6bSBaptiste Daroussin
34747295610fSBaptiste Daroussin static int
roff_noarg(ROFF_ARGS)34757295610fSBaptiste Daroussin roff_noarg(ROFF_ARGS)
34767295610fSBaptiste Daroussin {
34777295610fSBaptiste Daroussin if (r->man->flags & (MAN_BLINE | MAN_ELINE))
34787295610fSBaptiste Daroussin man_breakscope(r->man, tok);
34797295610fSBaptiste Daroussin if (tok == ROFF_brp)
34807295610fSBaptiste Daroussin tok = ROFF_br;
34817295610fSBaptiste Daroussin roff_elem_alloc(r->man, ln, ppos, tok);
34827295610fSBaptiste Daroussin if (buf->buf[pos] != '\0')
34837295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos,
34847295610fSBaptiste Daroussin "%s %s", roff_name[tok], buf->buf + pos);
34857295610fSBaptiste Daroussin if (tok == ROFF_nf)
34867295610fSBaptiste Daroussin r->man->flags |= ROFF_NOFILL;
34877295610fSBaptiste Daroussin else if (tok == ROFF_fi)
34887295610fSBaptiste Daroussin r->man->flags &= ~ROFF_NOFILL;
34897295610fSBaptiste Daroussin r->man->last->flags |= NODE_LINE | NODE_VALID | NODE_ENDED;
34907295610fSBaptiste Daroussin r->man->next = ROFF_NEXT_SIBLING;
34917295610fSBaptiste Daroussin return ROFF_IGN;
34927295610fSBaptiste Daroussin }
34937295610fSBaptiste Daroussin
34947295610fSBaptiste Daroussin static int
roff_onearg(ROFF_ARGS)349561d06d6bSBaptiste Daroussin roff_onearg(ROFF_ARGS)
349661d06d6bSBaptiste Daroussin {
349761d06d6bSBaptiste Daroussin struct roff_node *n;
349861d06d6bSBaptiste Daroussin char *cp;
349961d06d6bSBaptiste Daroussin int npos;
350061d06d6bSBaptiste Daroussin
350161d06d6bSBaptiste Daroussin if (r->man->flags & (MAN_BLINE | MAN_ELINE) &&
350261d06d6bSBaptiste Daroussin (tok == ROFF_ce || tok == ROFF_rj || tok == ROFF_sp ||
350361d06d6bSBaptiste Daroussin tok == ROFF_ti))
350461d06d6bSBaptiste Daroussin man_breakscope(r->man, tok);
350561d06d6bSBaptiste Daroussin
350661d06d6bSBaptiste Daroussin if (roffce_node != NULL && (tok == ROFF_ce || tok == ROFF_rj)) {
350761d06d6bSBaptiste Daroussin r->man->last = roffce_node;
350861d06d6bSBaptiste Daroussin r->man->next = ROFF_NEXT_SIBLING;
350961d06d6bSBaptiste Daroussin }
351061d06d6bSBaptiste Daroussin
351161d06d6bSBaptiste Daroussin roff_elem_alloc(r->man, ln, ppos, tok);
351261d06d6bSBaptiste Daroussin n = r->man->last;
351361d06d6bSBaptiste Daroussin
351461d06d6bSBaptiste Daroussin cp = buf->buf + pos;
351561d06d6bSBaptiste Daroussin if (*cp != '\0') {
351661d06d6bSBaptiste Daroussin while (*cp != '\0' && *cp != ' ')
351761d06d6bSBaptiste Daroussin cp++;
351861d06d6bSBaptiste Daroussin while (*cp == ' ')
351961d06d6bSBaptiste Daroussin *cp++ = '\0';
352061d06d6bSBaptiste Daroussin if (*cp != '\0')
35217295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_EXCESS,
35227295610fSBaptiste Daroussin ln, (int)(cp - buf->buf),
352361d06d6bSBaptiste Daroussin "%s ... %s", roff_name[tok], cp);
352461d06d6bSBaptiste Daroussin roff_word_alloc(r->man, ln, pos, buf->buf + pos);
352561d06d6bSBaptiste Daroussin }
352661d06d6bSBaptiste Daroussin
352761d06d6bSBaptiste Daroussin if (tok == ROFF_ce || tok == ROFF_rj) {
352861d06d6bSBaptiste Daroussin if (r->man->last->type == ROFFT_ELEM) {
352961d06d6bSBaptiste Daroussin roff_word_alloc(r->man, ln, pos, "1");
353061d06d6bSBaptiste Daroussin r->man->last->flags |= NODE_NOSRC;
353161d06d6bSBaptiste Daroussin }
353261d06d6bSBaptiste Daroussin npos = 0;
353361d06d6bSBaptiste Daroussin if (roff_evalnum(r, ln, r->man->last->string, &npos,
353461d06d6bSBaptiste Daroussin &roffce_lines, 0) == 0) {
35357295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_CE_NONUM,
35367295610fSBaptiste Daroussin ln, pos, "ce %s", buf->buf + pos);
353761d06d6bSBaptiste Daroussin roffce_lines = 1;
353861d06d6bSBaptiste Daroussin }
353961d06d6bSBaptiste Daroussin if (roffce_lines < 1) {
354061d06d6bSBaptiste Daroussin r->man->last = r->man->last->parent;
354161d06d6bSBaptiste Daroussin roffce_node = NULL;
354261d06d6bSBaptiste Daroussin roffce_lines = 0;
354361d06d6bSBaptiste Daroussin } else
354461d06d6bSBaptiste Daroussin roffce_node = r->man->last->parent;
354561d06d6bSBaptiste Daroussin } else {
354661d06d6bSBaptiste Daroussin n->flags |= NODE_VALID | NODE_ENDED;
354761d06d6bSBaptiste Daroussin r->man->last = n;
354861d06d6bSBaptiste Daroussin }
354961d06d6bSBaptiste Daroussin n->flags |= NODE_LINE;
355061d06d6bSBaptiste Daroussin r->man->next = ROFF_NEXT_SIBLING;
355161d06d6bSBaptiste Daroussin return ROFF_IGN;
355261d06d6bSBaptiste Daroussin }
355361d06d6bSBaptiste Daroussin
35547295610fSBaptiste Daroussin static int
roff_manyarg(ROFF_ARGS)355561d06d6bSBaptiste Daroussin roff_manyarg(ROFF_ARGS)
355661d06d6bSBaptiste Daroussin {
355761d06d6bSBaptiste Daroussin struct roff_node *n;
355861d06d6bSBaptiste Daroussin char *sp, *ep;
355961d06d6bSBaptiste Daroussin
356061d06d6bSBaptiste Daroussin roff_elem_alloc(r->man, ln, ppos, tok);
356161d06d6bSBaptiste Daroussin n = r->man->last;
356261d06d6bSBaptiste Daroussin
356361d06d6bSBaptiste Daroussin for (sp = ep = buf->buf + pos; *sp != '\0'; sp = ep) {
356461d06d6bSBaptiste Daroussin while (*ep != '\0' && *ep != ' ')
356561d06d6bSBaptiste Daroussin ep++;
356661d06d6bSBaptiste Daroussin while (*ep == ' ')
356761d06d6bSBaptiste Daroussin *ep++ = '\0';
356861d06d6bSBaptiste Daroussin roff_word_alloc(r->man, ln, sp - buf->buf, sp);
356961d06d6bSBaptiste Daroussin }
357061d06d6bSBaptiste Daroussin
357161d06d6bSBaptiste Daroussin n->flags |= NODE_LINE | NODE_VALID | NODE_ENDED;
357261d06d6bSBaptiste Daroussin r->man->last = n;
357361d06d6bSBaptiste Daroussin r->man->next = ROFF_NEXT_SIBLING;
357461d06d6bSBaptiste Daroussin return ROFF_IGN;
357561d06d6bSBaptiste Daroussin }
357661d06d6bSBaptiste Daroussin
35777295610fSBaptiste Daroussin static int
roff_als(ROFF_ARGS)357861d06d6bSBaptiste Daroussin roff_als(ROFF_ARGS)
357961d06d6bSBaptiste Daroussin {
358061d06d6bSBaptiste Daroussin char *oldn, *newn, *end, *value;
358161d06d6bSBaptiste Daroussin size_t oldsz, newsz, valsz;
358261d06d6bSBaptiste Daroussin
358361d06d6bSBaptiste Daroussin newn = oldn = buf->buf + pos;
358461d06d6bSBaptiste Daroussin if (*newn == '\0')
358561d06d6bSBaptiste Daroussin return ROFF_IGN;
358661d06d6bSBaptiste Daroussin
358761d06d6bSBaptiste Daroussin newsz = roff_getname(r, &oldn, ln, pos);
35887295610fSBaptiste Daroussin if (newn[newsz] == '\\' || newn[newsz] == '\t' || *oldn == '\0')
358961d06d6bSBaptiste Daroussin return ROFF_IGN;
359061d06d6bSBaptiste Daroussin
359161d06d6bSBaptiste Daroussin end = oldn;
359261d06d6bSBaptiste Daroussin oldsz = roff_getname(r, &end, ln, oldn - buf->buf);
359361d06d6bSBaptiste Daroussin if (oldsz == 0)
359461d06d6bSBaptiste Daroussin return ROFF_IGN;
359561d06d6bSBaptiste Daroussin
35967295610fSBaptiste Daroussin valsz = mandoc_asprintf(&value, ".%.*s \\$@\\\"\n",
359761d06d6bSBaptiste Daroussin (int)oldsz, oldn);
359861d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, newn, newsz, value, valsz, 0);
359961d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0);
360061d06d6bSBaptiste Daroussin free(value);
360161d06d6bSBaptiste Daroussin return ROFF_IGN;
360261d06d6bSBaptiste Daroussin }
360361d06d6bSBaptiste Daroussin
360445a5aec3SBaptiste Daroussin /*
360545a5aec3SBaptiste Daroussin * The .break request only makes sense inside conditionals,
360645a5aec3SBaptiste Daroussin * and that case is already handled in roff_cond_sub().
360745a5aec3SBaptiste Daroussin */
360845a5aec3SBaptiste Daroussin static int
roff_break(ROFF_ARGS)360945a5aec3SBaptiste Daroussin roff_break(ROFF_ARGS)
361045a5aec3SBaptiste Daroussin {
361145a5aec3SBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, pos, "break");
361245a5aec3SBaptiste Daroussin return ROFF_IGN;
361345a5aec3SBaptiste Daroussin }
361445a5aec3SBaptiste Daroussin
36157295610fSBaptiste Daroussin static int
roff_cc(ROFF_ARGS)361661d06d6bSBaptiste Daroussin roff_cc(ROFF_ARGS)
361761d06d6bSBaptiste Daroussin {
361861d06d6bSBaptiste Daroussin const char *p;
361961d06d6bSBaptiste Daroussin
362061d06d6bSBaptiste Daroussin p = buf->buf + pos;
362161d06d6bSBaptiste Daroussin
362261d06d6bSBaptiste Daroussin if (*p == '\0' || (r->control = *p++) == '.')
362361d06d6bSBaptiste Daroussin r->control = '\0';
362461d06d6bSBaptiste Daroussin
362561d06d6bSBaptiste Daroussin if (*p != '\0')
36267295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_EXCESS,
362761d06d6bSBaptiste Daroussin ln, p - buf->buf, "cc ... %s", p);
362861d06d6bSBaptiste Daroussin
362961d06d6bSBaptiste Daroussin return ROFF_IGN;
363061d06d6bSBaptiste Daroussin }
363161d06d6bSBaptiste Daroussin
36327295610fSBaptiste Daroussin static int
roff_char(ROFF_ARGS)36337295610fSBaptiste Daroussin roff_char(ROFF_ARGS)
36347295610fSBaptiste Daroussin {
36357295610fSBaptiste Daroussin const char *p, *kp, *vp;
36367295610fSBaptiste Daroussin size_t ksz, vsz;
36377295610fSBaptiste Daroussin int font;
36387295610fSBaptiste Daroussin
36397295610fSBaptiste Daroussin /* Parse the character to be replaced. */
36407295610fSBaptiste Daroussin
36417295610fSBaptiste Daroussin kp = buf->buf + pos;
36427295610fSBaptiste Daroussin p = kp + 1;
36437295610fSBaptiste Daroussin if (*kp == '\0' || (*kp == '\\' &&
36447295610fSBaptiste Daroussin mandoc_escape(&p, NULL, NULL) != ESCAPE_SPECIAL) ||
36457295610fSBaptiste Daroussin (*p != ' ' && *p != '\0')) {
36467295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_CHAR_ARG, ln, pos, "char %s", kp);
36477295610fSBaptiste Daroussin return ROFF_IGN;
36487295610fSBaptiste Daroussin }
36497295610fSBaptiste Daroussin ksz = p - kp;
36507295610fSBaptiste Daroussin while (*p == ' ')
36517295610fSBaptiste Daroussin p++;
36527295610fSBaptiste Daroussin
36537295610fSBaptiste Daroussin /*
36547295610fSBaptiste Daroussin * If the replacement string contains a font escape sequence,
36557295610fSBaptiste Daroussin * we have to restore the font at the end.
36567295610fSBaptiste Daroussin */
36577295610fSBaptiste Daroussin
36587295610fSBaptiste Daroussin vp = p;
36597295610fSBaptiste Daroussin vsz = strlen(p);
36607295610fSBaptiste Daroussin font = 0;
36617295610fSBaptiste Daroussin while (*p != '\0') {
36627295610fSBaptiste Daroussin if (*p++ != '\\')
36637295610fSBaptiste Daroussin continue;
36647295610fSBaptiste Daroussin switch (mandoc_escape(&p, NULL, NULL)) {
36657295610fSBaptiste Daroussin case ESCAPE_FONT:
36667295610fSBaptiste Daroussin case ESCAPE_FONTROMAN:
36677295610fSBaptiste Daroussin case ESCAPE_FONTITALIC:
36687295610fSBaptiste Daroussin case ESCAPE_FONTBOLD:
36697295610fSBaptiste Daroussin case ESCAPE_FONTBI:
3670*6d38604fSBaptiste Daroussin case ESCAPE_FONTCR:
3671*6d38604fSBaptiste Daroussin case ESCAPE_FONTCB:
3672*6d38604fSBaptiste Daroussin case ESCAPE_FONTCI:
36737295610fSBaptiste Daroussin case ESCAPE_FONTPREV:
36747295610fSBaptiste Daroussin font++;
36757295610fSBaptiste Daroussin break;
36767295610fSBaptiste Daroussin default:
36777295610fSBaptiste Daroussin break;
36787295610fSBaptiste Daroussin }
36797295610fSBaptiste Daroussin }
36807295610fSBaptiste Daroussin if (font > 1)
36817295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_CHAR_FONT,
36827295610fSBaptiste Daroussin ln, (int)(vp - buf->buf), "%s", vp);
36837295610fSBaptiste Daroussin
36847295610fSBaptiste Daroussin /*
36857295610fSBaptiste Daroussin * Approximate the effect of .char using the .tr tables.
36867295610fSBaptiste Daroussin * XXX In groff, .char and .tr interact differently.
36877295610fSBaptiste Daroussin */
36887295610fSBaptiste Daroussin
36897295610fSBaptiste Daroussin if (ksz == 1) {
36907295610fSBaptiste Daroussin if (r->xtab == NULL)
36917295610fSBaptiste Daroussin r->xtab = mandoc_calloc(128, sizeof(*r->xtab));
36927295610fSBaptiste Daroussin assert((unsigned int)*kp < 128);
36937295610fSBaptiste Daroussin free(r->xtab[(int)*kp].p);
36947295610fSBaptiste Daroussin r->xtab[(int)*kp].sz = mandoc_asprintf(&r->xtab[(int)*kp].p,
36957295610fSBaptiste Daroussin "%s%s", vp, font ? "\fP" : "");
36967295610fSBaptiste Daroussin } else {
36977295610fSBaptiste Daroussin roff_setstrn(&r->xmbtab, kp, ksz, vp, vsz, 0);
36987295610fSBaptiste Daroussin if (font)
36997295610fSBaptiste Daroussin roff_setstrn(&r->xmbtab, kp, ksz, "\\fP", 3, 1);
37007295610fSBaptiste Daroussin }
37017295610fSBaptiste Daroussin return ROFF_IGN;
37027295610fSBaptiste Daroussin }
37037295610fSBaptiste Daroussin
37047295610fSBaptiste Daroussin static int
roff_ec(ROFF_ARGS)370561d06d6bSBaptiste Daroussin roff_ec(ROFF_ARGS)
370661d06d6bSBaptiste Daroussin {
370761d06d6bSBaptiste Daroussin const char *p;
370861d06d6bSBaptiste Daroussin
370961d06d6bSBaptiste Daroussin p = buf->buf + pos;
371061d06d6bSBaptiste Daroussin if (*p == '\0')
371161d06d6bSBaptiste Daroussin r->escape = '\\';
371261d06d6bSBaptiste Daroussin else {
371361d06d6bSBaptiste Daroussin r->escape = *p;
371461d06d6bSBaptiste Daroussin if (*++p != '\0')
37157295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_EXCESS, ln,
37167295610fSBaptiste Daroussin (int)(p - buf->buf), "ec ... %s", p);
371761d06d6bSBaptiste Daroussin }
371861d06d6bSBaptiste Daroussin return ROFF_IGN;
371961d06d6bSBaptiste Daroussin }
372061d06d6bSBaptiste Daroussin
37217295610fSBaptiste Daroussin static int
roff_eo(ROFF_ARGS)372261d06d6bSBaptiste Daroussin roff_eo(ROFF_ARGS)
372361d06d6bSBaptiste Daroussin {
372461d06d6bSBaptiste Daroussin r->escape = '\0';
372561d06d6bSBaptiste Daroussin if (buf->buf[pos] != '\0')
37267295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_SKIP,
372761d06d6bSBaptiste Daroussin ln, pos, "eo %s", buf->buf + pos);
372861d06d6bSBaptiste Daroussin return ROFF_IGN;
372961d06d6bSBaptiste Daroussin }
373061d06d6bSBaptiste Daroussin
37317295610fSBaptiste Daroussin static int
roff_nop(ROFF_ARGS)37327295610fSBaptiste Daroussin roff_nop(ROFF_ARGS)
37337295610fSBaptiste Daroussin {
37347295610fSBaptiste Daroussin while (buf->buf[pos] == ' ')
37357295610fSBaptiste Daroussin pos++;
37367295610fSBaptiste Daroussin *offs = pos;
37377295610fSBaptiste Daroussin return ROFF_RERUN;
37387295610fSBaptiste Daroussin }
37397295610fSBaptiste Daroussin
37407295610fSBaptiste Daroussin static int
roff_tr(ROFF_ARGS)374161d06d6bSBaptiste Daroussin roff_tr(ROFF_ARGS)
374261d06d6bSBaptiste Daroussin {
374361d06d6bSBaptiste Daroussin const char *p, *first, *second;
374461d06d6bSBaptiste Daroussin size_t fsz, ssz;
374561d06d6bSBaptiste Daroussin enum mandoc_esc esc;
374661d06d6bSBaptiste Daroussin
374761d06d6bSBaptiste Daroussin p = buf->buf + pos;
374861d06d6bSBaptiste Daroussin
374961d06d6bSBaptiste Daroussin if (*p == '\0') {
37507295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_REQ_EMPTY, ln, ppos, "tr");
375161d06d6bSBaptiste Daroussin return ROFF_IGN;
375261d06d6bSBaptiste Daroussin }
375361d06d6bSBaptiste Daroussin
375461d06d6bSBaptiste Daroussin while (*p != '\0') {
375561d06d6bSBaptiste Daroussin fsz = ssz = 1;
375661d06d6bSBaptiste Daroussin
375761d06d6bSBaptiste Daroussin first = p++;
375861d06d6bSBaptiste Daroussin if (*first == '\\') {
375961d06d6bSBaptiste Daroussin esc = mandoc_escape(&p, NULL, NULL);
376061d06d6bSBaptiste Daroussin if (esc == ESCAPE_ERROR) {
37617295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ESC_BAD, ln,
37627295610fSBaptiste Daroussin (int)(p - buf->buf), "%s", first);
376361d06d6bSBaptiste Daroussin return ROFF_IGN;
376461d06d6bSBaptiste Daroussin }
376561d06d6bSBaptiste Daroussin fsz = (size_t)(p - first);
376661d06d6bSBaptiste Daroussin }
376761d06d6bSBaptiste Daroussin
376861d06d6bSBaptiste Daroussin second = p++;
376961d06d6bSBaptiste Daroussin if (*second == '\\') {
377061d06d6bSBaptiste Daroussin esc = mandoc_escape(&p, NULL, NULL);
377161d06d6bSBaptiste Daroussin if (esc == ESCAPE_ERROR) {
37727295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ESC_BAD, ln,
37737295610fSBaptiste Daroussin (int)(p - buf->buf), "%s", second);
377461d06d6bSBaptiste Daroussin return ROFF_IGN;
377561d06d6bSBaptiste Daroussin }
377661d06d6bSBaptiste Daroussin ssz = (size_t)(p - second);
377761d06d6bSBaptiste Daroussin } else if (*second == '\0') {
37787295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_TR_ODD, ln,
37797295610fSBaptiste Daroussin (int)(first - buf->buf), "tr %s", first);
378061d06d6bSBaptiste Daroussin second = " ";
378161d06d6bSBaptiste Daroussin p--;
378261d06d6bSBaptiste Daroussin }
378361d06d6bSBaptiste Daroussin
378461d06d6bSBaptiste Daroussin if (fsz > 1) {
378561d06d6bSBaptiste Daroussin roff_setstrn(&r->xmbtab, first, fsz,
378661d06d6bSBaptiste Daroussin second, ssz, 0);
378761d06d6bSBaptiste Daroussin continue;
378861d06d6bSBaptiste Daroussin }
378961d06d6bSBaptiste Daroussin
379061d06d6bSBaptiste Daroussin if (r->xtab == NULL)
379161d06d6bSBaptiste Daroussin r->xtab = mandoc_calloc(128,
379261d06d6bSBaptiste Daroussin sizeof(struct roffstr));
379361d06d6bSBaptiste Daroussin
379461d06d6bSBaptiste Daroussin free(r->xtab[(int)*first].p);
379561d06d6bSBaptiste Daroussin r->xtab[(int)*first].p = mandoc_strndup(second, ssz);
379661d06d6bSBaptiste Daroussin r->xtab[(int)*first].sz = ssz;
379761d06d6bSBaptiste Daroussin }
379861d06d6bSBaptiste Daroussin
379961d06d6bSBaptiste Daroussin return ROFF_IGN;
380061d06d6bSBaptiste Daroussin }
380161d06d6bSBaptiste Daroussin
38027295610fSBaptiste Daroussin /*
38037295610fSBaptiste Daroussin * Implementation of the .return request.
38047295610fSBaptiste Daroussin * There is no need to call roff_userret() from here.
38057295610fSBaptiste Daroussin * The read module will call that after rewinding the reader stack
38067295610fSBaptiste Daroussin * to the place from where the current macro was called.
38077295610fSBaptiste Daroussin */
38087295610fSBaptiste Daroussin static int
roff_return(ROFF_ARGS)38097295610fSBaptiste Daroussin roff_return(ROFF_ARGS)
38107295610fSBaptiste Daroussin {
38117295610fSBaptiste Daroussin if (r->mstackpos >= 0)
38127295610fSBaptiste Daroussin return ROFF_IGN | ROFF_USERRET;
38137295610fSBaptiste Daroussin
38147295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_REQ_NOMAC, ln, ppos, "return");
38157295610fSBaptiste Daroussin return ROFF_IGN;
38167295610fSBaptiste Daroussin }
38177295610fSBaptiste Daroussin
38187295610fSBaptiste Daroussin static int
roff_rn(ROFF_ARGS)381961d06d6bSBaptiste Daroussin roff_rn(ROFF_ARGS)
382061d06d6bSBaptiste Daroussin {
382161d06d6bSBaptiste Daroussin const char *value;
382261d06d6bSBaptiste Daroussin char *oldn, *newn, *end;
382361d06d6bSBaptiste Daroussin size_t oldsz, newsz;
382461d06d6bSBaptiste Daroussin int deftype;
382561d06d6bSBaptiste Daroussin
382661d06d6bSBaptiste Daroussin oldn = newn = buf->buf + pos;
382761d06d6bSBaptiste Daroussin if (*oldn == '\0')
382861d06d6bSBaptiste Daroussin return ROFF_IGN;
382961d06d6bSBaptiste Daroussin
383061d06d6bSBaptiste Daroussin oldsz = roff_getname(r, &newn, ln, pos);
38317295610fSBaptiste Daroussin if (oldn[oldsz] == '\\' || oldn[oldsz] == '\t' || *newn == '\0')
383261d06d6bSBaptiste Daroussin return ROFF_IGN;
383361d06d6bSBaptiste Daroussin
383461d06d6bSBaptiste Daroussin end = newn;
383561d06d6bSBaptiste Daroussin newsz = roff_getname(r, &end, ln, newn - buf->buf);
383661d06d6bSBaptiste Daroussin if (newsz == 0)
383761d06d6bSBaptiste Daroussin return ROFF_IGN;
383861d06d6bSBaptiste Daroussin
383961d06d6bSBaptiste Daroussin deftype = ROFFDEF_ANY;
384061d06d6bSBaptiste Daroussin value = roff_getstrn(r, oldn, oldsz, &deftype);
384161d06d6bSBaptiste Daroussin switch (deftype) {
384261d06d6bSBaptiste Daroussin case ROFFDEF_USER:
384361d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, newn, newsz, value, strlen(value), 0);
384461d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, oldn, oldsz, NULL, 0, 0);
384561d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0);
384661d06d6bSBaptiste Daroussin break;
384761d06d6bSBaptiste Daroussin case ROFFDEF_PRE:
384861d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, newn, newsz, value, strlen(value), 0);
384961d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0);
385061d06d6bSBaptiste Daroussin break;
385161d06d6bSBaptiste Daroussin case ROFFDEF_REN:
385261d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, newn, newsz, value, strlen(value), 0);
385361d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, oldn, oldsz, NULL, 0, 0);
385461d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, newn, newsz, NULL, 0, 0);
385561d06d6bSBaptiste Daroussin break;
385661d06d6bSBaptiste Daroussin case ROFFDEF_STD:
385761d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, newn, newsz, oldn, oldsz, 0);
385861d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, newn, newsz, NULL, 0, 0);
385961d06d6bSBaptiste Daroussin break;
386061d06d6bSBaptiste Daroussin default:
386161d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, newn, newsz, NULL, 0, 0);
386261d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0);
386361d06d6bSBaptiste Daroussin break;
386461d06d6bSBaptiste Daroussin }
386561d06d6bSBaptiste Daroussin return ROFF_IGN;
386661d06d6bSBaptiste Daroussin }
386761d06d6bSBaptiste Daroussin
38687295610fSBaptiste Daroussin static int
roff_shift(ROFF_ARGS)38697295610fSBaptiste Daroussin roff_shift(ROFF_ARGS)
38707295610fSBaptiste Daroussin {
38717295610fSBaptiste Daroussin struct mctx *ctx;
38727295610fSBaptiste Daroussin int levels, i;
38737295610fSBaptiste Daroussin
38747295610fSBaptiste Daroussin levels = 1;
38757295610fSBaptiste Daroussin if (buf->buf[pos] != '\0' &&
38767295610fSBaptiste Daroussin roff_evalnum(r, ln, buf->buf, &pos, &levels, 0) == 0) {
38777295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_CE_NONUM,
38787295610fSBaptiste Daroussin ln, pos, "shift %s", buf->buf + pos);
38797295610fSBaptiste Daroussin levels = 1;
38807295610fSBaptiste Daroussin }
38817295610fSBaptiste Daroussin if (r->mstackpos < 0) {
38827295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_REQ_NOMAC, ln, ppos, "shift");
38837295610fSBaptiste Daroussin return ROFF_IGN;
38847295610fSBaptiste Daroussin }
38857295610fSBaptiste Daroussin ctx = r->mstack + r->mstackpos;
38867295610fSBaptiste Daroussin if (levels > ctx->argc) {
38877295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_SHIFT,
38887295610fSBaptiste Daroussin ln, pos, "%d, but max is %d", levels, ctx->argc);
38897295610fSBaptiste Daroussin levels = ctx->argc;
38907295610fSBaptiste Daroussin }
38917295610fSBaptiste Daroussin if (levels == 0)
38927295610fSBaptiste Daroussin return ROFF_IGN;
38937295610fSBaptiste Daroussin for (i = 0; i < levels; i++)
38947295610fSBaptiste Daroussin free(ctx->argv[i]);
38957295610fSBaptiste Daroussin ctx->argc -= levels;
38967295610fSBaptiste Daroussin for (i = 0; i < ctx->argc; i++)
38977295610fSBaptiste Daroussin ctx->argv[i] = ctx->argv[i + levels];
38987295610fSBaptiste Daroussin return ROFF_IGN;
38997295610fSBaptiste Daroussin }
39007295610fSBaptiste Daroussin
39017295610fSBaptiste Daroussin static int
roff_so(ROFF_ARGS)390261d06d6bSBaptiste Daroussin roff_so(ROFF_ARGS)
390361d06d6bSBaptiste Daroussin {
390461d06d6bSBaptiste Daroussin char *name, *cp;
390561d06d6bSBaptiste Daroussin
390661d06d6bSBaptiste Daroussin name = buf->buf + pos;
39077295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_SO, ln, ppos, "so %s", name);
390861d06d6bSBaptiste Daroussin
390961d06d6bSBaptiste Daroussin /*
391061d06d6bSBaptiste Daroussin * Handle `so'. Be EXTREMELY careful, as we shouldn't be
391161d06d6bSBaptiste Daroussin * opening anything that's not in our cwd or anything beneath
391261d06d6bSBaptiste Daroussin * it. Thus, explicitly disallow traversing up the file-system
391361d06d6bSBaptiste Daroussin * or using absolute paths.
391461d06d6bSBaptiste Daroussin */
391561d06d6bSBaptiste Daroussin
391661d06d6bSBaptiste Daroussin if (*name == '/' || strstr(name, "../") || strstr(name, "/..")) {
39177295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_SO_PATH, ln, ppos, ".so %s", name);
391861d06d6bSBaptiste Daroussin buf->sz = mandoc_asprintf(&cp,
391961d06d6bSBaptiste Daroussin ".sp\nSee the file %s.\n.sp", name) + 1;
392061d06d6bSBaptiste Daroussin free(buf->buf);
392161d06d6bSBaptiste Daroussin buf->buf = cp;
392261d06d6bSBaptiste Daroussin *offs = 0;
392361d06d6bSBaptiste Daroussin return ROFF_REPARSE;
392461d06d6bSBaptiste Daroussin }
392561d06d6bSBaptiste Daroussin
392661d06d6bSBaptiste Daroussin *offs = pos;
392761d06d6bSBaptiste Daroussin return ROFF_SO;
392861d06d6bSBaptiste Daroussin }
392961d06d6bSBaptiste Daroussin
393061d06d6bSBaptiste Daroussin /* --- user defined strings and macros ------------------------------------ */
393161d06d6bSBaptiste Daroussin
39327295610fSBaptiste Daroussin static int
roff_userdef(ROFF_ARGS)393361d06d6bSBaptiste Daroussin roff_userdef(ROFF_ARGS)
393461d06d6bSBaptiste Daroussin {
39357295610fSBaptiste Daroussin struct mctx *ctx;
39367295610fSBaptiste Daroussin char *arg, *ap, *dst, *src;
39377295610fSBaptiste Daroussin size_t sz;
393861d06d6bSBaptiste Daroussin
393945a5aec3SBaptiste Daroussin /* If the macro is empty, ignore it altogether. */
394045a5aec3SBaptiste Daroussin
394145a5aec3SBaptiste Daroussin if (*r->current_string == '\0')
394245a5aec3SBaptiste Daroussin return ROFF_IGN;
394345a5aec3SBaptiste Daroussin
39447295610fSBaptiste Daroussin /* Initialize a new macro stack context. */
394561d06d6bSBaptiste Daroussin
39467295610fSBaptiste Daroussin if (++r->mstackpos == r->mstacksz) {
39477295610fSBaptiste Daroussin r->mstack = mandoc_recallocarray(r->mstack,
39487295610fSBaptiste Daroussin r->mstacksz, r->mstacksz + 8, sizeof(*r->mstack));
39497295610fSBaptiste Daroussin r->mstacksz += 8;
395061d06d6bSBaptiste Daroussin }
39517295610fSBaptiste Daroussin ctx = r->mstack + r->mstackpos;
39527295610fSBaptiste Daroussin ctx->argsz = 0;
39537295610fSBaptiste Daroussin ctx->argc = 0;
39547295610fSBaptiste Daroussin ctx->argv = NULL;
39557295610fSBaptiste Daroussin
39567295610fSBaptiste Daroussin /*
39577295610fSBaptiste Daroussin * Collect pointers to macro argument strings,
39587295610fSBaptiste Daroussin * NUL-terminating them and escaping quotes.
39597295610fSBaptiste Daroussin */
39607295610fSBaptiste Daroussin
39617295610fSBaptiste Daroussin src = buf->buf + pos;
39627295610fSBaptiste Daroussin while (*src != '\0') {
39637295610fSBaptiste Daroussin if (ctx->argc == ctx->argsz) {
39647295610fSBaptiste Daroussin ctx->argsz += 8;
39657295610fSBaptiste Daroussin ctx->argv = mandoc_reallocarray(ctx->argv,
39667295610fSBaptiste Daroussin ctx->argsz, sizeof(*ctx->argv));
396761d06d6bSBaptiste Daroussin }
39687295610fSBaptiste Daroussin arg = roff_getarg(r, &src, ln, &pos);
39697295610fSBaptiste Daroussin sz = 1; /* For the terminating NUL. */
39707295610fSBaptiste Daroussin for (ap = arg; *ap != '\0'; ap++)
39717295610fSBaptiste Daroussin sz += *ap == '"' ? 4 : 1;
39727295610fSBaptiste Daroussin ctx->argv[ctx->argc++] = dst = mandoc_malloc(sz);
39737295610fSBaptiste Daroussin for (ap = arg; *ap != '\0'; ap++) {
397461d06d6bSBaptiste Daroussin if (*ap == '"') {
39757295610fSBaptiste Daroussin memcpy(dst, "\\(dq", 4);
39767295610fSBaptiste Daroussin dst += 4;
397761d06d6bSBaptiste Daroussin } else
39787295610fSBaptiste Daroussin *dst++ = *ap;
397961d06d6bSBaptiste Daroussin }
39807295610fSBaptiste Daroussin *dst = '\0';
39817295610fSBaptiste Daroussin free(arg);
398261d06d6bSBaptiste Daroussin }
398361d06d6bSBaptiste Daroussin
39847295610fSBaptiste Daroussin /* Replace the macro invocation by the macro definition. */
398561d06d6bSBaptiste Daroussin
398661d06d6bSBaptiste Daroussin free(buf->buf);
39877295610fSBaptiste Daroussin buf->buf = mandoc_strdup(r->current_string);
39887295610fSBaptiste Daroussin buf->sz = strlen(buf->buf) + 1;
398961d06d6bSBaptiste Daroussin *offs = 0;
399061d06d6bSBaptiste Daroussin
399145a5aec3SBaptiste Daroussin return buf->buf[buf->sz - 2] == '\n' ?
39927295610fSBaptiste Daroussin ROFF_REPARSE | ROFF_USERCALL : ROFF_IGN | ROFF_APPEND;
399361d06d6bSBaptiste Daroussin }
399461d06d6bSBaptiste Daroussin
399561d06d6bSBaptiste Daroussin /*
399661d06d6bSBaptiste Daroussin * Calling a high-level macro that was renamed with .rn.
399761d06d6bSBaptiste Daroussin * r->current_string has already been set up by roff_parse().
399861d06d6bSBaptiste Daroussin */
39997295610fSBaptiste Daroussin static int
roff_renamed(ROFF_ARGS)400061d06d6bSBaptiste Daroussin roff_renamed(ROFF_ARGS)
400161d06d6bSBaptiste Daroussin {
400261d06d6bSBaptiste Daroussin char *nbuf;
400361d06d6bSBaptiste Daroussin
400461d06d6bSBaptiste Daroussin buf->sz = mandoc_asprintf(&nbuf, ".%s%s%s", r->current_string,
400561d06d6bSBaptiste Daroussin buf->buf[pos] == '\0' ? "" : " ", buf->buf + pos) + 1;
400661d06d6bSBaptiste Daroussin free(buf->buf);
400761d06d6bSBaptiste Daroussin buf->buf = nbuf;
400861d06d6bSBaptiste Daroussin *offs = 0;
400961d06d6bSBaptiste Daroussin return ROFF_CONT;
401061d06d6bSBaptiste Daroussin }
401161d06d6bSBaptiste Daroussin
40127295610fSBaptiste Daroussin /*
40137295610fSBaptiste Daroussin * Measure the length in bytes of the roff identifier at *cpp
40147295610fSBaptiste Daroussin * and advance the pointer to the next word.
40157295610fSBaptiste Daroussin */
401661d06d6bSBaptiste Daroussin static size_t
roff_getname(struct roff * r,char ** cpp,int ln,int pos)401761d06d6bSBaptiste Daroussin roff_getname(struct roff *r, char **cpp, int ln, int pos)
401861d06d6bSBaptiste Daroussin {
401961d06d6bSBaptiste Daroussin char *name, *cp;
402061d06d6bSBaptiste Daroussin size_t namesz;
402161d06d6bSBaptiste Daroussin
402261d06d6bSBaptiste Daroussin name = *cpp;
40237295610fSBaptiste Daroussin if (*name == '\0')
402461d06d6bSBaptiste Daroussin return 0;
402561d06d6bSBaptiste Daroussin
40267295610fSBaptiste Daroussin /* Advance cp to the byte after the end of the name. */
40277295610fSBaptiste Daroussin
402861d06d6bSBaptiste Daroussin for (cp = name; 1; cp++) {
402961d06d6bSBaptiste Daroussin namesz = cp - name;
40307295610fSBaptiste Daroussin if (*cp == '\0')
40317295610fSBaptiste Daroussin break;
40327295610fSBaptiste Daroussin if (*cp == ' ' || *cp == '\t') {
40337295610fSBaptiste Daroussin cp++;
403461d06d6bSBaptiste Daroussin break;
403561d06d6bSBaptiste Daroussin }
40367295610fSBaptiste Daroussin if (*cp != '\\')
403761d06d6bSBaptiste Daroussin continue;
40387295610fSBaptiste Daroussin if (cp[1] == '{' || cp[1] == '}')
403961d06d6bSBaptiste Daroussin break;
40407295610fSBaptiste Daroussin if (*++cp == '\\')
404161d06d6bSBaptiste Daroussin continue;
40427295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_NAMESC, ln, pos,
404361d06d6bSBaptiste Daroussin "%.*s", (int)(cp - name + 1), name);
404461d06d6bSBaptiste Daroussin mandoc_escape((const char **)&cp, NULL, NULL);
404561d06d6bSBaptiste Daroussin break;
404661d06d6bSBaptiste Daroussin }
404761d06d6bSBaptiste Daroussin
404861d06d6bSBaptiste Daroussin /* Read past spaces. */
40497295610fSBaptiste Daroussin
40507295610fSBaptiste Daroussin while (*cp == ' ')
405161d06d6bSBaptiste Daroussin cp++;
405261d06d6bSBaptiste Daroussin
405361d06d6bSBaptiste Daroussin *cpp = cp;
405461d06d6bSBaptiste Daroussin return namesz;
405561d06d6bSBaptiste Daroussin }
405661d06d6bSBaptiste Daroussin
405761d06d6bSBaptiste Daroussin /*
405861d06d6bSBaptiste Daroussin * Store *string into the user-defined string called *name.
405961d06d6bSBaptiste Daroussin * To clear an existing entry, call with (*r, *name, NULL, 0).
406061d06d6bSBaptiste Daroussin * append == 0: replace mode
406161d06d6bSBaptiste Daroussin * append == 1: single-line append mode
406261d06d6bSBaptiste Daroussin * append == 2: multiline append mode, append '\n' after each call
406361d06d6bSBaptiste Daroussin */
406461d06d6bSBaptiste Daroussin static void
roff_setstr(struct roff * r,const char * name,const char * string,int append)406561d06d6bSBaptiste Daroussin roff_setstr(struct roff *r, const char *name, const char *string,
406661d06d6bSBaptiste Daroussin int append)
406761d06d6bSBaptiste Daroussin {
406861d06d6bSBaptiste Daroussin size_t namesz;
406961d06d6bSBaptiste Daroussin
407061d06d6bSBaptiste Daroussin namesz = strlen(name);
407161d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, name, namesz, string,
407261d06d6bSBaptiste Daroussin string ? strlen(string) : 0, append);
407361d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0);
407461d06d6bSBaptiste Daroussin }
407561d06d6bSBaptiste Daroussin
407661d06d6bSBaptiste Daroussin static void
roff_setstrn(struct roffkv ** r,const char * name,size_t namesz,const char * string,size_t stringsz,int append)407761d06d6bSBaptiste Daroussin roff_setstrn(struct roffkv **r, const char *name, size_t namesz,
407861d06d6bSBaptiste Daroussin const char *string, size_t stringsz, int append)
407961d06d6bSBaptiste Daroussin {
408061d06d6bSBaptiste Daroussin struct roffkv *n;
408161d06d6bSBaptiste Daroussin char *c;
408261d06d6bSBaptiste Daroussin int i;
408361d06d6bSBaptiste Daroussin size_t oldch, newch;
408461d06d6bSBaptiste Daroussin
408561d06d6bSBaptiste Daroussin /* Search for an existing string with the same name. */
408661d06d6bSBaptiste Daroussin n = *r;
408761d06d6bSBaptiste Daroussin
408861d06d6bSBaptiste Daroussin while (n && (namesz != n->key.sz ||
408961d06d6bSBaptiste Daroussin strncmp(n->key.p, name, namesz)))
409061d06d6bSBaptiste Daroussin n = n->next;
409161d06d6bSBaptiste Daroussin
409261d06d6bSBaptiste Daroussin if (NULL == n) {
409361d06d6bSBaptiste Daroussin /* Create a new string table entry. */
409461d06d6bSBaptiste Daroussin n = mandoc_malloc(sizeof(struct roffkv));
409561d06d6bSBaptiste Daroussin n->key.p = mandoc_strndup(name, namesz);
409661d06d6bSBaptiste Daroussin n->key.sz = namesz;
409761d06d6bSBaptiste Daroussin n->val.p = NULL;
409861d06d6bSBaptiste Daroussin n->val.sz = 0;
409961d06d6bSBaptiste Daroussin n->next = *r;
410061d06d6bSBaptiste Daroussin *r = n;
410161d06d6bSBaptiste Daroussin } else if (0 == append) {
410261d06d6bSBaptiste Daroussin free(n->val.p);
410361d06d6bSBaptiste Daroussin n->val.p = NULL;
410461d06d6bSBaptiste Daroussin n->val.sz = 0;
410561d06d6bSBaptiste Daroussin }
410661d06d6bSBaptiste Daroussin
410761d06d6bSBaptiste Daroussin if (NULL == string)
410861d06d6bSBaptiste Daroussin return;
410961d06d6bSBaptiste Daroussin
411061d06d6bSBaptiste Daroussin /*
411161d06d6bSBaptiste Daroussin * One additional byte for the '\n' in multiline mode,
411261d06d6bSBaptiste Daroussin * and one for the terminating '\0'.
411361d06d6bSBaptiste Daroussin */
411461d06d6bSBaptiste Daroussin newch = stringsz + (1 < append ? 2u : 1u);
411561d06d6bSBaptiste Daroussin
411661d06d6bSBaptiste Daroussin if (NULL == n->val.p) {
411761d06d6bSBaptiste Daroussin n->val.p = mandoc_malloc(newch);
411861d06d6bSBaptiste Daroussin *n->val.p = '\0';
411961d06d6bSBaptiste Daroussin oldch = 0;
412061d06d6bSBaptiste Daroussin } else {
412161d06d6bSBaptiste Daroussin oldch = n->val.sz;
412261d06d6bSBaptiste Daroussin n->val.p = mandoc_realloc(n->val.p, oldch + newch);
412361d06d6bSBaptiste Daroussin }
412461d06d6bSBaptiste Daroussin
412561d06d6bSBaptiste Daroussin /* Skip existing content in the destination buffer. */
412661d06d6bSBaptiste Daroussin c = n->val.p + (int)oldch;
412761d06d6bSBaptiste Daroussin
412861d06d6bSBaptiste Daroussin /* Append new content to the destination buffer. */
412961d06d6bSBaptiste Daroussin i = 0;
413061d06d6bSBaptiste Daroussin while (i < (int)stringsz) {
413161d06d6bSBaptiste Daroussin /*
413261d06d6bSBaptiste Daroussin * Rudimentary roff copy mode:
413361d06d6bSBaptiste Daroussin * Handle escaped backslashes.
413461d06d6bSBaptiste Daroussin */
413561d06d6bSBaptiste Daroussin if ('\\' == string[i] && '\\' == string[i + 1])
413661d06d6bSBaptiste Daroussin i++;
413761d06d6bSBaptiste Daroussin *c++ = string[i++];
413861d06d6bSBaptiste Daroussin }
413961d06d6bSBaptiste Daroussin
414061d06d6bSBaptiste Daroussin /* Append terminating bytes. */
414161d06d6bSBaptiste Daroussin if (1 < append)
414261d06d6bSBaptiste Daroussin *c++ = '\n';
414361d06d6bSBaptiste Daroussin
414461d06d6bSBaptiste Daroussin *c = '\0';
414561d06d6bSBaptiste Daroussin n->val.sz = (int)(c - n->val.p);
414661d06d6bSBaptiste Daroussin }
414761d06d6bSBaptiste Daroussin
414861d06d6bSBaptiste Daroussin static const char *
roff_getstrn(struct roff * r,const char * name,size_t len,int * deftype)414961d06d6bSBaptiste Daroussin roff_getstrn(struct roff *r, const char *name, size_t len,
415061d06d6bSBaptiste Daroussin int *deftype)
415161d06d6bSBaptiste Daroussin {
415261d06d6bSBaptiste Daroussin const struct roffkv *n;
415361d06d6bSBaptiste Daroussin int found, i;
415461d06d6bSBaptiste Daroussin enum roff_tok tok;
415561d06d6bSBaptiste Daroussin
415661d06d6bSBaptiste Daroussin found = 0;
415761d06d6bSBaptiste Daroussin for (n = r->strtab; n != NULL; n = n->next) {
415861d06d6bSBaptiste Daroussin if (strncmp(name, n->key.p, len) != 0 ||
415961d06d6bSBaptiste Daroussin n->key.p[len] != '\0' || n->val.p == NULL)
416061d06d6bSBaptiste Daroussin continue;
416161d06d6bSBaptiste Daroussin if (*deftype & ROFFDEF_USER) {
416261d06d6bSBaptiste Daroussin *deftype = ROFFDEF_USER;
416361d06d6bSBaptiste Daroussin return n->val.p;
416461d06d6bSBaptiste Daroussin } else {
416561d06d6bSBaptiste Daroussin found = 1;
416661d06d6bSBaptiste Daroussin break;
416761d06d6bSBaptiste Daroussin }
416861d06d6bSBaptiste Daroussin }
416961d06d6bSBaptiste Daroussin for (n = r->rentab; n != NULL; n = n->next) {
417061d06d6bSBaptiste Daroussin if (strncmp(name, n->key.p, len) != 0 ||
417161d06d6bSBaptiste Daroussin n->key.p[len] != '\0' || n->val.p == NULL)
417261d06d6bSBaptiste Daroussin continue;
417361d06d6bSBaptiste Daroussin if (*deftype & ROFFDEF_REN) {
417461d06d6bSBaptiste Daroussin *deftype = ROFFDEF_REN;
417561d06d6bSBaptiste Daroussin return n->val.p;
417661d06d6bSBaptiste Daroussin } else {
417761d06d6bSBaptiste Daroussin found = 1;
417861d06d6bSBaptiste Daroussin break;
417961d06d6bSBaptiste Daroussin }
418061d06d6bSBaptiste Daroussin }
418161d06d6bSBaptiste Daroussin for (i = 0; i < PREDEFS_MAX; i++) {
418261d06d6bSBaptiste Daroussin if (strncmp(name, predefs[i].name, len) != 0 ||
418361d06d6bSBaptiste Daroussin predefs[i].name[len] != '\0')
418461d06d6bSBaptiste Daroussin continue;
418561d06d6bSBaptiste Daroussin if (*deftype & ROFFDEF_PRE) {
418661d06d6bSBaptiste Daroussin *deftype = ROFFDEF_PRE;
418761d06d6bSBaptiste Daroussin return predefs[i].str;
418861d06d6bSBaptiste Daroussin } else {
418961d06d6bSBaptiste Daroussin found = 1;
419061d06d6bSBaptiste Daroussin break;
419161d06d6bSBaptiste Daroussin }
419261d06d6bSBaptiste Daroussin }
41937295610fSBaptiste Daroussin if (r->man->meta.macroset != MACROSET_MAN) {
419461d06d6bSBaptiste Daroussin for (tok = MDOC_Dd; tok < MDOC_MAX; tok++) {
419561d06d6bSBaptiste Daroussin if (strncmp(name, roff_name[tok], len) != 0 ||
419661d06d6bSBaptiste Daroussin roff_name[tok][len] != '\0')
419761d06d6bSBaptiste Daroussin continue;
419861d06d6bSBaptiste Daroussin if (*deftype & ROFFDEF_STD) {
419961d06d6bSBaptiste Daroussin *deftype = ROFFDEF_STD;
420061d06d6bSBaptiste Daroussin return NULL;
420161d06d6bSBaptiste Daroussin } else {
420261d06d6bSBaptiste Daroussin found = 1;
420361d06d6bSBaptiste Daroussin break;
420461d06d6bSBaptiste Daroussin }
420561d06d6bSBaptiste Daroussin }
420661d06d6bSBaptiste Daroussin }
42077295610fSBaptiste Daroussin if (r->man->meta.macroset != MACROSET_MDOC) {
420861d06d6bSBaptiste Daroussin for (tok = MAN_TH; tok < MAN_MAX; tok++) {
420961d06d6bSBaptiste Daroussin if (strncmp(name, roff_name[tok], len) != 0 ||
421061d06d6bSBaptiste Daroussin roff_name[tok][len] != '\0')
421161d06d6bSBaptiste Daroussin continue;
421261d06d6bSBaptiste Daroussin if (*deftype & ROFFDEF_STD) {
421361d06d6bSBaptiste Daroussin *deftype = ROFFDEF_STD;
421461d06d6bSBaptiste Daroussin return NULL;
421561d06d6bSBaptiste Daroussin } else {
421661d06d6bSBaptiste Daroussin found = 1;
421761d06d6bSBaptiste Daroussin break;
421861d06d6bSBaptiste Daroussin }
421961d06d6bSBaptiste Daroussin }
422061d06d6bSBaptiste Daroussin }
422161d06d6bSBaptiste Daroussin
422261d06d6bSBaptiste Daroussin if (found == 0 && *deftype != ROFFDEF_ANY) {
422361d06d6bSBaptiste Daroussin if (*deftype & ROFFDEF_REN) {
422461d06d6bSBaptiste Daroussin /*
422561d06d6bSBaptiste Daroussin * This might still be a request,
422661d06d6bSBaptiste Daroussin * so do not treat it as undefined yet.
422761d06d6bSBaptiste Daroussin */
422861d06d6bSBaptiste Daroussin *deftype = ROFFDEF_UNDEF;
422961d06d6bSBaptiste Daroussin return NULL;
423061d06d6bSBaptiste Daroussin }
423161d06d6bSBaptiste Daroussin
423261d06d6bSBaptiste Daroussin /* Using an undefined string defines it to be empty. */
423361d06d6bSBaptiste Daroussin
423461d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, name, len, "", 0, 0);
423561d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, name, len, NULL, 0, 0);
423661d06d6bSBaptiste Daroussin }
423761d06d6bSBaptiste Daroussin
423861d06d6bSBaptiste Daroussin *deftype = 0;
423961d06d6bSBaptiste Daroussin return NULL;
424061d06d6bSBaptiste Daroussin }
424161d06d6bSBaptiste Daroussin
424261d06d6bSBaptiste Daroussin static void
roff_freestr(struct roffkv * r)424361d06d6bSBaptiste Daroussin roff_freestr(struct roffkv *r)
424461d06d6bSBaptiste Daroussin {
424561d06d6bSBaptiste Daroussin struct roffkv *n, *nn;
424661d06d6bSBaptiste Daroussin
424761d06d6bSBaptiste Daroussin for (n = r; n; n = nn) {
424861d06d6bSBaptiste Daroussin free(n->key.p);
424961d06d6bSBaptiste Daroussin free(n->val.p);
425061d06d6bSBaptiste Daroussin nn = n->next;
425161d06d6bSBaptiste Daroussin free(n);
425261d06d6bSBaptiste Daroussin }
425361d06d6bSBaptiste Daroussin }
425461d06d6bSBaptiste Daroussin
425561d06d6bSBaptiste Daroussin /* --- accessors and utility functions ------------------------------------ */
425661d06d6bSBaptiste Daroussin
425761d06d6bSBaptiste Daroussin /*
425861d06d6bSBaptiste Daroussin * Duplicate an input string, making the appropriate character
425961d06d6bSBaptiste Daroussin * conversations (as stipulated by `tr') along the way.
426061d06d6bSBaptiste Daroussin * Returns a heap-allocated string with all the replacements made.
426161d06d6bSBaptiste Daroussin */
426261d06d6bSBaptiste Daroussin char *
roff_strdup(const struct roff * r,const char * p)426361d06d6bSBaptiste Daroussin roff_strdup(const struct roff *r, const char *p)
426461d06d6bSBaptiste Daroussin {
426561d06d6bSBaptiste Daroussin const struct roffkv *cp;
426661d06d6bSBaptiste Daroussin char *res;
426761d06d6bSBaptiste Daroussin const char *pp;
426861d06d6bSBaptiste Daroussin size_t ssz, sz;
426961d06d6bSBaptiste Daroussin enum mandoc_esc esc;
427061d06d6bSBaptiste Daroussin
427161d06d6bSBaptiste Daroussin if (NULL == r->xmbtab && NULL == r->xtab)
427261d06d6bSBaptiste Daroussin return mandoc_strdup(p);
427361d06d6bSBaptiste Daroussin else if ('\0' == *p)
427461d06d6bSBaptiste Daroussin return mandoc_strdup("");
427561d06d6bSBaptiste Daroussin
427661d06d6bSBaptiste Daroussin /*
427761d06d6bSBaptiste Daroussin * Step through each character looking for term matches
427861d06d6bSBaptiste Daroussin * (remember that a `tr' can be invoked with an escape, which is
427961d06d6bSBaptiste Daroussin * a glyph but the escape is multi-character).
428061d06d6bSBaptiste Daroussin * We only do this if the character hash has been initialised
428161d06d6bSBaptiste Daroussin * and the string is >0 length.
428261d06d6bSBaptiste Daroussin */
428361d06d6bSBaptiste Daroussin
428461d06d6bSBaptiste Daroussin res = NULL;
428561d06d6bSBaptiste Daroussin ssz = 0;
428661d06d6bSBaptiste Daroussin
428761d06d6bSBaptiste Daroussin while ('\0' != *p) {
428861d06d6bSBaptiste Daroussin assert((unsigned int)*p < 128);
428961d06d6bSBaptiste Daroussin if ('\\' != *p && r->xtab && r->xtab[(unsigned int)*p].p) {
429061d06d6bSBaptiste Daroussin sz = r->xtab[(int)*p].sz;
429161d06d6bSBaptiste Daroussin res = mandoc_realloc(res, ssz + sz + 1);
429261d06d6bSBaptiste Daroussin memcpy(res + ssz, r->xtab[(int)*p].p, sz);
429361d06d6bSBaptiste Daroussin ssz += sz;
429461d06d6bSBaptiste Daroussin p++;
429561d06d6bSBaptiste Daroussin continue;
429661d06d6bSBaptiste Daroussin } else if ('\\' != *p) {
429761d06d6bSBaptiste Daroussin res = mandoc_realloc(res, ssz + 2);
429861d06d6bSBaptiste Daroussin res[ssz++] = *p++;
429961d06d6bSBaptiste Daroussin continue;
430061d06d6bSBaptiste Daroussin }
430161d06d6bSBaptiste Daroussin
430261d06d6bSBaptiste Daroussin /* Search for term matches. */
430361d06d6bSBaptiste Daroussin for (cp = r->xmbtab; cp; cp = cp->next)
430461d06d6bSBaptiste Daroussin if (0 == strncmp(p, cp->key.p, cp->key.sz))
430561d06d6bSBaptiste Daroussin break;
430661d06d6bSBaptiste Daroussin
430761d06d6bSBaptiste Daroussin if (NULL != cp) {
430861d06d6bSBaptiste Daroussin /*
430961d06d6bSBaptiste Daroussin * A match has been found.
431061d06d6bSBaptiste Daroussin * Append the match to the array and move
431161d06d6bSBaptiste Daroussin * forward by its keysize.
431261d06d6bSBaptiste Daroussin */
431361d06d6bSBaptiste Daroussin res = mandoc_realloc(res,
431461d06d6bSBaptiste Daroussin ssz + cp->val.sz + 1);
431561d06d6bSBaptiste Daroussin memcpy(res + ssz, cp->val.p, cp->val.sz);
431661d06d6bSBaptiste Daroussin ssz += cp->val.sz;
431761d06d6bSBaptiste Daroussin p += (int)cp->key.sz;
431861d06d6bSBaptiste Daroussin continue;
431961d06d6bSBaptiste Daroussin }
432061d06d6bSBaptiste Daroussin
432161d06d6bSBaptiste Daroussin /*
432261d06d6bSBaptiste Daroussin * Handle escapes carefully: we need to copy
432361d06d6bSBaptiste Daroussin * over just the escape itself, or else we might
432461d06d6bSBaptiste Daroussin * do replacements within the escape itself.
432561d06d6bSBaptiste Daroussin * Make sure to pass along the bogus string.
432661d06d6bSBaptiste Daroussin */
432761d06d6bSBaptiste Daroussin pp = p++;
432861d06d6bSBaptiste Daroussin esc = mandoc_escape(&p, NULL, NULL);
432961d06d6bSBaptiste Daroussin if (ESCAPE_ERROR == esc) {
433061d06d6bSBaptiste Daroussin sz = strlen(pp);
433161d06d6bSBaptiste Daroussin res = mandoc_realloc(res, ssz + sz + 1);
433261d06d6bSBaptiste Daroussin memcpy(res + ssz, pp, sz);
433361d06d6bSBaptiste Daroussin break;
433461d06d6bSBaptiste Daroussin }
433561d06d6bSBaptiste Daroussin /*
433661d06d6bSBaptiste Daroussin * We bail out on bad escapes.
433761d06d6bSBaptiste Daroussin * No need to warn: we already did so when
43387295610fSBaptiste Daroussin * roff_expand() was called.
433961d06d6bSBaptiste Daroussin */
434061d06d6bSBaptiste Daroussin sz = (int)(p - pp);
434161d06d6bSBaptiste Daroussin res = mandoc_realloc(res, ssz + sz + 1);
434261d06d6bSBaptiste Daroussin memcpy(res + ssz, pp, sz);
434361d06d6bSBaptiste Daroussin ssz += sz;
434461d06d6bSBaptiste Daroussin }
434561d06d6bSBaptiste Daroussin
434661d06d6bSBaptiste Daroussin res[(int)ssz] = '\0';
434761d06d6bSBaptiste Daroussin return res;
434861d06d6bSBaptiste Daroussin }
434961d06d6bSBaptiste Daroussin
435061d06d6bSBaptiste Daroussin int
roff_getformat(const struct roff * r)435161d06d6bSBaptiste Daroussin roff_getformat(const struct roff *r)
435261d06d6bSBaptiste Daroussin {
435361d06d6bSBaptiste Daroussin
435461d06d6bSBaptiste Daroussin return r->format;
435561d06d6bSBaptiste Daroussin }
435661d06d6bSBaptiste Daroussin
435761d06d6bSBaptiste Daroussin /*
435861d06d6bSBaptiste Daroussin * Find out whether a line is a macro line or not.
435961d06d6bSBaptiste Daroussin * If it is, adjust the current position and return one; if it isn't,
436061d06d6bSBaptiste Daroussin * return zero and don't change the current position.
436161d06d6bSBaptiste Daroussin * If the control character has been set with `.cc', then let that grain
436261d06d6bSBaptiste Daroussin * precedence.
436361d06d6bSBaptiste Daroussin * This is slighly contrary to groff, where using the non-breaking
436461d06d6bSBaptiste Daroussin * control character when `cc' has been invoked will cause the
436561d06d6bSBaptiste Daroussin * non-breaking macro contents to be printed verbatim.
436661d06d6bSBaptiste Daroussin */
436761d06d6bSBaptiste Daroussin int
roff_getcontrol(const struct roff * r,const char * cp,int * ppos)436861d06d6bSBaptiste Daroussin roff_getcontrol(const struct roff *r, const char *cp, int *ppos)
436961d06d6bSBaptiste Daroussin {
437061d06d6bSBaptiste Daroussin int pos;
437161d06d6bSBaptiste Daroussin
437261d06d6bSBaptiste Daroussin pos = *ppos;
437361d06d6bSBaptiste Daroussin
437461d06d6bSBaptiste Daroussin if (r->control != '\0' && cp[pos] == r->control)
437561d06d6bSBaptiste Daroussin pos++;
437661d06d6bSBaptiste Daroussin else if (r->control != '\0')
437761d06d6bSBaptiste Daroussin return 0;
437861d06d6bSBaptiste Daroussin else if ('\\' == cp[pos] && '.' == cp[pos + 1])
437961d06d6bSBaptiste Daroussin pos += 2;
438061d06d6bSBaptiste Daroussin else if ('.' == cp[pos] || '\'' == cp[pos])
438161d06d6bSBaptiste Daroussin pos++;
438261d06d6bSBaptiste Daroussin else
438361d06d6bSBaptiste Daroussin return 0;
438461d06d6bSBaptiste Daroussin
438561d06d6bSBaptiste Daroussin while (' ' == cp[pos] || '\t' == cp[pos])
438661d06d6bSBaptiste Daroussin pos++;
438761d06d6bSBaptiste Daroussin
438861d06d6bSBaptiste Daroussin *ppos = pos;
438961d06d6bSBaptiste Daroussin return 1;
439061d06d6bSBaptiste Daroussin }
4391