1*61d06d6bSBaptiste Daroussin /* $Id: roff.c,v 1.329 2018/08/01 15:40:17 schwarze Exp $ */ 2*61d06d6bSBaptiste Daroussin /* 3*61d06d6bSBaptiste Daroussin * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv> 4*61d06d6bSBaptiste Daroussin * Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org> 5*61d06d6bSBaptiste Daroussin * 6*61d06d6bSBaptiste Daroussin * Permission to use, copy, modify, and distribute this software for any 7*61d06d6bSBaptiste Daroussin * purpose with or without fee is hereby granted, provided that the above 8*61d06d6bSBaptiste Daroussin * copyright notice and this permission notice appear in all copies. 9*61d06d6bSBaptiste Daroussin * 10*61d06d6bSBaptiste Daroussin * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES 11*61d06d6bSBaptiste Daroussin * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*61d06d6bSBaptiste Daroussin * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR 13*61d06d6bSBaptiste Daroussin * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14*61d06d6bSBaptiste Daroussin * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15*61d06d6bSBaptiste Daroussin * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16*61d06d6bSBaptiste Daroussin * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*61d06d6bSBaptiste Daroussin */ 18*61d06d6bSBaptiste Daroussin #include "config.h" 19*61d06d6bSBaptiste Daroussin 20*61d06d6bSBaptiste Daroussin #include <sys/types.h> 21*61d06d6bSBaptiste Daroussin 22*61d06d6bSBaptiste Daroussin #include <assert.h> 23*61d06d6bSBaptiste Daroussin #include <ctype.h> 24*61d06d6bSBaptiste Daroussin #include <limits.h> 25*61d06d6bSBaptiste Daroussin #include <stddef.h> 26*61d06d6bSBaptiste Daroussin #include <stdint.h> 27*61d06d6bSBaptiste Daroussin #include <stdio.h> 28*61d06d6bSBaptiste Daroussin #include <stdlib.h> 29*61d06d6bSBaptiste Daroussin #include <string.h> 30*61d06d6bSBaptiste Daroussin 31*61d06d6bSBaptiste Daroussin #include "mandoc.h" 32*61d06d6bSBaptiste Daroussin #include "mandoc_aux.h" 33*61d06d6bSBaptiste Daroussin #include "mandoc_ohash.h" 34*61d06d6bSBaptiste Daroussin #include "roff.h" 35*61d06d6bSBaptiste Daroussin #include "libmandoc.h" 36*61d06d6bSBaptiste Daroussin #include "roff_int.h" 37*61d06d6bSBaptiste Daroussin #include "libroff.h" 38*61d06d6bSBaptiste Daroussin 39*61d06d6bSBaptiste Daroussin /* Maximum number of string expansions per line, to break infinite loops. */ 40*61d06d6bSBaptiste Daroussin #define EXPAND_LIMIT 1000 41*61d06d6bSBaptiste Daroussin 42*61d06d6bSBaptiste Daroussin /* Types of definitions of macros and strings. */ 43*61d06d6bSBaptiste Daroussin #define ROFFDEF_USER (1 << 1) /* User-defined. */ 44*61d06d6bSBaptiste Daroussin #define ROFFDEF_PRE (1 << 2) /* Predefined. */ 45*61d06d6bSBaptiste Daroussin #define ROFFDEF_REN (1 << 3) /* Renamed standard macro. */ 46*61d06d6bSBaptiste Daroussin #define ROFFDEF_STD (1 << 4) /* mdoc(7) or man(7) macro. */ 47*61d06d6bSBaptiste Daroussin #define ROFFDEF_ANY (ROFFDEF_USER | ROFFDEF_PRE | \ 48*61d06d6bSBaptiste Daroussin ROFFDEF_REN | ROFFDEF_STD) 49*61d06d6bSBaptiste Daroussin #define ROFFDEF_UNDEF (1 << 5) /* Completely undefined. */ 50*61d06d6bSBaptiste Daroussin 51*61d06d6bSBaptiste Daroussin /* --- data types --------------------------------------------------------- */ 52*61d06d6bSBaptiste Daroussin 53*61d06d6bSBaptiste Daroussin /* 54*61d06d6bSBaptiste Daroussin * An incredibly-simple string buffer. 55*61d06d6bSBaptiste Daroussin */ 56*61d06d6bSBaptiste Daroussin struct roffstr { 57*61d06d6bSBaptiste Daroussin char *p; /* nil-terminated buffer */ 58*61d06d6bSBaptiste Daroussin size_t sz; /* saved strlen(p) */ 59*61d06d6bSBaptiste Daroussin }; 60*61d06d6bSBaptiste Daroussin 61*61d06d6bSBaptiste Daroussin /* 62*61d06d6bSBaptiste Daroussin * A key-value roffstr pair as part of a singly-linked list. 63*61d06d6bSBaptiste Daroussin */ 64*61d06d6bSBaptiste Daroussin struct roffkv { 65*61d06d6bSBaptiste Daroussin struct roffstr key; 66*61d06d6bSBaptiste Daroussin struct roffstr val; 67*61d06d6bSBaptiste Daroussin struct roffkv *next; /* next in list */ 68*61d06d6bSBaptiste Daroussin }; 69*61d06d6bSBaptiste Daroussin 70*61d06d6bSBaptiste Daroussin /* 71*61d06d6bSBaptiste Daroussin * A single number register as part of a singly-linked list. 72*61d06d6bSBaptiste Daroussin */ 73*61d06d6bSBaptiste Daroussin struct roffreg { 74*61d06d6bSBaptiste Daroussin struct roffstr key; 75*61d06d6bSBaptiste Daroussin int val; 76*61d06d6bSBaptiste Daroussin int step; 77*61d06d6bSBaptiste Daroussin struct roffreg *next; 78*61d06d6bSBaptiste Daroussin }; 79*61d06d6bSBaptiste Daroussin 80*61d06d6bSBaptiste Daroussin /* 81*61d06d6bSBaptiste Daroussin * Association of request and macro names with token IDs. 82*61d06d6bSBaptiste Daroussin */ 83*61d06d6bSBaptiste Daroussin struct roffreq { 84*61d06d6bSBaptiste Daroussin enum roff_tok tok; 85*61d06d6bSBaptiste Daroussin char name[]; 86*61d06d6bSBaptiste Daroussin }; 87*61d06d6bSBaptiste Daroussin 88*61d06d6bSBaptiste Daroussin struct roff { 89*61d06d6bSBaptiste Daroussin struct mparse *parse; /* parse point */ 90*61d06d6bSBaptiste Daroussin struct roff_man *man; /* mdoc or man parser */ 91*61d06d6bSBaptiste Daroussin struct roffnode *last; /* leaf of stack */ 92*61d06d6bSBaptiste Daroussin int *rstack; /* stack of inverted `ie' values */ 93*61d06d6bSBaptiste Daroussin struct ohash *reqtab; /* request lookup table */ 94*61d06d6bSBaptiste Daroussin struct roffreg *regtab; /* number registers */ 95*61d06d6bSBaptiste Daroussin struct roffkv *strtab; /* user-defined strings & macros */ 96*61d06d6bSBaptiste Daroussin struct roffkv *rentab; /* renamed strings & macros */ 97*61d06d6bSBaptiste Daroussin struct roffkv *xmbtab; /* multi-byte trans table (`tr') */ 98*61d06d6bSBaptiste Daroussin struct roffstr *xtab; /* single-byte trans table (`tr') */ 99*61d06d6bSBaptiste Daroussin const char *current_string; /* value of last called user macro */ 100*61d06d6bSBaptiste Daroussin struct tbl_node *first_tbl; /* first table parsed */ 101*61d06d6bSBaptiste Daroussin struct tbl_node *last_tbl; /* last table parsed */ 102*61d06d6bSBaptiste Daroussin struct tbl_node *tbl; /* current table being parsed */ 103*61d06d6bSBaptiste Daroussin struct eqn_node *last_eqn; /* equation parser */ 104*61d06d6bSBaptiste Daroussin struct eqn_node *eqn; /* active equation parser */ 105*61d06d6bSBaptiste Daroussin int eqn_inline; /* current equation is inline */ 106*61d06d6bSBaptiste Daroussin int options; /* parse options */ 107*61d06d6bSBaptiste Daroussin int rstacksz; /* current size limit of rstack */ 108*61d06d6bSBaptiste Daroussin int rstackpos; /* position in rstack */ 109*61d06d6bSBaptiste Daroussin int format; /* current file in mdoc or man format */ 110*61d06d6bSBaptiste Daroussin int argc; /* number of args of the last macro */ 111*61d06d6bSBaptiste Daroussin char control; /* control character */ 112*61d06d6bSBaptiste Daroussin char escape; /* escape character */ 113*61d06d6bSBaptiste Daroussin }; 114*61d06d6bSBaptiste Daroussin 115*61d06d6bSBaptiste Daroussin struct roffnode { 116*61d06d6bSBaptiste Daroussin enum roff_tok tok; /* type of node */ 117*61d06d6bSBaptiste Daroussin struct roffnode *parent; /* up one in stack */ 118*61d06d6bSBaptiste Daroussin int line; /* parse line */ 119*61d06d6bSBaptiste Daroussin int col; /* parse col */ 120*61d06d6bSBaptiste Daroussin char *name; /* node name, e.g. macro name */ 121*61d06d6bSBaptiste Daroussin char *end; /* end-rules: custom token */ 122*61d06d6bSBaptiste Daroussin int endspan; /* end-rules: next-line or infty */ 123*61d06d6bSBaptiste Daroussin int rule; /* current evaluation rule */ 124*61d06d6bSBaptiste Daroussin }; 125*61d06d6bSBaptiste Daroussin 126*61d06d6bSBaptiste Daroussin #define ROFF_ARGS struct roff *r, /* parse ctx */ \ 127*61d06d6bSBaptiste Daroussin enum roff_tok tok, /* tok of macro */ \ 128*61d06d6bSBaptiste Daroussin struct buf *buf, /* input buffer */ \ 129*61d06d6bSBaptiste Daroussin int ln, /* parse line */ \ 130*61d06d6bSBaptiste Daroussin int ppos, /* original pos in buffer */ \ 131*61d06d6bSBaptiste Daroussin int pos, /* current pos in buffer */ \ 132*61d06d6bSBaptiste Daroussin int *offs /* reset offset of buffer data */ 133*61d06d6bSBaptiste Daroussin 134*61d06d6bSBaptiste Daroussin typedef enum rofferr (*roffproc)(ROFF_ARGS); 135*61d06d6bSBaptiste Daroussin 136*61d06d6bSBaptiste Daroussin struct roffmac { 137*61d06d6bSBaptiste Daroussin roffproc proc; /* process new macro */ 138*61d06d6bSBaptiste Daroussin roffproc text; /* process as child text of macro */ 139*61d06d6bSBaptiste Daroussin roffproc sub; /* process as child of macro */ 140*61d06d6bSBaptiste Daroussin int flags; 141*61d06d6bSBaptiste Daroussin #define ROFFMAC_STRUCT (1 << 0) /* always interpret */ 142*61d06d6bSBaptiste Daroussin }; 143*61d06d6bSBaptiste Daroussin 144*61d06d6bSBaptiste Daroussin struct predef { 145*61d06d6bSBaptiste Daroussin const char *name; /* predefined input name */ 146*61d06d6bSBaptiste Daroussin const char *str; /* replacement symbol */ 147*61d06d6bSBaptiste Daroussin }; 148*61d06d6bSBaptiste Daroussin 149*61d06d6bSBaptiste Daroussin #define PREDEF(__name, __str) \ 150*61d06d6bSBaptiste Daroussin { (__name), (__str) }, 151*61d06d6bSBaptiste Daroussin 152*61d06d6bSBaptiste Daroussin /* --- function prototypes ------------------------------------------------ */ 153*61d06d6bSBaptiste Daroussin 154*61d06d6bSBaptiste Daroussin static void roffnode_cleanscope(struct roff *); 155*61d06d6bSBaptiste Daroussin static void roffnode_pop(struct roff *); 156*61d06d6bSBaptiste Daroussin static void roffnode_push(struct roff *, enum roff_tok, 157*61d06d6bSBaptiste Daroussin const char *, int, int); 158*61d06d6bSBaptiste Daroussin static void roff_addtbl(struct roff_man *, struct tbl_node *); 159*61d06d6bSBaptiste Daroussin static enum rofferr roff_als(ROFF_ARGS); 160*61d06d6bSBaptiste Daroussin static enum rofferr roff_block(ROFF_ARGS); 161*61d06d6bSBaptiste Daroussin static enum rofferr roff_block_text(ROFF_ARGS); 162*61d06d6bSBaptiste Daroussin static enum rofferr roff_block_sub(ROFF_ARGS); 163*61d06d6bSBaptiste Daroussin static enum rofferr roff_br(ROFF_ARGS); 164*61d06d6bSBaptiste Daroussin static enum rofferr roff_cblock(ROFF_ARGS); 165*61d06d6bSBaptiste Daroussin static enum rofferr roff_cc(ROFF_ARGS); 166*61d06d6bSBaptiste Daroussin static void roff_ccond(struct roff *, int, int); 167*61d06d6bSBaptiste Daroussin static enum rofferr roff_cond(ROFF_ARGS); 168*61d06d6bSBaptiste Daroussin static enum rofferr roff_cond_text(ROFF_ARGS); 169*61d06d6bSBaptiste Daroussin static enum rofferr roff_cond_sub(ROFF_ARGS); 170*61d06d6bSBaptiste Daroussin static enum rofferr roff_ds(ROFF_ARGS); 171*61d06d6bSBaptiste Daroussin static enum rofferr roff_ec(ROFF_ARGS); 172*61d06d6bSBaptiste Daroussin static enum rofferr roff_eo(ROFF_ARGS); 173*61d06d6bSBaptiste Daroussin static enum rofferr roff_eqndelim(struct roff *, struct buf *, int); 174*61d06d6bSBaptiste Daroussin static int roff_evalcond(struct roff *r, int, char *, int *); 175*61d06d6bSBaptiste Daroussin static int roff_evalnum(struct roff *, int, 176*61d06d6bSBaptiste Daroussin const char *, int *, int *, int); 177*61d06d6bSBaptiste Daroussin static int roff_evalpar(struct roff *, int, 178*61d06d6bSBaptiste Daroussin const char *, int *, int *, int); 179*61d06d6bSBaptiste Daroussin static int roff_evalstrcond(const char *, int *); 180*61d06d6bSBaptiste Daroussin static void roff_free1(struct roff *); 181*61d06d6bSBaptiste Daroussin static void roff_freereg(struct roffreg *); 182*61d06d6bSBaptiste Daroussin static void roff_freestr(struct roffkv *); 183*61d06d6bSBaptiste Daroussin static size_t roff_getname(struct roff *, char **, int, int); 184*61d06d6bSBaptiste Daroussin static int roff_getnum(const char *, int *, int *, int); 185*61d06d6bSBaptiste Daroussin static int roff_getop(const char *, int *, char *); 186*61d06d6bSBaptiste Daroussin static int roff_getregn(struct roff *, 187*61d06d6bSBaptiste Daroussin const char *, size_t, char); 188*61d06d6bSBaptiste Daroussin static int roff_getregro(const struct roff *, 189*61d06d6bSBaptiste Daroussin const char *name); 190*61d06d6bSBaptiste Daroussin static const char *roff_getstrn(struct roff *, 191*61d06d6bSBaptiste Daroussin const char *, size_t, int *); 192*61d06d6bSBaptiste Daroussin static int roff_hasregn(const struct roff *, 193*61d06d6bSBaptiste Daroussin const char *, size_t); 194*61d06d6bSBaptiste Daroussin static enum rofferr roff_insec(ROFF_ARGS); 195*61d06d6bSBaptiste Daroussin static enum rofferr roff_it(ROFF_ARGS); 196*61d06d6bSBaptiste Daroussin static enum rofferr roff_line_ignore(ROFF_ARGS); 197*61d06d6bSBaptiste Daroussin static void roff_man_alloc1(struct roff_man *); 198*61d06d6bSBaptiste Daroussin static void roff_man_free1(struct roff_man *); 199*61d06d6bSBaptiste Daroussin static enum rofferr roff_manyarg(ROFF_ARGS); 200*61d06d6bSBaptiste Daroussin static enum rofferr roff_nr(ROFF_ARGS); 201*61d06d6bSBaptiste Daroussin static enum rofferr roff_onearg(ROFF_ARGS); 202*61d06d6bSBaptiste Daroussin static enum roff_tok roff_parse(struct roff *, char *, int *, 203*61d06d6bSBaptiste Daroussin int, int); 204*61d06d6bSBaptiste Daroussin static enum rofferr roff_parsetext(struct roff *, struct buf *, 205*61d06d6bSBaptiste Daroussin int, int *); 206*61d06d6bSBaptiste Daroussin static enum rofferr roff_renamed(ROFF_ARGS); 207*61d06d6bSBaptiste Daroussin static enum rofferr roff_res(struct roff *, struct buf *, int, int); 208*61d06d6bSBaptiste Daroussin static enum rofferr roff_rm(ROFF_ARGS); 209*61d06d6bSBaptiste Daroussin static enum rofferr roff_rn(ROFF_ARGS); 210*61d06d6bSBaptiste Daroussin static enum rofferr roff_rr(ROFF_ARGS); 211*61d06d6bSBaptiste Daroussin static void roff_setregn(struct roff *, const char *, 212*61d06d6bSBaptiste Daroussin size_t, int, char, int); 213*61d06d6bSBaptiste Daroussin static void roff_setstr(struct roff *, 214*61d06d6bSBaptiste Daroussin const char *, const char *, int); 215*61d06d6bSBaptiste Daroussin static void roff_setstrn(struct roffkv **, const char *, 216*61d06d6bSBaptiste Daroussin size_t, const char *, size_t, int); 217*61d06d6bSBaptiste Daroussin static enum rofferr roff_so(ROFF_ARGS); 218*61d06d6bSBaptiste Daroussin static enum rofferr roff_tr(ROFF_ARGS); 219*61d06d6bSBaptiste Daroussin static enum rofferr roff_Dd(ROFF_ARGS); 220*61d06d6bSBaptiste Daroussin static enum rofferr roff_TE(ROFF_ARGS); 221*61d06d6bSBaptiste Daroussin static enum rofferr roff_TS(ROFF_ARGS); 222*61d06d6bSBaptiste Daroussin static enum rofferr roff_EQ(ROFF_ARGS); 223*61d06d6bSBaptiste Daroussin static enum rofferr roff_EN(ROFF_ARGS); 224*61d06d6bSBaptiste Daroussin static enum rofferr roff_T_(ROFF_ARGS); 225*61d06d6bSBaptiste Daroussin static enum rofferr roff_unsupp(ROFF_ARGS); 226*61d06d6bSBaptiste Daroussin static enum rofferr roff_userdef(ROFF_ARGS); 227*61d06d6bSBaptiste Daroussin 228*61d06d6bSBaptiste Daroussin /* --- constant data ------------------------------------------------------ */ 229*61d06d6bSBaptiste Daroussin 230*61d06d6bSBaptiste Daroussin #define ROFFNUM_SCALE (1 << 0) /* Honour scaling in roff_getnum(). */ 231*61d06d6bSBaptiste Daroussin #define ROFFNUM_WHITE (1 << 1) /* Skip whitespace in roff_evalnum(). */ 232*61d06d6bSBaptiste Daroussin 233*61d06d6bSBaptiste Daroussin const char *__roff_name[MAN_MAX + 1] = { 234*61d06d6bSBaptiste Daroussin "br", "ce", "ft", "ll", 235*61d06d6bSBaptiste Daroussin "mc", "po", "rj", "sp", 236*61d06d6bSBaptiste Daroussin "ta", "ti", NULL, 237*61d06d6bSBaptiste Daroussin "ab", "ad", "af", "aln", 238*61d06d6bSBaptiste Daroussin "als", "am", "am1", "ami", 239*61d06d6bSBaptiste Daroussin "ami1", "as", "as1", "asciify", 240*61d06d6bSBaptiste Daroussin "backtrace", "bd", "bleedat", "blm", 241*61d06d6bSBaptiste Daroussin "box", "boxa", "bp", "BP", 242*61d06d6bSBaptiste Daroussin "break", "breakchar", "brnl", "brp", 243*61d06d6bSBaptiste Daroussin "brpnl", "c2", "cc", 244*61d06d6bSBaptiste Daroussin "cf", "cflags", "ch", "char", 245*61d06d6bSBaptiste Daroussin "chop", "class", "close", "CL", 246*61d06d6bSBaptiste Daroussin "color", "composite", "continue", "cp", 247*61d06d6bSBaptiste Daroussin "cropat", "cs", "cu", "da", 248*61d06d6bSBaptiste Daroussin "dch", "Dd", "de", "de1", 249*61d06d6bSBaptiste Daroussin "defcolor", "dei", "dei1", "device", 250*61d06d6bSBaptiste Daroussin "devicem", "di", "do", "ds", 251*61d06d6bSBaptiste Daroussin "ds1", "dwh", "dt", "ec", 252*61d06d6bSBaptiste Daroussin "ecr", "ecs", "el", "em", 253*61d06d6bSBaptiste Daroussin "EN", "eo", "EP", "EQ", 254*61d06d6bSBaptiste Daroussin "errprint", "ev", "evc", "ex", 255*61d06d6bSBaptiste Daroussin "fallback", "fam", "fc", "fchar", 256*61d06d6bSBaptiste Daroussin "fcolor", "fdeferlig", "feature", "fkern", 257*61d06d6bSBaptiste Daroussin "fl", "flig", "fp", "fps", 258*61d06d6bSBaptiste Daroussin "fschar", "fspacewidth", "fspecial", "ftr", 259*61d06d6bSBaptiste Daroussin "fzoom", "gcolor", "hc", "hcode", 260*61d06d6bSBaptiste Daroussin "hidechar", "hla", "hlm", "hpf", 261*61d06d6bSBaptiste Daroussin "hpfa", "hpfcode", "hw", "hy", 262*61d06d6bSBaptiste Daroussin "hylang", "hylen", "hym", "hypp", 263*61d06d6bSBaptiste Daroussin "hys", "ie", "if", "ig", 264*61d06d6bSBaptiste Daroussin "index", "it", "itc", "IX", 265*61d06d6bSBaptiste Daroussin "kern", "kernafter", "kernbefore", "kernpair", 266*61d06d6bSBaptiste Daroussin "lc", "lc_ctype", "lds", "length", 267*61d06d6bSBaptiste Daroussin "letadj", "lf", "lg", "lhang", 268*61d06d6bSBaptiste Daroussin "linetabs", "lnr", "lnrf", "lpfx", 269*61d06d6bSBaptiste Daroussin "ls", "lsm", "lt", 270*61d06d6bSBaptiste Daroussin "mediasize", "minss", "mk", "mso", 271*61d06d6bSBaptiste Daroussin "na", "ne", "nh", "nhychar", 272*61d06d6bSBaptiste Daroussin "nm", "nn", "nop", "nr", 273*61d06d6bSBaptiste Daroussin "nrf", "nroff", "ns", "nx", 274*61d06d6bSBaptiste Daroussin "open", "opena", "os", "output", 275*61d06d6bSBaptiste Daroussin "padj", "papersize", "pc", "pev", 276*61d06d6bSBaptiste Daroussin "pi", "PI", "pl", "pm", 277*61d06d6bSBaptiste Daroussin "pn", "pnr", "ps", 278*61d06d6bSBaptiste Daroussin "psbb", "pshape", "pso", "ptr", 279*61d06d6bSBaptiste Daroussin "pvs", "rchar", "rd", "recursionlimit", 280*61d06d6bSBaptiste Daroussin "return", "rfschar", "rhang", 281*61d06d6bSBaptiste Daroussin "rm", "rn", "rnn", "rr", 282*61d06d6bSBaptiste Daroussin "rs", "rt", "schar", "sentchar", 283*61d06d6bSBaptiste Daroussin "shc", "shift", "sizes", "so", 284*61d06d6bSBaptiste Daroussin "spacewidth", "special", "spreadwarn", "ss", 285*61d06d6bSBaptiste Daroussin "sty", "substring", "sv", "sy", 286*61d06d6bSBaptiste Daroussin "T&", "tc", "TE", 287*61d06d6bSBaptiste Daroussin "TH", "tkf", "tl", 288*61d06d6bSBaptiste Daroussin "tm", "tm1", "tmc", "tr", 289*61d06d6bSBaptiste Daroussin "track", "transchar", "trf", "trimat", 290*61d06d6bSBaptiste Daroussin "trin", "trnt", "troff", "TS", 291*61d06d6bSBaptiste Daroussin "uf", "ul", "unformat", "unwatch", 292*61d06d6bSBaptiste Daroussin "unwatchn", "vpt", "vs", "warn", 293*61d06d6bSBaptiste Daroussin "warnscale", "watch", "watchlength", "watchn", 294*61d06d6bSBaptiste Daroussin "wh", "while", "write", "writec", 295*61d06d6bSBaptiste Daroussin "writem", "xflag", ".", NULL, 296*61d06d6bSBaptiste Daroussin NULL, "text", 297*61d06d6bSBaptiste Daroussin "Dd", "Dt", "Os", "Sh", 298*61d06d6bSBaptiste Daroussin "Ss", "Pp", "D1", "Dl", 299*61d06d6bSBaptiste Daroussin "Bd", "Ed", "Bl", "El", 300*61d06d6bSBaptiste Daroussin "It", "Ad", "An", "Ap", 301*61d06d6bSBaptiste Daroussin "Ar", "Cd", "Cm", "Dv", 302*61d06d6bSBaptiste Daroussin "Er", "Ev", "Ex", "Fa", 303*61d06d6bSBaptiste Daroussin "Fd", "Fl", "Fn", "Ft", 304*61d06d6bSBaptiste Daroussin "Ic", "In", "Li", "Nd", 305*61d06d6bSBaptiste Daroussin "Nm", "Op", "Ot", "Pa", 306*61d06d6bSBaptiste Daroussin "Rv", "St", "Va", "Vt", 307*61d06d6bSBaptiste Daroussin "Xr", "%A", "%B", "%D", 308*61d06d6bSBaptiste Daroussin "%I", "%J", "%N", "%O", 309*61d06d6bSBaptiste Daroussin "%P", "%R", "%T", "%V", 310*61d06d6bSBaptiste Daroussin "Ac", "Ao", "Aq", "At", 311*61d06d6bSBaptiste Daroussin "Bc", "Bf", "Bo", "Bq", 312*61d06d6bSBaptiste Daroussin "Bsx", "Bx", "Db", "Dc", 313*61d06d6bSBaptiste Daroussin "Do", "Dq", "Ec", "Ef", 314*61d06d6bSBaptiste Daroussin "Em", "Eo", "Fx", "Ms", 315*61d06d6bSBaptiste Daroussin "No", "Ns", "Nx", "Ox", 316*61d06d6bSBaptiste Daroussin "Pc", "Pf", "Po", "Pq", 317*61d06d6bSBaptiste Daroussin "Qc", "Ql", "Qo", "Qq", 318*61d06d6bSBaptiste Daroussin "Re", "Rs", "Sc", "So", 319*61d06d6bSBaptiste Daroussin "Sq", "Sm", "Sx", "Sy", 320*61d06d6bSBaptiste Daroussin "Tn", "Ux", "Xc", "Xo", 321*61d06d6bSBaptiste Daroussin "Fo", "Fc", "Oo", "Oc", 322*61d06d6bSBaptiste Daroussin "Bk", "Ek", "Bt", "Hf", 323*61d06d6bSBaptiste Daroussin "Fr", "Ud", "Lb", "Lp", 324*61d06d6bSBaptiste Daroussin "Lk", "Mt", "Brq", "Bro", 325*61d06d6bSBaptiste Daroussin "Brc", "%C", "Es", "En", 326*61d06d6bSBaptiste Daroussin "Dx", "%Q", "%U", "Ta", 327*61d06d6bSBaptiste Daroussin NULL, 328*61d06d6bSBaptiste Daroussin "TH", "SH", "SS", "TP", 329*61d06d6bSBaptiste Daroussin "LP", "PP", "P", "IP", 330*61d06d6bSBaptiste Daroussin "HP", "SM", "SB", "BI", 331*61d06d6bSBaptiste Daroussin "IB", "BR", "RB", "R", 332*61d06d6bSBaptiste Daroussin "B", "I", "IR", "RI", 333*61d06d6bSBaptiste Daroussin "nf", "fi", 334*61d06d6bSBaptiste Daroussin "RE", "RS", "DT", "UC", 335*61d06d6bSBaptiste Daroussin "PD", "AT", "in", 336*61d06d6bSBaptiste Daroussin "OP", "EX", "EE", "UR", 337*61d06d6bSBaptiste Daroussin "UE", "MT", "ME", NULL 338*61d06d6bSBaptiste Daroussin }; 339*61d06d6bSBaptiste Daroussin const char *const *roff_name = __roff_name; 340*61d06d6bSBaptiste Daroussin 341*61d06d6bSBaptiste Daroussin static struct roffmac roffs[TOKEN_NONE] = { 342*61d06d6bSBaptiste Daroussin { roff_br, NULL, NULL, 0 }, /* br */ 343*61d06d6bSBaptiste Daroussin { roff_onearg, NULL, NULL, 0 }, /* ce */ 344*61d06d6bSBaptiste Daroussin { roff_onearg, NULL, NULL, 0 }, /* ft */ 345*61d06d6bSBaptiste Daroussin { roff_onearg, NULL, NULL, 0 }, /* ll */ 346*61d06d6bSBaptiste Daroussin { roff_onearg, NULL, NULL, 0 }, /* mc */ 347*61d06d6bSBaptiste Daroussin { roff_onearg, NULL, NULL, 0 }, /* po */ 348*61d06d6bSBaptiste Daroussin { roff_onearg, NULL, NULL, 0 }, /* rj */ 349*61d06d6bSBaptiste Daroussin { roff_onearg, NULL, NULL, 0 }, /* sp */ 350*61d06d6bSBaptiste Daroussin { roff_manyarg, NULL, NULL, 0 }, /* ta */ 351*61d06d6bSBaptiste Daroussin { roff_onearg, NULL, NULL, 0 }, /* ti */ 352*61d06d6bSBaptiste Daroussin { NULL, NULL, NULL, 0 }, /* ROFF_MAX */ 353*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* ab */ 354*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* ad */ 355*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* af */ 356*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* aln */ 357*61d06d6bSBaptiste Daroussin { roff_als, NULL, NULL, 0 }, /* als */ 358*61d06d6bSBaptiste Daroussin { roff_block, roff_block_text, roff_block_sub, 0 }, /* am */ 359*61d06d6bSBaptiste Daroussin { roff_block, roff_block_text, roff_block_sub, 0 }, /* am1 */ 360*61d06d6bSBaptiste Daroussin { roff_block, roff_block_text, roff_block_sub, 0 }, /* ami */ 361*61d06d6bSBaptiste Daroussin { roff_block, roff_block_text, roff_block_sub, 0 }, /* ami1 */ 362*61d06d6bSBaptiste Daroussin { roff_ds, NULL, NULL, 0 }, /* as */ 363*61d06d6bSBaptiste Daroussin { roff_ds, NULL, NULL, 0 }, /* as1 */ 364*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* asciify */ 365*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* backtrace */ 366*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* bd */ 367*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* bleedat */ 368*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* blm */ 369*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* box */ 370*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* boxa */ 371*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* bp */ 372*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* BP */ 373*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* break */ 374*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* breakchar */ 375*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* brnl */ 376*61d06d6bSBaptiste Daroussin { roff_br, NULL, NULL, 0 }, /* brp */ 377*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* brpnl */ 378*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* c2 */ 379*61d06d6bSBaptiste Daroussin { roff_cc, NULL, NULL, 0 }, /* cc */ 380*61d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* cf */ 381*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* cflags */ 382*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* ch */ 383*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* char */ 384*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* chop */ 385*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* class */ 386*61d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* close */ 387*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* CL */ 388*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* color */ 389*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* composite */ 390*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* continue */ 391*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* cp */ 392*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* cropat */ 393*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* cs */ 394*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* cu */ 395*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* da */ 396*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* dch */ 397*61d06d6bSBaptiste Daroussin { roff_Dd, NULL, NULL, 0 }, /* Dd */ 398*61d06d6bSBaptiste Daroussin { roff_block, roff_block_text, roff_block_sub, 0 }, /* de */ 399*61d06d6bSBaptiste Daroussin { roff_block, roff_block_text, roff_block_sub, 0 }, /* de1 */ 400*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* defcolor */ 401*61d06d6bSBaptiste Daroussin { roff_block, roff_block_text, roff_block_sub, 0 }, /* dei */ 402*61d06d6bSBaptiste Daroussin { roff_block, roff_block_text, roff_block_sub, 0 }, /* dei1 */ 403*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* device */ 404*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* devicem */ 405*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* di */ 406*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* do */ 407*61d06d6bSBaptiste Daroussin { roff_ds, NULL, NULL, 0 }, /* ds */ 408*61d06d6bSBaptiste Daroussin { roff_ds, NULL, NULL, 0 }, /* ds1 */ 409*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* dwh */ 410*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* dt */ 411*61d06d6bSBaptiste Daroussin { roff_ec, NULL, NULL, 0 }, /* ec */ 412*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* ecr */ 413*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* ecs */ 414*61d06d6bSBaptiste Daroussin { roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT }, /* el */ 415*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* em */ 416*61d06d6bSBaptiste Daroussin { roff_EN, NULL, NULL, 0 }, /* EN */ 417*61d06d6bSBaptiste Daroussin { roff_eo, NULL, NULL, 0 }, /* eo */ 418*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* EP */ 419*61d06d6bSBaptiste Daroussin { roff_EQ, NULL, NULL, 0 }, /* EQ */ 420*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* errprint */ 421*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* ev */ 422*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* evc */ 423*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* ex */ 424*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* fallback */ 425*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* fam */ 426*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* fc */ 427*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* fchar */ 428*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* fcolor */ 429*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* fdeferlig */ 430*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* feature */ 431*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* fkern */ 432*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* fl */ 433*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* flig */ 434*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* fp */ 435*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* fps */ 436*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* fschar */ 437*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* fspacewidth */ 438*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* fspecial */ 439*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* ftr */ 440*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* fzoom */ 441*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* gcolor */ 442*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hc */ 443*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hcode */ 444*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hidechar */ 445*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hla */ 446*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hlm */ 447*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hpf */ 448*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hpfa */ 449*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hpfcode */ 450*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hw */ 451*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hy */ 452*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hylang */ 453*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hylen */ 454*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hym */ 455*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hypp */ 456*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* hys */ 457*61d06d6bSBaptiste Daroussin { roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT }, /* ie */ 458*61d06d6bSBaptiste Daroussin { roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT }, /* if */ 459*61d06d6bSBaptiste Daroussin { roff_block, roff_block_text, roff_block_sub, 0 }, /* ig */ 460*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* index */ 461*61d06d6bSBaptiste Daroussin { roff_it, NULL, NULL, 0 }, /* it */ 462*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* itc */ 463*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* IX */ 464*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* kern */ 465*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* kernafter */ 466*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* kernbefore */ 467*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* kernpair */ 468*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* lc */ 469*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* lc_ctype */ 470*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* lds */ 471*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* length */ 472*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* letadj */ 473*61d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* lf */ 474*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* lg */ 475*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* lhang */ 476*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* linetabs */ 477*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* lnr */ 478*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* lnrf */ 479*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* lpfx */ 480*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* ls */ 481*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* lsm */ 482*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* lt */ 483*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* mediasize */ 484*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* minss */ 485*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* mk */ 486*61d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* mso */ 487*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* na */ 488*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* ne */ 489*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* nh */ 490*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* nhychar */ 491*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* nm */ 492*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* nn */ 493*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* nop */ 494*61d06d6bSBaptiste Daroussin { roff_nr, NULL, NULL, 0 }, /* nr */ 495*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* nrf */ 496*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* nroff */ 497*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* ns */ 498*61d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* nx */ 499*61d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* open */ 500*61d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* opena */ 501*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* os */ 502*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* output */ 503*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* padj */ 504*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* papersize */ 505*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* pc */ 506*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* pev */ 507*61d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* pi */ 508*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* PI */ 509*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* pl */ 510*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* pm */ 511*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* pn */ 512*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* pnr */ 513*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* ps */ 514*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* psbb */ 515*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* pshape */ 516*61d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* pso */ 517*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* ptr */ 518*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* pvs */ 519*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* rchar */ 520*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* rd */ 521*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* recursionlimit */ 522*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* return */ 523*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* rfschar */ 524*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* rhang */ 525*61d06d6bSBaptiste Daroussin { roff_rm, NULL, NULL, 0 }, /* rm */ 526*61d06d6bSBaptiste Daroussin { roff_rn, NULL, NULL, 0 }, /* rn */ 527*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* rnn */ 528*61d06d6bSBaptiste Daroussin { roff_rr, NULL, NULL, 0 }, /* rr */ 529*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* rs */ 530*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* rt */ 531*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* schar */ 532*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* sentchar */ 533*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* shc */ 534*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* shift */ 535*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* sizes */ 536*61d06d6bSBaptiste Daroussin { roff_so, NULL, NULL, 0 }, /* so */ 537*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* spacewidth */ 538*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* special */ 539*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* spreadwarn */ 540*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* ss */ 541*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* sty */ 542*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* substring */ 543*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* sv */ 544*61d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* sy */ 545*61d06d6bSBaptiste Daroussin { roff_T_, NULL, NULL, 0 }, /* T& */ 546*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* tc */ 547*61d06d6bSBaptiste Daroussin { roff_TE, NULL, NULL, 0 }, /* TE */ 548*61d06d6bSBaptiste Daroussin { roff_Dd, NULL, NULL, 0 }, /* TH */ 549*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* tkf */ 550*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* tl */ 551*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* tm */ 552*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* tm1 */ 553*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* tmc */ 554*61d06d6bSBaptiste Daroussin { roff_tr, NULL, NULL, 0 }, /* tr */ 555*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* track */ 556*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* transchar */ 557*61d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* trf */ 558*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* trimat */ 559*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* trin */ 560*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* trnt */ 561*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* troff */ 562*61d06d6bSBaptiste Daroussin { roff_TS, NULL, NULL, 0 }, /* TS */ 563*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* uf */ 564*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* ul */ 565*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* unformat */ 566*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* unwatch */ 567*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* unwatchn */ 568*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* vpt */ 569*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* vs */ 570*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* warn */ 571*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* warnscale */ 572*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* watch */ 573*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* watchlength */ 574*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* watchn */ 575*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* wh */ 576*61d06d6bSBaptiste Daroussin { roff_unsupp, NULL, NULL, 0 }, /* while */ 577*61d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* write */ 578*61d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* writec */ 579*61d06d6bSBaptiste Daroussin { roff_insec, NULL, NULL, 0 }, /* writem */ 580*61d06d6bSBaptiste Daroussin { roff_line_ignore, NULL, NULL, 0 }, /* xflag */ 581*61d06d6bSBaptiste Daroussin { roff_cblock, NULL, NULL, 0 }, /* . */ 582*61d06d6bSBaptiste Daroussin { roff_renamed, NULL, NULL, 0 }, 583*61d06d6bSBaptiste Daroussin { roff_userdef, NULL, NULL, 0 } 584*61d06d6bSBaptiste Daroussin }; 585*61d06d6bSBaptiste Daroussin 586*61d06d6bSBaptiste Daroussin /* Array of injected predefined strings. */ 587*61d06d6bSBaptiste Daroussin #define PREDEFS_MAX 38 588*61d06d6bSBaptiste Daroussin static const struct predef predefs[PREDEFS_MAX] = { 589*61d06d6bSBaptiste Daroussin #include "predefs.in" 590*61d06d6bSBaptiste Daroussin }; 591*61d06d6bSBaptiste Daroussin 592*61d06d6bSBaptiste Daroussin static int roffce_lines; /* number of input lines to center */ 593*61d06d6bSBaptiste Daroussin static struct roff_node *roffce_node; /* active request */ 594*61d06d6bSBaptiste Daroussin static int roffit_lines; /* number of lines to delay */ 595*61d06d6bSBaptiste Daroussin static char *roffit_macro; /* nil-terminated macro line */ 596*61d06d6bSBaptiste Daroussin 597*61d06d6bSBaptiste Daroussin 598*61d06d6bSBaptiste Daroussin /* --- request table ------------------------------------------------------ */ 599*61d06d6bSBaptiste Daroussin 600*61d06d6bSBaptiste Daroussin struct ohash * 601*61d06d6bSBaptiste Daroussin roffhash_alloc(enum roff_tok mintok, enum roff_tok maxtok) 602*61d06d6bSBaptiste Daroussin { 603*61d06d6bSBaptiste Daroussin struct ohash *htab; 604*61d06d6bSBaptiste Daroussin struct roffreq *req; 605*61d06d6bSBaptiste Daroussin enum roff_tok tok; 606*61d06d6bSBaptiste Daroussin size_t sz; 607*61d06d6bSBaptiste Daroussin unsigned int slot; 608*61d06d6bSBaptiste Daroussin 609*61d06d6bSBaptiste Daroussin htab = mandoc_malloc(sizeof(*htab)); 610*61d06d6bSBaptiste Daroussin mandoc_ohash_init(htab, 8, offsetof(struct roffreq, name)); 611*61d06d6bSBaptiste Daroussin 612*61d06d6bSBaptiste Daroussin for (tok = mintok; tok < maxtok; tok++) { 613*61d06d6bSBaptiste Daroussin if (roff_name[tok] == NULL) 614*61d06d6bSBaptiste Daroussin continue; 615*61d06d6bSBaptiste Daroussin sz = strlen(roff_name[tok]); 616*61d06d6bSBaptiste Daroussin req = mandoc_malloc(sizeof(*req) + sz + 1); 617*61d06d6bSBaptiste Daroussin req->tok = tok; 618*61d06d6bSBaptiste Daroussin memcpy(req->name, roff_name[tok], sz + 1); 619*61d06d6bSBaptiste Daroussin slot = ohash_qlookup(htab, req->name); 620*61d06d6bSBaptiste Daroussin ohash_insert(htab, slot, req); 621*61d06d6bSBaptiste Daroussin } 622*61d06d6bSBaptiste Daroussin return htab; 623*61d06d6bSBaptiste Daroussin } 624*61d06d6bSBaptiste Daroussin 625*61d06d6bSBaptiste Daroussin void 626*61d06d6bSBaptiste Daroussin roffhash_free(struct ohash *htab) 627*61d06d6bSBaptiste Daroussin { 628*61d06d6bSBaptiste Daroussin struct roffreq *req; 629*61d06d6bSBaptiste Daroussin unsigned int slot; 630*61d06d6bSBaptiste Daroussin 631*61d06d6bSBaptiste Daroussin if (htab == NULL) 632*61d06d6bSBaptiste Daroussin return; 633*61d06d6bSBaptiste Daroussin for (req = ohash_first(htab, &slot); req != NULL; 634*61d06d6bSBaptiste Daroussin req = ohash_next(htab, &slot)) 635*61d06d6bSBaptiste Daroussin free(req); 636*61d06d6bSBaptiste Daroussin ohash_delete(htab); 637*61d06d6bSBaptiste Daroussin free(htab); 638*61d06d6bSBaptiste Daroussin } 639*61d06d6bSBaptiste Daroussin 640*61d06d6bSBaptiste Daroussin enum roff_tok 641*61d06d6bSBaptiste Daroussin roffhash_find(struct ohash *htab, const char *name, size_t sz) 642*61d06d6bSBaptiste Daroussin { 643*61d06d6bSBaptiste Daroussin struct roffreq *req; 644*61d06d6bSBaptiste Daroussin const char *end; 645*61d06d6bSBaptiste Daroussin 646*61d06d6bSBaptiste Daroussin if (sz) { 647*61d06d6bSBaptiste Daroussin end = name + sz; 648*61d06d6bSBaptiste Daroussin req = ohash_find(htab, ohash_qlookupi(htab, name, &end)); 649*61d06d6bSBaptiste Daroussin } else 650*61d06d6bSBaptiste Daroussin req = ohash_find(htab, ohash_qlookup(htab, name)); 651*61d06d6bSBaptiste Daroussin return req == NULL ? TOKEN_NONE : req->tok; 652*61d06d6bSBaptiste Daroussin } 653*61d06d6bSBaptiste Daroussin 654*61d06d6bSBaptiste Daroussin /* --- stack of request blocks -------------------------------------------- */ 655*61d06d6bSBaptiste Daroussin 656*61d06d6bSBaptiste Daroussin /* 657*61d06d6bSBaptiste Daroussin * Pop the current node off of the stack of roff instructions currently 658*61d06d6bSBaptiste Daroussin * pending. 659*61d06d6bSBaptiste Daroussin */ 660*61d06d6bSBaptiste Daroussin static void 661*61d06d6bSBaptiste Daroussin roffnode_pop(struct roff *r) 662*61d06d6bSBaptiste Daroussin { 663*61d06d6bSBaptiste Daroussin struct roffnode *p; 664*61d06d6bSBaptiste Daroussin 665*61d06d6bSBaptiste Daroussin assert(r->last); 666*61d06d6bSBaptiste Daroussin p = r->last; 667*61d06d6bSBaptiste Daroussin 668*61d06d6bSBaptiste Daroussin r->last = r->last->parent; 669*61d06d6bSBaptiste Daroussin free(p->name); 670*61d06d6bSBaptiste Daroussin free(p->end); 671*61d06d6bSBaptiste Daroussin free(p); 672*61d06d6bSBaptiste Daroussin } 673*61d06d6bSBaptiste Daroussin 674*61d06d6bSBaptiste Daroussin /* 675*61d06d6bSBaptiste Daroussin * Push a roff node onto the instruction stack. This must later be 676*61d06d6bSBaptiste Daroussin * removed with roffnode_pop(). 677*61d06d6bSBaptiste Daroussin */ 678*61d06d6bSBaptiste Daroussin static void 679*61d06d6bSBaptiste Daroussin roffnode_push(struct roff *r, enum roff_tok tok, const char *name, 680*61d06d6bSBaptiste Daroussin int line, int col) 681*61d06d6bSBaptiste Daroussin { 682*61d06d6bSBaptiste Daroussin struct roffnode *p; 683*61d06d6bSBaptiste Daroussin 684*61d06d6bSBaptiste Daroussin p = mandoc_calloc(1, sizeof(struct roffnode)); 685*61d06d6bSBaptiste Daroussin p->tok = tok; 686*61d06d6bSBaptiste Daroussin if (name) 687*61d06d6bSBaptiste Daroussin p->name = mandoc_strdup(name); 688*61d06d6bSBaptiste Daroussin p->parent = r->last; 689*61d06d6bSBaptiste Daroussin p->line = line; 690*61d06d6bSBaptiste Daroussin p->col = col; 691*61d06d6bSBaptiste Daroussin p->rule = p->parent ? p->parent->rule : 0; 692*61d06d6bSBaptiste Daroussin 693*61d06d6bSBaptiste Daroussin r->last = p; 694*61d06d6bSBaptiste Daroussin } 695*61d06d6bSBaptiste Daroussin 696*61d06d6bSBaptiste Daroussin /* --- roff parser state data management ---------------------------------- */ 697*61d06d6bSBaptiste Daroussin 698*61d06d6bSBaptiste Daroussin static void 699*61d06d6bSBaptiste Daroussin roff_free1(struct roff *r) 700*61d06d6bSBaptiste Daroussin { 701*61d06d6bSBaptiste Daroussin struct tbl_node *tbl; 702*61d06d6bSBaptiste Daroussin int i; 703*61d06d6bSBaptiste Daroussin 704*61d06d6bSBaptiste Daroussin while (NULL != (tbl = r->first_tbl)) { 705*61d06d6bSBaptiste Daroussin r->first_tbl = tbl->next; 706*61d06d6bSBaptiste Daroussin tbl_free(tbl); 707*61d06d6bSBaptiste Daroussin } 708*61d06d6bSBaptiste Daroussin r->first_tbl = r->last_tbl = r->tbl = NULL; 709*61d06d6bSBaptiste Daroussin 710*61d06d6bSBaptiste Daroussin if (r->last_eqn != NULL) 711*61d06d6bSBaptiste Daroussin eqn_free(r->last_eqn); 712*61d06d6bSBaptiste Daroussin r->last_eqn = r->eqn = NULL; 713*61d06d6bSBaptiste Daroussin 714*61d06d6bSBaptiste Daroussin while (r->last) 715*61d06d6bSBaptiste Daroussin roffnode_pop(r); 716*61d06d6bSBaptiste Daroussin 717*61d06d6bSBaptiste Daroussin free (r->rstack); 718*61d06d6bSBaptiste Daroussin r->rstack = NULL; 719*61d06d6bSBaptiste Daroussin r->rstacksz = 0; 720*61d06d6bSBaptiste Daroussin r->rstackpos = -1; 721*61d06d6bSBaptiste Daroussin 722*61d06d6bSBaptiste Daroussin roff_freereg(r->regtab); 723*61d06d6bSBaptiste Daroussin r->regtab = NULL; 724*61d06d6bSBaptiste Daroussin 725*61d06d6bSBaptiste Daroussin roff_freestr(r->strtab); 726*61d06d6bSBaptiste Daroussin roff_freestr(r->rentab); 727*61d06d6bSBaptiste Daroussin roff_freestr(r->xmbtab); 728*61d06d6bSBaptiste Daroussin r->strtab = r->rentab = r->xmbtab = NULL; 729*61d06d6bSBaptiste Daroussin 730*61d06d6bSBaptiste Daroussin if (r->xtab) 731*61d06d6bSBaptiste Daroussin for (i = 0; i < 128; i++) 732*61d06d6bSBaptiste Daroussin free(r->xtab[i].p); 733*61d06d6bSBaptiste Daroussin free(r->xtab); 734*61d06d6bSBaptiste Daroussin r->xtab = NULL; 735*61d06d6bSBaptiste Daroussin } 736*61d06d6bSBaptiste Daroussin 737*61d06d6bSBaptiste Daroussin void 738*61d06d6bSBaptiste Daroussin roff_reset(struct roff *r) 739*61d06d6bSBaptiste Daroussin { 740*61d06d6bSBaptiste Daroussin roff_free1(r); 741*61d06d6bSBaptiste Daroussin r->format = r->options & (MPARSE_MDOC | MPARSE_MAN); 742*61d06d6bSBaptiste Daroussin r->control = '\0'; 743*61d06d6bSBaptiste Daroussin r->escape = '\\'; 744*61d06d6bSBaptiste Daroussin roffce_lines = 0; 745*61d06d6bSBaptiste Daroussin roffce_node = NULL; 746*61d06d6bSBaptiste Daroussin roffit_lines = 0; 747*61d06d6bSBaptiste Daroussin roffit_macro = NULL; 748*61d06d6bSBaptiste Daroussin } 749*61d06d6bSBaptiste Daroussin 750*61d06d6bSBaptiste Daroussin void 751*61d06d6bSBaptiste Daroussin roff_free(struct roff *r) 752*61d06d6bSBaptiste Daroussin { 753*61d06d6bSBaptiste Daroussin roff_free1(r); 754*61d06d6bSBaptiste Daroussin roffhash_free(r->reqtab); 755*61d06d6bSBaptiste Daroussin free(r); 756*61d06d6bSBaptiste Daroussin } 757*61d06d6bSBaptiste Daroussin 758*61d06d6bSBaptiste Daroussin struct roff * 759*61d06d6bSBaptiste Daroussin roff_alloc(struct mparse *parse, int options) 760*61d06d6bSBaptiste Daroussin { 761*61d06d6bSBaptiste Daroussin struct roff *r; 762*61d06d6bSBaptiste Daroussin 763*61d06d6bSBaptiste Daroussin r = mandoc_calloc(1, sizeof(struct roff)); 764*61d06d6bSBaptiste Daroussin r->parse = parse; 765*61d06d6bSBaptiste Daroussin r->reqtab = roffhash_alloc(0, ROFF_RENAMED); 766*61d06d6bSBaptiste Daroussin r->options = options; 767*61d06d6bSBaptiste Daroussin r->format = options & (MPARSE_MDOC | MPARSE_MAN); 768*61d06d6bSBaptiste Daroussin r->rstackpos = -1; 769*61d06d6bSBaptiste Daroussin r->escape = '\\'; 770*61d06d6bSBaptiste Daroussin return r; 771*61d06d6bSBaptiste Daroussin } 772*61d06d6bSBaptiste Daroussin 773*61d06d6bSBaptiste Daroussin /* --- syntax tree state data management ---------------------------------- */ 774*61d06d6bSBaptiste Daroussin 775*61d06d6bSBaptiste Daroussin static void 776*61d06d6bSBaptiste Daroussin roff_man_free1(struct roff_man *man) 777*61d06d6bSBaptiste Daroussin { 778*61d06d6bSBaptiste Daroussin 779*61d06d6bSBaptiste Daroussin if (man->first != NULL) 780*61d06d6bSBaptiste Daroussin roff_node_delete(man, man->first); 781*61d06d6bSBaptiste Daroussin free(man->meta.msec); 782*61d06d6bSBaptiste Daroussin free(man->meta.vol); 783*61d06d6bSBaptiste Daroussin free(man->meta.os); 784*61d06d6bSBaptiste Daroussin free(man->meta.arch); 785*61d06d6bSBaptiste Daroussin free(man->meta.title); 786*61d06d6bSBaptiste Daroussin free(man->meta.name); 787*61d06d6bSBaptiste Daroussin free(man->meta.date); 788*61d06d6bSBaptiste Daroussin } 789*61d06d6bSBaptiste Daroussin 790*61d06d6bSBaptiste Daroussin static void 791*61d06d6bSBaptiste Daroussin roff_man_alloc1(struct roff_man *man) 792*61d06d6bSBaptiste Daroussin { 793*61d06d6bSBaptiste Daroussin 794*61d06d6bSBaptiste Daroussin memset(&man->meta, 0, sizeof(man->meta)); 795*61d06d6bSBaptiste Daroussin man->first = mandoc_calloc(1, sizeof(*man->first)); 796*61d06d6bSBaptiste Daroussin man->first->type = ROFFT_ROOT; 797*61d06d6bSBaptiste Daroussin man->last = man->first; 798*61d06d6bSBaptiste Daroussin man->last_es = NULL; 799*61d06d6bSBaptiste Daroussin man->flags = 0; 800*61d06d6bSBaptiste Daroussin man->macroset = MACROSET_NONE; 801*61d06d6bSBaptiste Daroussin man->lastsec = man->lastnamed = SEC_NONE; 802*61d06d6bSBaptiste Daroussin man->next = ROFF_NEXT_CHILD; 803*61d06d6bSBaptiste Daroussin } 804*61d06d6bSBaptiste Daroussin 805*61d06d6bSBaptiste Daroussin void 806*61d06d6bSBaptiste Daroussin roff_man_reset(struct roff_man *man) 807*61d06d6bSBaptiste Daroussin { 808*61d06d6bSBaptiste Daroussin 809*61d06d6bSBaptiste Daroussin roff_man_free1(man); 810*61d06d6bSBaptiste Daroussin roff_man_alloc1(man); 811*61d06d6bSBaptiste Daroussin } 812*61d06d6bSBaptiste Daroussin 813*61d06d6bSBaptiste Daroussin void 814*61d06d6bSBaptiste Daroussin roff_man_free(struct roff_man *man) 815*61d06d6bSBaptiste Daroussin { 816*61d06d6bSBaptiste Daroussin 817*61d06d6bSBaptiste Daroussin roff_man_free1(man); 818*61d06d6bSBaptiste Daroussin free(man); 819*61d06d6bSBaptiste Daroussin } 820*61d06d6bSBaptiste Daroussin 821*61d06d6bSBaptiste Daroussin struct roff_man * 822*61d06d6bSBaptiste Daroussin roff_man_alloc(struct roff *roff, struct mparse *parse, 823*61d06d6bSBaptiste Daroussin const char *os_s, int quick) 824*61d06d6bSBaptiste Daroussin { 825*61d06d6bSBaptiste Daroussin struct roff_man *man; 826*61d06d6bSBaptiste Daroussin 827*61d06d6bSBaptiste Daroussin man = mandoc_calloc(1, sizeof(*man)); 828*61d06d6bSBaptiste Daroussin man->parse = parse; 829*61d06d6bSBaptiste Daroussin man->roff = roff; 830*61d06d6bSBaptiste Daroussin man->os_s = os_s; 831*61d06d6bSBaptiste Daroussin man->quick = quick; 832*61d06d6bSBaptiste Daroussin roff_man_alloc1(man); 833*61d06d6bSBaptiste Daroussin roff->man = man; 834*61d06d6bSBaptiste Daroussin return man; 835*61d06d6bSBaptiste Daroussin } 836*61d06d6bSBaptiste Daroussin 837*61d06d6bSBaptiste Daroussin /* --- syntax tree handling ----------------------------------------------- */ 838*61d06d6bSBaptiste Daroussin 839*61d06d6bSBaptiste Daroussin struct roff_node * 840*61d06d6bSBaptiste Daroussin roff_node_alloc(struct roff_man *man, int line, int pos, 841*61d06d6bSBaptiste Daroussin enum roff_type type, int tok) 842*61d06d6bSBaptiste Daroussin { 843*61d06d6bSBaptiste Daroussin struct roff_node *n; 844*61d06d6bSBaptiste Daroussin 845*61d06d6bSBaptiste Daroussin n = mandoc_calloc(1, sizeof(*n)); 846*61d06d6bSBaptiste Daroussin n->line = line; 847*61d06d6bSBaptiste Daroussin n->pos = pos; 848*61d06d6bSBaptiste Daroussin n->tok = tok; 849*61d06d6bSBaptiste Daroussin n->type = type; 850*61d06d6bSBaptiste Daroussin n->sec = man->lastsec; 851*61d06d6bSBaptiste Daroussin 852*61d06d6bSBaptiste Daroussin if (man->flags & MDOC_SYNOPSIS) 853*61d06d6bSBaptiste Daroussin n->flags |= NODE_SYNPRETTY; 854*61d06d6bSBaptiste Daroussin else 855*61d06d6bSBaptiste Daroussin n->flags &= ~NODE_SYNPRETTY; 856*61d06d6bSBaptiste Daroussin if (man->flags & MDOC_NEWLINE) 857*61d06d6bSBaptiste Daroussin n->flags |= NODE_LINE; 858*61d06d6bSBaptiste Daroussin man->flags &= ~MDOC_NEWLINE; 859*61d06d6bSBaptiste Daroussin 860*61d06d6bSBaptiste Daroussin return n; 861*61d06d6bSBaptiste Daroussin } 862*61d06d6bSBaptiste Daroussin 863*61d06d6bSBaptiste Daroussin void 864*61d06d6bSBaptiste Daroussin roff_node_append(struct roff_man *man, struct roff_node *n) 865*61d06d6bSBaptiste Daroussin { 866*61d06d6bSBaptiste Daroussin 867*61d06d6bSBaptiste Daroussin switch (man->next) { 868*61d06d6bSBaptiste Daroussin case ROFF_NEXT_SIBLING: 869*61d06d6bSBaptiste Daroussin if (man->last->next != NULL) { 870*61d06d6bSBaptiste Daroussin n->next = man->last->next; 871*61d06d6bSBaptiste Daroussin man->last->next->prev = n; 872*61d06d6bSBaptiste Daroussin } else 873*61d06d6bSBaptiste Daroussin man->last->parent->last = n; 874*61d06d6bSBaptiste Daroussin man->last->next = n; 875*61d06d6bSBaptiste Daroussin n->prev = man->last; 876*61d06d6bSBaptiste Daroussin n->parent = man->last->parent; 877*61d06d6bSBaptiste Daroussin break; 878*61d06d6bSBaptiste Daroussin case ROFF_NEXT_CHILD: 879*61d06d6bSBaptiste Daroussin if (man->last->child != NULL) { 880*61d06d6bSBaptiste Daroussin n->next = man->last->child; 881*61d06d6bSBaptiste Daroussin man->last->child->prev = n; 882*61d06d6bSBaptiste Daroussin } else 883*61d06d6bSBaptiste Daroussin man->last->last = n; 884*61d06d6bSBaptiste Daroussin man->last->child = n; 885*61d06d6bSBaptiste Daroussin n->parent = man->last; 886*61d06d6bSBaptiste Daroussin break; 887*61d06d6bSBaptiste Daroussin default: 888*61d06d6bSBaptiste Daroussin abort(); 889*61d06d6bSBaptiste Daroussin } 890*61d06d6bSBaptiste Daroussin man->last = n; 891*61d06d6bSBaptiste Daroussin 892*61d06d6bSBaptiste Daroussin switch (n->type) { 893*61d06d6bSBaptiste Daroussin case ROFFT_HEAD: 894*61d06d6bSBaptiste Daroussin n->parent->head = n; 895*61d06d6bSBaptiste Daroussin break; 896*61d06d6bSBaptiste Daroussin case ROFFT_BODY: 897*61d06d6bSBaptiste Daroussin if (n->end != ENDBODY_NOT) 898*61d06d6bSBaptiste Daroussin return; 899*61d06d6bSBaptiste Daroussin n->parent->body = n; 900*61d06d6bSBaptiste Daroussin break; 901*61d06d6bSBaptiste Daroussin case ROFFT_TAIL: 902*61d06d6bSBaptiste Daroussin n->parent->tail = n; 903*61d06d6bSBaptiste Daroussin break; 904*61d06d6bSBaptiste Daroussin default: 905*61d06d6bSBaptiste Daroussin return; 906*61d06d6bSBaptiste Daroussin } 907*61d06d6bSBaptiste Daroussin 908*61d06d6bSBaptiste Daroussin /* 909*61d06d6bSBaptiste Daroussin * Copy over the normalised-data pointer of our parent. Not 910*61d06d6bSBaptiste Daroussin * everybody has one, but copying a null pointer is fine. 911*61d06d6bSBaptiste Daroussin */ 912*61d06d6bSBaptiste Daroussin 913*61d06d6bSBaptiste Daroussin n->norm = n->parent->norm; 914*61d06d6bSBaptiste Daroussin assert(n->parent->type == ROFFT_BLOCK); 915*61d06d6bSBaptiste Daroussin } 916*61d06d6bSBaptiste Daroussin 917*61d06d6bSBaptiste Daroussin void 918*61d06d6bSBaptiste Daroussin roff_word_alloc(struct roff_man *man, int line, int pos, const char *word) 919*61d06d6bSBaptiste Daroussin { 920*61d06d6bSBaptiste Daroussin struct roff_node *n; 921*61d06d6bSBaptiste Daroussin 922*61d06d6bSBaptiste Daroussin n = roff_node_alloc(man, line, pos, ROFFT_TEXT, TOKEN_NONE); 923*61d06d6bSBaptiste Daroussin n->string = roff_strdup(man->roff, word); 924*61d06d6bSBaptiste Daroussin roff_node_append(man, n); 925*61d06d6bSBaptiste Daroussin n->flags |= NODE_VALID | NODE_ENDED; 926*61d06d6bSBaptiste Daroussin man->next = ROFF_NEXT_SIBLING; 927*61d06d6bSBaptiste Daroussin } 928*61d06d6bSBaptiste Daroussin 929*61d06d6bSBaptiste Daroussin void 930*61d06d6bSBaptiste Daroussin roff_word_append(struct roff_man *man, const char *word) 931*61d06d6bSBaptiste Daroussin { 932*61d06d6bSBaptiste Daroussin struct roff_node *n; 933*61d06d6bSBaptiste Daroussin char *addstr, *newstr; 934*61d06d6bSBaptiste Daroussin 935*61d06d6bSBaptiste Daroussin n = man->last; 936*61d06d6bSBaptiste Daroussin addstr = roff_strdup(man->roff, word); 937*61d06d6bSBaptiste Daroussin mandoc_asprintf(&newstr, "%s %s", n->string, addstr); 938*61d06d6bSBaptiste Daroussin free(addstr); 939*61d06d6bSBaptiste Daroussin free(n->string); 940*61d06d6bSBaptiste Daroussin n->string = newstr; 941*61d06d6bSBaptiste Daroussin man->next = ROFF_NEXT_SIBLING; 942*61d06d6bSBaptiste Daroussin } 943*61d06d6bSBaptiste Daroussin 944*61d06d6bSBaptiste Daroussin void 945*61d06d6bSBaptiste Daroussin roff_elem_alloc(struct roff_man *man, int line, int pos, int tok) 946*61d06d6bSBaptiste Daroussin { 947*61d06d6bSBaptiste Daroussin struct roff_node *n; 948*61d06d6bSBaptiste Daroussin 949*61d06d6bSBaptiste Daroussin n = roff_node_alloc(man, line, pos, ROFFT_ELEM, tok); 950*61d06d6bSBaptiste Daroussin roff_node_append(man, n); 951*61d06d6bSBaptiste Daroussin man->next = ROFF_NEXT_CHILD; 952*61d06d6bSBaptiste Daroussin } 953*61d06d6bSBaptiste Daroussin 954*61d06d6bSBaptiste Daroussin struct roff_node * 955*61d06d6bSBaptiste Daroussin roff_block_alloc(struct roff_man *man, int line, int pos, int tok) 956*61d06d6bSBaptiste Daroussin { 957*61d06d6bSBaptiste Daroussin struct roff_node *n; 958*61d06d6bSBaptiste Daroussin 959*61d06d6bSBaptiste Daroussin n = roff_node_alloc(man, line, pos, ROFFT_BLOCK, tok); 960*61d06d6bSBaptiste Daroussin roff_node_append(man, n); 961*61d06d6bSBaptiste Daroussin man->next = ROFF_NEXT_CHILD; 962*61d06d6bSBaptiste Daroussin return n; 963*61d06d6bSBaptiste Daroussin } 964*61d06d6bSBaptiste Daroussin 965*61d06d6bSBaptiste Daroussin struct roff_node * 966*61d06d6bSBaptiste Daroussin roff_head_alloc(struct roff_man *man, int line, int pos, int tok) 967*61d06d6bSBaptiste Daroussin { 968*61d06d6bSBaptiste Daroussin struct roff_node *n; 969*61d06d6bSBaptiste Daroussin 970*61d06d6bSBaptiste Daroussin n = roff_node_alloc(man, line, pos, ROFFT_HEAD, tok); 971*61d06d6bSBaptiste Daroussin roff_node_append(man, n); 972*61d06d6bSBaptiste Daroussin man->next = ROFF_NEXT_CHILD; 973*61d06d6bSBaptiste Daroussin return n; 974*61d06d6bSBaptiste Daroussin } 975*61d06d6bSBaptiste Daroussin 976*61d06d6bSBaptiste Daroussin struct roff_node * 977*61d06d6bSBaptiste Daroussin roff_body_alloc(struct roff_man *man, int line, int pos, int tok) 978*61d06d6bSBaptiste Daroussin { 979*61d06d6bSBaptiste Daroussin struct roff_node *n; 980*61d06d6bSBaptiste Daroussin 981*61d06d6bSBaptiste Daroussin n = roff_node_alloc(man, line, pos, ROFFT_BODY, tok); 982*61d06d6bSBaptiste Daroussin roff_node_append(man, n); 983*61d06d6bSBaptiste Daroussin man->next = ROFF_NEXT_CHILD; 984*61d06d6bSBaptiste Daroussin return n; 985*61d06d6bSBaptiste Daroussin } 986*61d06d6bSBaptiste Daroussin 987*61d06d6bSBaptiste Daroussin static void 988*61d06d6bSBaptiste Daroussin roff_addtbl(struct roff_man *man, struct tbl_node *tbl) 989*61d06d6bSBaptiste Daroussin { 990*61d06d6bSBaptiste Daroussin struct roff_node *n; 991*61d06d6bSBaptiste Daroussin const struct tbl_span *span; 992*61d06d6bSBaptiste Daroussin 993*61d06d6bSBaptiste Daroussin if (man->macroset == MACROSET_MAN) 994*61d06d6bSBaptiste Daroussin man_breakscope(man, ROFF_TS); 995*61d06d6bSBaptiste Daroussin while ((span = tbl_span(tbl)) != NULL) { 996*61d06d6bSBaptiste Daroussin n = roff_node_alloc(man, tbl->line, 0, ROFFT_TBL, TOKEN_NONE); 997*61d06d6bSBaptiste Daroussin n->span = span; 998*61d06d6bSBaptiste Daroussin roff_node_append(man, n); 999*61d06d6bSBaptiste Daroussin n->flags |= NODE_VALID | NODE_ENDED; 1000*61d06d6bSBaptiste Daroussin man->next = ROFF_NEXT_SIBLING; 1001*61d06d6bSBaptiste Daroussin } 1002*61d06d6bSBaptiste Daroussin } 1003*61d06d6bSBaptiste Daroussin 1004*61d06d6bSBaptiste Daroussin void 1005*61d06d6bSBaptiste Daroussin roff_node_unlink(struct roff_man *man, struct roff_node *n) 1006*61d06d6bSBaptiste Daroussin { 1007*61d06d6bSBaptiste Daroussin 1008*61d06d6bSBaptiste Daroussin /* Adjust siblings. */ 1009*61d06d6bSBaptiste Daroussin 1010*61d06d6bSBaptiste Daroussin if (n->prev) 1011*61d06d6bSBaptiste Daroussin n->prev->next = n->next; 1012*61d06d6bSBaptiste Daroussin if (n->next) 1013*61d06d6bSBaptiste Daroussin n->next->prev = n->prev; 1014*61d06d6bSBaptiste Daroussin 1015*61d06d6bSBaptiste Daroussin /* Adjust parent. */ 1016*61d06d6bSBaptiste Daroussin 1017*61d06d6bSBaptiste Daroussin if (n->parent != NULL) { 1018*61d06d6bSBaptiste Daroussin if (n->parent->child == n) 1019*61d06d6bSBaptiste Daroussin n->parent->child = n->next; 1020*61d06d6bSBaptiste Daroussin if (n->parent->last == n) 1021*61d06d6bSBaptiste Daroussin n->parent->last = n->prev; 1022*61d06d6bSBaptiste Daroussin } 1023*61d06d6bSBaptiste Daroussin 1024*61d06d6bSBaptiste Daroussin /* Adjust parse point. */ 1025*61d06d6bSBaptiste Daroussin 1026*61d06d6bSBaptiste Daroussin if (man == NULL) 1027*61d06d6bSBaptiste Daroussin return; 1028*61d06d6bSBaptiste Daroussin if (man->last == n) { 1029*61d06d6bSBaptiste Daroussin if (n->prev == NULL) { 1030*61d06d6bSBaptiste Daroussin man->last = n->parent; 1031*61d06d6bSBaptiste Daroussin man->next = ROFF_NEXT_CHILD; 1032*61d06d6bSBaptiste Daroussin } else { 1033*61d06d6bSBaptiste Daroussin man->last = n->prev; 1034*61d06d6bSBaptiste Daroussin man->next = ROFF_NEXT_SIBLING; 1035*61d06d6bSBaptiste Daroussin } 1036*61d06d6bSBaptiste Daroussin } 1037*61d06d6bSBaptiste Daroussin if (man->first == n) 1038*61d06d6bSBaptiste Daroussin man->first = NULL; 1039*61d06d6bSBaptiste Daroussin } 1040*61d06d6bSBaptiste Daroussin 1041*61d06d6bSBaptiste Daroussin void 1042*61d06d6bSBaptiste Daroussin roff_node_free(struct roff_node *n) 1043*61d06d6bSBaptiste Daroussin { 1044*61d06d6bSBaptiste Daroussin 1045*61d06d6bSBaptiste Daroussin if (n->args != NULL) 1046*61d06d6bSBaptiste Daroussin mdoc_argv_free(n->args); 1047*61d06d6bSBaptiste Daroussin if (n->type == ROFFT_BLOCK || n->type == ROFFT_ELEM) 1048*61d06d6bSBaptiste Daroussin free(n->norm); 1049*61d06d6bSBaptiste Daroussin if (n->eqn != NULL) 1050*61d06d6bSBaptiste Daroussin eqn_box_free(n->eqn); 1051*61d06d6bSBaptiste Daroussin free(n->string); 1052*61d06d6bSBaptiste Daroussin free(n); 1053*61d06d6bSBaptiste Daroussin } 1054*61d06d6bSBaptiste Daroussin 1055*61d06d6bSBaptiste Daroussin void 1056*61d06d6bSBaptiste Daroussin roff_node_delete(struct roff_man *man, struct roff_node *n) 1057*61d06d6bSBaptiste Daroussin { 1058*61d06d6bSBaptiste Daroussin 1059*61d06d6bSBaptiste Daroussin while (n->child != NULL) 1060*61d06d6bSBaptiste Daroussin roff_node_delete(man, n->child); 1061*61d06d6bSBaptiste Daroussin roff_node_unlink(man, n); 1062*61d06d6bSBaptiste Daroussin roff_node_free(n); 1063*61d06d6bSBaptiste Daroussin } 1064*61d06d6bSBaptiste Daroussin 1065*61d06d6bSBaptiste Daroussin void 1066*61d06d6bSBaptiste Daroussin deroff(char **dest, const struct roff_node *n) 1067*61d06d6bSBaptiste Daroussin { 1068*61d06d6bSBaptiste Daroussin char *cp; 1069*61d06d6bSBaptiste Daroussin size_t sz; 1070*61d06d6bSBaptiste Daroussin 1071*61d06d6bSBaptiste Daroussin if (n->type != ROFFT_TEXT) { 1072*61d06d6bSBaptiste Daroussin for (n = n->child; n != NULL; n = n->next) 1073*61d06d6bSBaptiste Daroussin deroff(dest, n); 1074*61d06d6bSBaptiste Daroussin return; 1075*61d06d6bSBaptiste Daroussin } 1076*61d06d6bSBaptiste Daroussin 1077*61d06d6bSBaptiste Daroussin /* Skip leading whitespace. */ 1078*61d06d6bSBaptiste Daroussin 1079*61d06d6bSBaptiste Daroussin for (cp = n->string; *cp != '\0'; cp++) { 1080*61d06d6bSBaptiste Daroussin if (cp[0] == '\\' && cp[1] != '\0' && 1081*61d06d6bSBaptiste Daroussin strchr(" %&0^|~", cp[1]) != NULL) 1082*61d06d6bSBaptiste Daroussin cp++; 1083*61d06d6bSBaptiste Daroussin else if ( ! isspace((unsigned char)*cp)) 1084*61d06d6bSBaptiste Daroussin break; 1085*61d06d6bSBaptiste Daroussin } 1086*61d06d6bSBaptiste Daroussin 1087*61d06d6bSBaptiste Daroussin /* Skip trailing backslash. */ 1088*61d06d6bSBaptiste Daroussin 1089*61d06d6bSBaptiste Daroussin sz = strlen(cp); 1090*61d06d6bSBaptiste Daroussin if (sz > 0 && cp[sz - 1] == '\\') 1091*61d06d6bSBaptiste Daroussin sz--; 1092*61d06d6bSBaptiste Daroussin 1093*61d06d6bSBaptiste Daroussin /* Skip trailing whitespace. */ 1094*61d06d6bSBaptiste Daroussin 1095*61d06d6bSBaptiste Daroussin for (; sz; sz--) 1096*61d06d6bSBaptiste Daroussin if ( ! isspace((unsigned char)cp[sz-1])) 1097*61d06d6bSBaptiste Daroussin break; 1098*61d06d6bSBaptiste Daroussin 1099*61d06d6bSBaptiste Daroussin /* Skip empty strings. */ 1100*61d06d6bSBaptiste Daroussin 1101*61d06d6bSBaptiste Daroussin if (sz == 0) 1102*61d06d6bSBaptiste Daroussin return; 1103*61d06d6bSBaptiste Daroussin 1104*61d06d6bSBaptiste Daroussin if (*dest == NULL) { 1105*61d06d6bSBaptiste Daroussin *dest = mandoc_strndup(cp, sz); 1106*61d06d6bSBaptiste Daroussin return; 1107*61d06d6bSBaptiste Daroussin } 1108*61d06d6bSBaptiste Daroussin 1109*61d06d6bSBaptiste Daroussin mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp); 1110*61d06d6bSBaptiste Daroussin free(*dest); 1111*61d06d6bSBaptiste Daroussin *dest = cp; 1112*61d06d6bSBaptiste Daroussin } 1113*61d06d6bSBaptiste Daroussin 1114*61d06d6bSBaptiste Daroussin /* --- main functions of the roff parser ---------------------------------- */ 1115*61d06d6bSBaptiste Daroussin 1116*61d06d6bSBaptiste Daroussin /* 1117*61d06d6bSBaptiste Daroussin * In the current line, expand escape sequences that tend to get 1118*61d06d6bSBaptiste Daroussin * used in numerical expressions and conditional requests. 1119*61d06d6bSBaptiste Daroussin * Also check the syntax of the remaining escape sequences. 1120*61d06d6bSBaptiste Daroussin */ 1121*61d06d6bSBaptiste Daroussin static enum rofferr 1122*61d06d6bSBaptiste Daroussin roff_res(struct roff *r, struct buf *buf, int ln, int pos) 1123*61d06d6bSBaptiste Daroussin { 1124*61d06d6bSBaptiste Daroussin char ubuf[24]; /* buffer to print the number */ 1125*61d06d6bSBaptiste Daroussin struct roff_node *n; /* used for header comments */ 1126*61d06d6bSBaptiste Daroussin const char *start; /* start of the string to process */ 1127*61d06d6bSBaptiste Daroussin char *stesc; /* start of an escape sequence ('\\') */ 1128*61d06d6bSBaptiste Daroussin char *ep; /* end of comment string */ 1129*61d06d6bSBaptiste Daroussin const char *stnam; /* start of the name, after "[(*" */ 1130*61d06d6bSBaptiste Daroussin const char *cp; /* end of the name, e.g. before ']' */ 1131*61d06d6bSBaptiste Daroussin const char *res; /* the string to be substituted */ 1132*61d06d6bSBaptiste Daroussin char *nbuf; /* new buffer to copy buf->buf to */ 1133*61d06d6bSBaptiste Daroussin size_t maxl; /* expected length of the escape name */ 1134*61d06d6bSBaptiste Daroussin size_t naml; /* actual length of the escape name */ 1135*61d06d6bSBaptiste Daroussin enum mandoc_esc esc; /* type of the escape sequence */ 1136*61d06d6bSBaptiste Daroussin int inaml; /* length returned from mandoc_escape() */ 1137*61d06d6bSBaptiste Daroussin int expand_count; /* to avoid infinite loops */ 1138*61d06d6bSBaptiste Daroussin int npos; /* position in numeric expression */ 1139*61d06d6bSBaptiste Daroussin int arg_complete; /* argument not interrupted by eol */ 1140*61d06d6bSBaptiste Daroussin int done; /* no more input available */ 1141*61d06d6bSBaptiste Daroussin int deftype; /* type of definition to paste */ 1142*61d06d6bSBaptiste Daroussin int rcsid; /* kind of RCS id seen */ 1143*61d06d6bSBaptiste Daroussin char sign; /* increment number register */ 1144*61d06d6bSBaptiste Daroussin char term; /* character terminating the escape */ 1145*61d06d6bSBaptiste Daroussin 1146*61d06d6bSBaptiste Daroussin /* Search forward for comments. */ 1147*61d06d6bSBaptiste Daroussin 1148*61d06d6bSBaptiste Daroussin done = 0; 1149*61d06d6bSBaptiste Daroussin start = buf->buf + pos; 1150*61d06d6bSBaptiste Daroussin for (stesc = buf->buf + pos; *stesc != '\0'; stesc++) { 1151*61d06d6bSBaptiste Daroussin if (stesc[0] != r->escape || stesc[1] == '\0') 1152*61d06d6bSBaptiste Daroussin continue; 1153*61d06d6bSBaptiste Daroussin stesc++; 1154*61d06d6bSBaptiste Daroussin if (*stesc != '"' && *stesc != '#') 1155*61d06d6bSBaptiste Daroussin continue; 1156*61d06d6bSBaptiste Daroussin 1157*61d06d6bSBaptiste Daroussin /* Comment found, look for RCS id. */ 1158*61d06d6bSBaptiste Daroussin 1159*61d06d6bSBaptiste Daroussin rcsid = 0; 1160*61d06d6bSBaptiste Daroussin if ((cp = strstr(stesc, "$" "OpenBSD")) != NULL) { 1161*61d06d6bSBaptiste Daroussin rcsid = 1 << MANDOC_OS_OPENBSD; 1162*61d06d6bSBaptiste Daroussin cp += 8; 1163*61d06d6bSBaptiste Daroussin } else if ((cp = strstr(stesc, "$" "NetBSD")) != NULL) { 1164*61d06d6bSBaptiste Daroussin rcsid = 1 << MANDOC_OS_NETBSD; 1165*61d06d6bSBaptiste Daroussin cp += 7; 1166*61d06d6bSBaptiste Daroussin } 1167*61d06d6bSBaptiste Daroussin if (cp != NULL && 1168*61d06d6bSBaptiste Daroussin isalnum((unsigned char)*cp) == 0 && 1169*61d06d6bSBaptiste Daroussin strchr(cp, '$') != NULL) { 1170*61d06d6bSBaptiste Daroussin if (r->man->meta.rcsids & rcsid) 1171*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_RCS_REP, r->parse, 1172*61d06d6bSBaptiste Daroussin ln, stesc + 1 - buf->buf, stesc + 1); 1173*61d06d6bSBaptiste Daroussin r->man->meta.rcsids |= rcsid; 1174*61d06d6bSBaptiste Daroussin } 1175*61d06d6bSBaptiste Daroussin 1176*61d06d6bSBaptiste Daroussin /* Handle trailing whitespace. */ 1177*61d06d6bSBaptiste Daroussin 1178*61d06d6bSBaptiste Daroussin ep = strchr(stesc--, '\0') - 1; 1179*61d06d6bSBaptiste Daroussin if (*ep == '\n') { 1180*61d06d6bSBaptiste Daroussin done = 1; 1181*61d06d6bSBaptiste Daroussin ep--; 1182*61d06d6bSBaptiste Daroussin } 1183*61d06d6bSBaptiste Daroussin if (*ep == ' ' || *ep == '\t') 1184*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_SPACE_EOL, r->parse, 1185*61d06d6bSBaptiste Daroussin ln, ep - buf->buf, NULL); 1186*61d06d6bSBaptiste Daroussin 1187*61d06d6bSBaptiste Daroussin /* 1188*61d06d6bSBaptiste Daroussin * Save comments preceding the title macro 1189*61d06d6bSBaptiste Daroussin * in the syntax tree. 1190*61d06d6bSBaptiste Daroussin */ 1191*61d06d6bSBaptiste Daroussin 1192*61d06d6bSBaptiste Daroussin if (r->format == 0) { 1193*61d06d6bSBaptiste Daroussin while (*ep == ' ' || *ep == '\t') 1194*61d06d6bSBaptiste Daroussin ep--; 1195*61d06d6bSBaptiste Daroussin ep[1] = '\0'; 1196*61d06d6bSBaptiste Daroussin n = roff_node_alloc(r->man, 1197*61d06d6bSBaptiste Daroussin ln, stesc + 1 - buf->buf, 1198*61d06d6bSBaptiste Daroussin ROFFT_COMMENT, TOKEN_NONE); 1199*61d06d6bSBaptiste Daroussin n->string = mandoc_strdup(stesc + 2); 1200*61d06d6bSBaptiste Daroussin roff_node_append(r->man, n); 1201*61d06d6bSBaptiste Daroussin n->flags |= NODE_VALID | NODE_ENDED; 1202*61d06d6bSBaptiste Daroussin r->man->next = ROFF_NEXT_SIBLING; 1203*61d06d6bSBaptiste Daroussin } 1204*61d06d6bSBaptiste Daroussin 1205*61d06d6bSBaptiste Daroussin /* Discard comments. */ 1206*61d06d6bSBaptiste Daroussin 1207*61d06d6bSBaptiste Daroussin while (stesc > start && stesc[-1] == ' ') 1208*61d06d6bSBaptiste Daroussin stesc--; 1209*61d06d6bSBaptiste Daroussin *stesc = '\0'; 1210*61d06d6bSBaptiste Daroussin break; 1211*61d06d6bSBaptiste Daroussin } 1212*61d06d6bSBaptiste Daroussin if (stesc == start) 1213*61d06d6bSBaptiste Daroussin return ROFF_CONT; 1214*61d06d6bSBaptiste Daroussin stesc--; 1215*61d06d6bSBaptiste Daroussin 1216*61d06d6bSBaptiste Daroussin /* Notice the end of the input. */ 1217*61d06d6bSBaptiste Daroussin 1218*61d06d6bSBaptiste Daroussin if (*stesc == '\n') { 1219*61d06d6bSBaptiste Daroussin *stesc-- = '\0'; 1220*61d06d6bSBaptiste Daroussin done = 1; 1221*61d06d6bSBaptiste Daroussin } 1222*61d06d6bSBaptiste Daroussin 1223*61d06d6bSBaptiste Daroussin expand_count = 0; 1224*61d06d6bSBaptiste Daroussin while (stesc >= start) { 1225*61d06d6bSBaptiste Daroussin 1226*61d06d6bSBaptiste Daroussin /* Search backwards for the next backslash. */ 1227*61d06d6bSBaptiste Daroussin 1228*61d06d6bSBaptiste Daroussin if (*stesc != r->escape) { 1229*61d06d6bSBaptiste Daroussin if (*stesc == '\\') { 1230*61d06d6bSBaptiste Daroussin *stesc = '\0'; 1231*61d06d6bSBaptiste Daroussin buf->sz = mandoc_asprintf(&nbuf, "%s\\e%s", 1232*61d06d6bSBaptiste Daroussin buf->buf, stesc + 1) + 1; 1233*61d06d6bSBaptiste Daroussin start = nbuf + pos; 1234*61d06d6bSBaptiste Daroussin stesc = nbuf + (stesc - buf->buf); 1235*61d06d6bSBaptiste Daroussin free(buf->buf); 1236*61d06d6bSBaptiste Daroussin buf->buf = nbuf; 1237*61d06d6bSBaptiste Daroussin } 1238*61d06d6bSBaptiste Daroussin stesc--; 1239*61d06d6bSBaptiste Daroussin continue; 1240*61d06d6bSBaptiste Daroussin } 1241*61d06d6bSBaptiste Daroussin 1242*61d06d6bSBaptiste Daroussin /* If it is escaped, skip it. */ 1243*61d06d6bSBaptiste Daroussin 1244*61d06d6bSBaptiste Daroussin for (cp = stesc - 1; cp >= start; cp--) 1245*61d06d6bSBaptiste Daroussin if (*cp != r->escape) 1246*61d06d6bSBaptiste Daroussin break; 1247*61d06d6bSBaptiste Daroussin 1248*61d06d6bSBaptiste Daroussin if ((stesc - cp) % 2 == 0) { 1249*61d06d6bSBaptiste Daroussin while (stesc > cp) 1250*61d06d6bSBaptiste Daroussin *stesc-- = '\\'; 1251*61d06d6bSBaptiste Daroussin continue; 1252*61d06d6bSBaptiste Daroussin } else if (stesc[1] != '\0') { 1253*61d06d6bSBaptiste Daroussin *stesc = '\\'; 1254*61d06d6bSBaptiste Daroussin } else { 1255*61d06d6bSBaptiste Daroussin *stesc-- = '\0'; 1256*61d06d6bSBaptiste Daroussin if (done) 1257*61d06d6bSBaptiste Daroussin continue; 1258*61d06d6bSBaptiste Daroussin else 1259*61d06d6bSBaptiste Daroussin return ROFF_APPEND; 1260*61d06d6bSBaptiste Daroussin } 1261*61d06d6bSBaptiste Daroussin 1262*61d06d6bSBaptiste Daroussin /* Decide whether to expand or to check only. */ 1263*61d06d6bSBaptiste Daroussin 1264*61d06d6bSBaptiste Daroussin term = '\0'; 1265*61d06d6bSBaptiste Daroussin cp = stesc + 1; 1266*61d06d6bSBaptiste Daroussin switch (*cp) { 1267*61d06d6bSBaptiste Daroussin case '*': 1268*61d06d6bSBaptiste Daroussin res = NULL; 1269*61d06d6bSBaptiste Daroussin break; 1270*61d06d6bSBaptiste Daroussin case 'B': 1271*61d06d6bSBaptiste Daroussin case 'w': 1272*61d06d6bSBaptiste Daroussin term = cp[1]; 1273*61d06d6bSBaptiste Daroussin /* FALLTHROUGH */ 1274*61d06d6bSBaptiste Daroussin case 'n': 1275*61d06d6bSBaptiste Daroussin sign = cp[1]; 1276*61d06d6bSBaptiste Daroussin if (sign == '+' || sign == '-') 1277*61d06d6bSBaptiste Daroussin cp++; 1278*61d06d6bSBaptiste Daroussin res = ubuf; 1279*61d06d6bSBaptiste Daroussin break; 1280*61d06d6bSBaptiste Daroussin default: 1281*61d06d6bSBaptiste Daroussin esc = mandoc_escape(&cp, &stnam, &inaml); 1282*61d06d6bSBaptiste Daroussin if (esc == ESCAPE_ERROR || 1283*61d06d6bSBaptiste Daroussin (esc == ESCAPE_SPECIAL && 1284*61d06d6bSBaptiste Daroussin mchars_spec2cp(stnam, inaml) < 0)) 1285*61d06d6bSBaptiste Daroussin mandoc_vmsg(MANDOCERR_ESC_BAD, 1286*61d06d6bSBaptiste Daroussin r->parse, ln, (int)(stesc - buf->buf), 1287*61d06d6bSBaptiste Daroussin "%.*s", (int)(cp - stesc), stesc); 1288*61d06d6bSBaptiste Daroussin stesc--; 1289*61d06d6bSBaptiste Daroussin continue; 1290*61d06d6bSBaptiste Daroussin } 1291*61d06d6bSBaptiste Daroussin 1292*61d06d6bSBaptiste Daroussin if (EXPAND_LIMIT < ++expand_count) { 1293*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, 1294*61d06d6bSBaptiste Daroussin ln, (int)(stesc - buf->buf), NULL); 1295*61d06d6bSBaptiste Daroussin return ROFF_IGN; 1296*61d06d6bSBaptiste Daroussin } 1297*61d06d6bSBaptiste Daroussin 1298*61d06d6bSBaptiste Daroussin /* 1299*61d06d6bSBaptiste Daroussin * The third character decides the length 1300*61d06d6bSBaptiste Daroussin * of the name of the string or register. 1301*61d06d6bSBaptiste Daroussin * Save a pointer to the name. 1302*61d06d6bSBaptiste Daroussin */ 1303*61d06d6bSBaptiste Daroussin 1304*61d06d6bSBaptiste Daroussin if (term == '\0') { 1305*61d06d6bSBaptiste Daroussin switch (*++cp) { 1306*61d06d6bSBaptiste Daroussin case '\0': 1307*61d06d6bSBaptiste Daroussin maxl = 0; 1308*61d06d6bSBaptiste Daroussin break; 1309*61d06d6bSBaptiste Daroussin case '(': 1310*61d06d6bSBaptiste Daroussin cp++; 1311*61d06d6bSBaptiste Daroussin maxl = 2; 1312*61d06d6bSBaptiste Daroussin break; 1313*61d06d6bSBaptiste Daroussin case '[': 1314*61d06d6bSBaptiste Daroussin cp++; 1315*61d06d6bSBaptiste Daroussin term = ']'; 1316*61d06d6bSBaptiste Daroussin maxl = 0; 1317*61d06d6bSBaptiste Daroussin break; 1318*61d06d6bSBaptiste Daroussin default: 1319*61d06d6bSBaptiste Daroussin maxl = 1; 1320*61d06d6bSBaptiste Daroussin break; 1321*61d06d6bSBaptiste Daroussin } 1322*61d06d6bSBaptiste Daroussin } else { 1323*61d06d6bSBaptiste Daroussin cp += 2; 1324*61d06d6bSBaptiste Daroussin maxl = 0; 1325*61d06d6bSBaptiste Daroussin } 1326*61d06d6bSBaptiste Daroussin stnam = cp; 1327*61d06d6bSBaptiste Daroussin 1328*61d06d6bSBaptiste Daroussin /* Advance to the end of the name. */ 1329*61d06d6bSBaptiste Daroussin 1330*61d06d6bSBaptiste Daroussin naml = 0; 1331*61d06d6bSBaptiste Daroussin arg_complete = 1; 1332*61d06d6bSBaptiste Daroussin while (maxl == 0 || naml < maxl) { 1333*61d06d6bSBaptiste Daroussin if (*cp == '\0') { 1334*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_ESC_BAD, r->parse, 1335*61d06d6bSBaptiste Daroussin ln, (int)(stesc - buf->buf), stesc); 1336*61d06d6bSBaptiste Daroussin arg_complete = 0; 1337*61d06d6bSBaptiste Daroussin break; 1338*61d06d6bSBaptiste Daroussin } 1339*61d06d6bSBaptiste Daroussin if (maxl == 0 && *cp == term) { 1340*61d06d6bSBaptiste Daroussin cp++; 1341*61d06d6bSBaptiste Daroussin break; 1342*61d06d6bSBaptiste Daroussin } 1343*61d06d6bSBaptiste Daroussin if (*cp++ != '\\' || stesc[1] != 'w') { 1344*61d06d6bSBaptiste Daroussin naml++; 1345*61d06d6bSBaptiste Daroussin continue; 1346*61d06d6bSBaptiste Daroussin } 1347*61d06d6bSBaptiste Daroussin switch (mandoc_escape(&cp, NULL, NULL)) { 1348*61d06d6bSBaptiste Daroussin case ESCAPE_SPECIAL: 1349*61d06d6bSBaptiste Daroussin case ESCAPE_UNICODE: 1350*61d06d6bSBaptiste Daroussin case ESCAPE_NUMBERED: 1351*61d06d6bSBaptiste Daroussin case ESCAPE_OVERSTRIKE: 1352*61d06d6bSBaptiste Daroussin naml++; 1353*61d06d6bSBaptiste Daroussin break; 1354*61d06d6bSBaptiste Daroussin default: 1355*61d06d6bSBaptiste Daroussin break; 1356*61d06d6bSBaptiste Daroussin } 1357*61d06d6bSBaptiste Daroussin } 1358*61d06d6bSBaptiste Daroussin 1359*61d06d6bSBaptiste Daroussin /* 1360*61d06d6bSBaptiste Daroussin * Retrieve the replacement string; if it is 1361*61d06d6bSBaptiste Daroussin * undefined, resume searching for escapes. 1362*61d06d6bSBaptiste Daroussin */ 1363*61d06d6bSBaptiste Daroussin 1364*61d06d6bSBaptiste Daroussin switch (stesc[1]) { 1365*61d06d6bSBaptiste Daroussin case '*': 1366*61d06d6bSBaptiste Daroussin if (arg_complete) { 1367*61d06d6bSBaptiste Daroussin deftype = ROFFDEF_USER | ROFFDEF_PRE; 1368*61d06d6bSBaptiste Daroussin res = roff_getstrn(r, stnam, naml, &deftype); 1369*61d06d6bSBaptiste Daroussin } 1370*61d06d6bSBaptiste Daroussin break; 1371*61d06d6bSBaptiste Daroussin case 'B': 1372*61d06d6bSBaptiste Daroussin npos = 0; 1373*61d06d6bSBaptiste Daroussin ubuf[0] = arg_complete && 1374*61d06d6bSBaptiste Daroussin roff_evalnum(r, ln, stnam, &npos, 1375*61d06d6bSBaptiste Daroussin NULL, ROFFNUM_SCALE) && 1376*61d06d6bSBaptiste Daroussin stnam + npos + 1 == cp ? '1' : '0'; 1377*61d06d6bSBaptiste Daroussin ubuf[1] = '\0'; 1378*61d06d6bSBaptiste Daroussin break; 1379*61d06d6bSBaptiste Daroussin case 'n': 1380*61d06d6bSBaptiste Daroussin if (arg_complete) 1381*61d06d6bSBaptiste Daroussin (void)snprintf(ubuf, sizeof(ubuf), "%d", 1382*61d06d6bSBaptiste Daroussin roff_getregn(r, stnam, naml, sign)); 1383*61d06d6bSBaptiste Daroussin else 1384*61d06d6bSBaptiste Daroussin ubuf[0] = '\0'; 1385*61d06d6bSBaptiste Daroussin break; 1386*61d06d6bSBaptiste Daroussin case 'w': 1387*61d06d6bSBaptiste Daroussin /* use even incomplete args */ 1388*61d06d6bSBaptiste Daroussin (void)snprintf(ubuf, sizeof(ubuf), "%d", 1389*61d06d6bSBaptiste Daroussin 24 * (int)naml); 1390*61d06d6bSBaptiste Daroussin break; 1391*61d06d6bSBaptiste Daroussin } 1392*61d06d6bSBaptiste Daroussin 1393*61d06d6bSBaptiste Daroussin if (res == NULL) { 1394*61d06d6bSBaptiste Daroussin mandoc_vmsg(MANDOCERR_STR_UNDEF, 1395*61d06d6bSBaptiste Daroussin r->parse, ln, (int)(stesc - buf->buf), 1396*61d06d6bSBaptiste Daroussin "%.*s", (int)naml, stnam); 1397*61d06d6bSBaptiste Daroussin res = ""; 1398*61d06d6bSBaptiste Daroussin } else if (buf->sz + strlen(res) > SHRT_MAX) { 1399*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, 1400*61d06d6bSBaptiste Daroussin ln, (int)(stesc - buf->buf), NULL); 1401*61d06d6bSBaptiste Daroussin return ROFF_IGN; 1402*61d06d6bSBaptiste Daroussin } 1403*61d06d6bSBaptiste Daroussin 1404*61d06d6bSBaptiste Daroussin /* Replace the escape sequence by the string. */ 1405*61d06d6bSBaptiste Daroussin 1406*61d06d6bSBaptiste Daroussin *stesc = '\0'; 1407*61d06d6bSBaptiste Daroussin buf->sz = mandoc_asprintf(&nbuf, "%s%s%s", 1408*61d06d6bSBaptiste Daroussin buf->buf, res, cp) + 1; 1409*61d06d6bSBaptiste Daroussin 1410*61d06d6bSBaptiste Daroussin /* Prepare for the next replacement. */ 1411*61d06d6bSBaptiste Daroussin 1412*61d06d6bSBaptiste Daroussin start = nbuf + pos; 1413*61d06d6bSBaptiste Daroussin stesc = nbuf + (stesc - buf->buf) + strlen(res); 1414*61d06d6bSBaptiste Daroussin free(buf->buf); 1415*61d06d6bSBaptiste Daroussin buf->buf = nbuf; 1416*61d06d6bSBaptiste Daroussin } 1417*61d06d6bSBaptiste Daroussin return ROFF_CONT; 1418*61d06d6bSBaptiste Daroussin } 1419*61d06d6bSBaptiste Daroussin 1420*61d06d6bSBaptiste Daroussin /* 1421*61d06d6bSBaptiste Daroussin * Process text streams. 1422*61d06d6bSBaptiste Daroussin */ 1423*61d06d6bSBaptiste Daroussin static enum rofferr 1424*61d06d6bSBaptiste Daroussin roff_parsetext(struct roff *r, struct buf *buf, int pos, int *offs) 1425*61d06d6bSBaptiste Daroussin { 1426*61d06d6bSBaptiste Daroussin size_t sz; 1427*61d06d6bSBaptiste Daroussin const char *start; 1428*61d06d6bSBaptiste Daroussin char *p; 1429*61d06d6bSBaptiste Daroussin int isz; 1430*61d06d6bSBaptiste Daroussin enum mandoc_esc esc; 1431*61d06d6bSBaptiste Daroussin 1432*61d06d6bSBaptiste Daroussin /* Spring the input line trap. */ 1433*61d06d6bSBaptiste Daroussin 1434*61d06d6bSBaptiste Daroussin if (roffit_lines == 1) { 1435*61d06d6bSBaptiste Daroussin isz = mandoc_asprintf(&p, "%s\n.%s", buf->buf, roffit_macro); 1436*61d06d6bSBaptiste Daroussin free(buf->buf); 1437*61d06d6bSBaptiste Daroussin buf->buf = p; 1438*61d06d6bSBaptiste Daroussin buf->sz = isz + 1; 1439*61d06d6bSBaptiste Daroussin *offs = 0; 1440*61d06d6bSBaptiste Daroussin free(roffit_macro); 1441*61d06d6bSBaptiste Daroussin roffit_lines = 0; 1442*61d06d6bSBaptiste Daroussin return ROFF_REPARSE; 1443*61d06d6bSBaptiste Daroussin } else if (roffit_lines > 1) 1444*61d06d6bSBaptiste Daroussin --roffit_lines; 1445*61d06d6bSBaptiste Daroussin 1446*61d06d6bSBaptiste Daroussin if (roffce_node != NULL && buf->buf[pos] != '\0') { 1447*61d06d6bSBaptiste Daroussin if (roffce_lines < 1) { 1448*61d06d6bSBaptiste Daroussin r->man->last = roffce_node; 1449*61d06d6bSBaptiste Daroussin r->man->next = ROFF_NEXT_SIBLING; 1450*61d06d6bSBaptiste Daroussin roffce_lines = 0; 1451*61d06d6bSBaptiste Daroussin roffce_node = NULL; 1452*61d06d6bSBaptiste Daroussin } else 1453*61d06d6bSBaptiste Daroussin roffce_lines--; 1454*61d06d6bSBaptiste Daroussin } 1455*61d06d6bSBaptiste Daroussin 1456*61d06d6bSBaptiste Daroussin /* Convert all breakable hyphens into ASCII_HYPH. */ 1457*61d06d6bSBaptiste Daroussin 1458*61d06d6bSBaptiste Daroussin start = p = buf->buf + pos; 1459*61d06d6bSBaptiste Daroussin 1460*61d06d6bSBaptiste Daroussin while (*p != '\0') { 1461*61d06d6bSBaptiste Daroussin sz = strcspn(p, "-\\"); 1462*61d06d6bSBaptiste Daroussin p += sz; 1463*61d06d6bSBaptiste Daroussin 1464*61d06d6bSBaptiste Daroussin if (*p == '\0') 1465*61d06d6bSBaptiste Daroussin break; 1466*61d06d6bSBaptiste Daroussin 1467*61d06d6bSBaptiste Daroussin if (*p == '\\') { 1468*61d06d6bSBaptiste Daroussin /* Skip over escapes. */ 1469*61d06d6bSBaptiste Daroussin p++; 1470*61d06d6bSBaptiste Daroussin esc = mandoc_escape((const char **)&p, NULL, NULL); 1471*61d06d6bSBaptiste Daroussin if (esc == ESCAPE_ERROR) 1472*61d06d6bSBaptiste Daroussin break; 1473*61d06d6bSBaptiste Daroussin while (*p == '-') 1474*61d06d6bSBaptiste Daroussin p++; 1475*61d06d6bSBaptiste Daroussin continue; 1476*61d06d6bSBaptiste Daroussin } else if (p == start) { 1477*61d06d6bSBaptiste Daroussin p++; 1478*61d06d6bSBaptiste Daroussin continue; 1479*61d06d6bSBaptiste Daroussin } 1480*61d06d6bSBaptiste Daroussin 1481*61d06d6bSBaptiste Daroussin if (isalpha((unsigned char)p[-1]) && 1482*61d06d6bSBaptiste Daroussin isalpha((unsigned char)p[1])) 1483*61d06d6bSBaptiste Daroussin *p = ASCII_HYPH; 1484*61d06d6bSBaptiste Daroussin p++; 1485*61d06d6bSBaptiste Daroussin } 1486*61d06d6bSBaptiste Daroussin return ROFF_CONT; 1487*61d06d6bSBaptiste Daroussin } 1488*61d06d6bSBaptiste Daroussin 1489*61d06d6bSBaptiste Daroussin enum rofferr 1490*61d06d6bSBaptiste Daroussin roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs) 1491*61d06d6bSBaptiste Daroussin { 1492*61d06d6bSBaptiste Daroussin enum roff_tok t; 1493*61d06d6bSBaptiste Daroussin enum rofferr e; 1494*61d06d6bSBaptiste Daroussin int pos; /* parse point */ 1495*61d06d6bSBaptiste Daroussin int spos; /* saved parse point for messages */ 1496*61d06d6bSBaptiste Daroussin int ppos; /* original offset in buf->buf */ 1497*61d06d6bSBaptiste Daroussin int ctl; /* macro line (boolean) */ 1498*61d06d6bSBaptiste Daroussin 1499*61d06d6bSBaptiste Daroussin ppos = pos = *offs; 1500*61d06d6bSBaptiste Daroussin 1501*61d06d6bSBaptiste Daroussin /* Handle in-line equation delimiters. */ 1502*61d06d6bSBaptiste Daroussin 1503*61d06d6bSBaptiste Daroussin if (r->tbl == NULL && 1504*61d06d6bSBaptiste Daroussin r->last_eqn != NULL && r->last_eqn->delim && 1505*61d06d6bSBaptiste Daroussin (r->eqn == NULL || r->eqn_inline)) { 1506*61d06d6bSBaptiste Daroussin e = roff_eqndelim(r, buf, pos); 1507*61d06d6bSBaptiste Daroussin if (e == ROFF_REPARSE) 1508*61d06d6bSBaptiste Daroussin return e; 1509*61d06d6bSBaptiste Daroussin assert(e == ROFF_CONT); 1510*61d06d6bSBaptiste Daroussin } 1511*61d06d6bSBaptiste Daroussin 1512*61d06d6bSBaptiste Daroussin /* Expand some escape sequences. */ 1513*61d06d6bSBaptiste Daroussin 1514*61d06d6bSBaptiste Daroussin e = roff_res(r, buf, ln, pos); 1515*61d06d6bSBaptiste Daroussin if (e == ROFF_IGN || e == ROFF_APPEND) 1516*61d06d6bSBaptiste Daroussin return e; 1517*61d06d6bSBaptiste Daroussin assert(e == ROFF_CONT); 1518*61d06d6bSBaptiste Daroussin 1519*61d06d6bSBaptiste Daroussin ctl = roff_getcontrol(r, buf->buf, &pos); 1520*61d06d6bSBaptiste Daroussin 1521*61d06d6bSBaptiste Daroussin /* 1522*61d06d6bSBaptiste Daroussin * First, if a scope is open and we're not a macro, pass the 1523*61d06d6bSBaptiste Daroussin * text through the macro's filter. 1524*61d06d6bSBaptiste Daroussin * Equations process all content themselves. 1525*61d06d6bSBaptiste Daroussin * Tables process almost all content themselves, but we want 1526*61d06d6bSBaptiste Daroussin * to warn about macros before passing it there. 1527*61d06d6bSBaptiste Daroussin */ 1528*61d06d6bSBaptiste Daroussin 1529*61d06d6bSBaptiste Daroussin if (r->last != NULL && ! ctl) { 1530*61d06d6bSBaptiste Daroussin t = r->last->tok; 1531*61d06d6bSBaptiste Daroussin e = (*roffs[t].text)(r, t, buf, ln, pos, pos, offs); 1532*61d06d6bSBaptiste Daroussin if (e == ROFF_IGN) 1533*61d06d6bSBaptiste Daroussin return e; 1534*61d06d6bSBaptiste Daroussin assert(e == ROFF_CONT); 1535*61d06d6bSBaptiste Daroussin } 1536*61d06d6bSBaptiste Daroussin if (r->eqn != NULL && strncmp(buf->buf + ppos, ".EN", 3)) { 1537*61d06d6bSBaptiste Daroussin eqn_read(r->eqn, buf->buf + ppos); 1538*61d06d6bSBaptiste Daroussin return ROFF_IGN; 1539*61d06d6bSBaptiste Daroussin } 1540*61d06d6bSBaptiste Daroussin if (r->tbl != NULL && (ctl == 0 || buf->buf[pos] == '\0')) { 1541*61d06d6bSBaptiste Daroussin tbl_read(r->tbl, ln, buf->buf, ppos); 1542*61d06d6bSBaptiste Daroussin roff_addtbl(r->man, r->tbl); 1543*61d06d6bSBaptiste Daroussin return ROFF_IGN; 1544*61d06d6bSBaptiste Daroussin } 1545*61d06d6bSBaptiste Daroussin if ( ! ctl) 1546*61d06d6bSBaptiste Daroussin return roff_parsetext(r, buf, pos, offs); 1547*61d06d6bSBaptiste Daroussin 1548*61d06d6bSBaptiste Daroussin /* Skip empty request lines. */ 1549*61d06d6bSBaptiste Daroussin 1550*61d06d6bSBaptiste Daroussin if (buf->buf[pos] == '"') { 1551*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_COMMENT_BAD, r->parse, 1552*61d06d6bSBaptiste Daroussin ln, pos, NULL); 1553*61d06d6bSBaptiste Daroussin return ROFF_IGN; 1554*61d06d6bSBaptiste Daroussin } else if (buf->buf[pos] == '\0') 1555*61d06d6bSBaptiste Daroussin return ROFF_IGN; 1556*61d06d6bSBaptiste Daroussin 1557*61d06d6bSBaptiste Daroussin /* 1558*61d06d6bSBaptiste Daroussin * If a scope is open, go to the child handler for that macro, 1559*61d06d6bSBaptiste Daroussin * as it may want to preprocess before doing anything with it. 1560*61d06d6bSBaptiste Daroussin * Don't do so if an equation is open. 1561*61d06d6bSBaptiste Daroussin */ 1562*61d06d6bSBaptiste Daroussin 1563*61d06d6bSBaptiste Daroussin if (r->last) { 1564*61d06d6bSBaptiste Daroussin t = r->last->tok; 1565*61d06d6bSBaptiste Daroussin return (*roffs[t].sub)(r, t, buf, ln, ppos, pos, offs); 1566*61d06d6bSBaptiste Daroussin } 1567*61d06d6bSBaptiste Daroussin 1568*61d06d6bSBaptiste Daroussin /* No scope is open. This is a new request or macro. */ 1569*61d06d6bSBaptiste Daroussin 1570*61d06d6bSBaptiste Daroussin spos = pos; 1571*61d06d6bSBaptiste Daroussin t = roff_parse(r, buf->buf, &pos, ln, ppos); 1572*61d06d6bSBaptiste Daroussin 1573*61d06d6bSBaptiste Daroussin /* Tables ignore most macros. */ 1574*61d06d6bSBaptiste Daroussin 1575*61d06d6bSBaptiste Daroussin if (r->tbl != NULL && (t == TOKEN_NONE || t == ROFF_TS || 1576*61d06d6bSBaptiste Daroussin t == ROFF_br || t == ROFF_ce || t == ROFF_rj || t == ROFF_sp)) { 1577*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_TBLMACRO, r->parse, 1578*61d06d6bSBaptiste Daroussin ln, pos, buf->buf + spos); 1579*61d06d6bSBaptiste Daroussin if (t != TOKEN_NONE) 1580*61d06d6bSBaptiste Daroussin return ROFF_IGN; 1581*61d06d6bSBaptiste Daroussin while (buf->buf[pos] != '\0' && buf->buf[pos] != ' ') 1582*61d06d6bSBaptiste Daroussin pos++; 1583*61d06d6bSBaptiste Daroussin while (buf->buf[pos] == ' ') 1584*61d06d6bSBaptiste Daroussin pos++; 1585*61d06d6bSBaptiste Daroussin tbl_read(r->tbl, ln, buf->buf, pos); 1586*61d06d6bSBaptiste Daroussin roff_addtbl(r->man, r->tbl); 1587*61d06d6bSBaptiste Daroussin return ROFF_IGN; 1588*61d06d6bSBaptiste Daroussin } 1589*61d06d6bSBaptiste Daroussin 1590*61d06d6bSBaptiste Daroussin /* For now, let high level macros abort .ce mode. */ 1591*61d06d6bSBaptiste Daroussin 1592*61d06d6bSBaptiste Daroussin if (ctl && roffce_node != NULL && 1593*61d06d6bSBaptiste Daroussin (t == TOKEN_NONE || t == ROFF_Dd || t == ROFF_EQ || 1594*61d06d6bSBaptiste Daroussin t == ROFF_TH || t == ROFF_TS)) { 1595*61d06d6bSBaptiste Daroussin r->man->last = roffce_node; 1596*61d06d6bSBaptiste Daroussin r->man->next = ROFF_NEXT_SIBLING; 1597*61d06d6bSBaptiste Daroussin roffce_lines = 0; 1598*61d06d6bSBaptiste Daroussin roffce_node = NULL; 1599*61d06d6bSBaptiste Daroussin } 1600*61d06d6bSBaptiste Daroussin 1601*61d06d6bSBaptiste Daroussin /* 1602*61d06d6bSBaptiste Daroussin * This is neither a roff request nor a user-defined macro. 1603*61d06d6bSBaptiste Daroussin * Let the standard macro set parsers handle it. 1604*61d06d6bSBaptiste Daroussin */ 1605*61d06d6bSBaptiste Daroussin 1606*61d06d6bSBaptiste Daroussin if (t == TOKEN_NONE) 1607*61d06d6bSBaptiste Daroussin return ROFF_CONT; 1608*61d06d6bSBaptiste Daroussin 1609*61d06d6bSBaptiste Daroussin /* Execute a roff request or a user defined macro. */ 1610*61d06d6bSBaptiste Daroussin 1611*61d06d6bSBaptiste Daroussin return (*roffs[t].proc)(r, t, buf, ln, spos, pos, offs); 1612*61d06d6bSBaptiste Daroussin } 1613*61d06d6bSBaptiste Daroussin 1614*61d06d6bSBaptiste Daroussin void 1615*61d06d6bSBaptiste Daroussin roff_endparse(struct roff *r) 1616*61d06d6bSBaptiste Daroussin { 1617*61d06d6bSBaptiste Daroussin if (r->last != NULL) 1618*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_NOEND, r->parse, 1619*61d06d6bSBaptiste Daroussin r->last->line, r->last->col, 1620*61d06d6bSBaptiste Daroussin roff_name[r->last->tok]); 1621*61d06d6bSBaptiste Daroussin 1622*61d06d6bSBaptiste Daroussin if (r->eqn != NULL) { 1623*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_NOEND, r->parse, 1624*61d06d6bSBaptiste Daroussin r->eqn->node->line, r->eqn->node->pos, "EQ"); 1625*61d06d6bSBaptiste Daroussin eqn_parse(r->eqn); 1626*61d06d6bSBaptiste Daroussin r->eqn = NULL; 1627*61d06d6bSBaptiste Daroussin } 1628*61d06d6bSBaptiste Daroussin 1629*61d06d6bSBaptiste Daroussin if (r->tbl != NULL) { 1630*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_NOEND, r->parse, 1631*61d06d6bSBaptiste Daroussin r->tbl->line, r->tbl->pos, "TS"); 1632*61d06d6bSBaptiste Daroussin tbl_end(r->tbl); 1633*61d06d6bSBaptiste Daroussin r->tbl = NULL; 1634*61d06d6bSBaptiste Daroussin } 1635*61d06d6bSBaptiste Daroussin } 1636*61d06d6bSBaptiste Daroussin 1637*61d06d6bSBaptiste Daroussin /* 1638*61d06d6bSBaptiste Daroussin * Parse a roff node's type from the input buffer. This must be in the 1639*61d06d6bSBaptiste Daroussin * form of ".foo xxx" in the usual way. 1640*61d06d6bSBaptiste Daroussin */ 1641*61d06d6bSBaptiste Daroussin static enum roff_tok 1642*61d06d6bSBaptiste Daroussin roff_parse(struct roff *r, char *buf, int *pos, int ln, int ppos) 1643*61d06d6bSBaptiste Daroussin { 1644*61d06d6bSBaptiste Daroussin char *cp; 1645*61d06d6bSBaptiste Daroussin const char *mac; 1646*61d06d6bSBaptiste Daroussin size_t maclen; 1647*61d06d6bSBaptiste Daroussin int deftype; 1648*61d06d6bSBaptiste Daroussin enum roff_tok t; 1649*61d06d6bSBaptiste Daroussin 1650*61d06d6bSBaptiste Daroussin cp = buf + *pos; 1651*61d06d6bSBaptiste Daroussin 1652*61d06d6bSBaptiste Daroussin if ('\0' == *cp || '"' == *cp || '\t' == *cp || ' ' == *cp) 1653*61d06d6bSBaptiste Daroussin return TOKEN_NONE; 1654*61d06d6bSBaptiste Daroussin 1655*61d06d6bSBaptiste Daroussin mac = cp; 1656*61d06d6bSBaptiste Daroussin maclen = roff_getname(r, &cp, ln, ppos); 1657*61d06d6bSBaptiste Daroussin 1658*61d06d6bSBaptiste Daroussin deftype = ROFFDEF_USER | ROFFDEF_REN; 1659*61d06d6bSBaptiste Daroussin r->current_string = roff_getstrn(r, mac, maclen, &deftype); 1660*61d06d6bSBaptiste Daroussin switch (deftype) { 1661*61d06d6bSBaptiste Daroussin case ROFFDEF_USER: 1662*61d06d6bSBaptiste Daroussin t = ROFF_USERDEF; 1663*61d06d6bSBaptiste Daroussin break; 1664*61d06d6bSBaptiste Daroussin case ROFFDEF_REN: 1665*61d06d6bSBaptiste Daroussin t = ROFF_RENAMED; 1666*61d06d6bSBaptiste Daroussin break; 1667*61d06d6bSBaptiste Daroussin default: 1668*61d06d6bSBaptiste Daroussin t = roffhash_find(r->reqtab, mac, maclen); 1669*61d06d6bSBaptiste Daroussin break; 1670*61d06d6bSBaptiste Daroussin } 1671*61d06d6bSBaptiste Daroussin if (t != TOKEN_NONE) 1672*61d06d6bSBaptiste Daroussin *pos = cp - buf; 1673*61d06d6bSBaptiste Daroussin else if (deftype == ROFFDEF_UNDEF) { 1674*61d06d6bSBaptiste Daroussin /* Using an undefined macro defines it to be empty. */ 1675*61d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, mac, maclen, "", 0, 0); 1676*61d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, mac, maclen, NULL, 0, 0); 1677*61d06d6bSBaptiste Daroussin } 1678*61d06d6bSBaptiste Daroussin return t; 1679*61d06d6bSBaptiste Daroussin } 1680*61d06d6bSBaptiste Daroussin 1681*61d06d6bSBaptiste Daroussin /* --- handling of request blocks ----------------------------------------- */ 1682*61d06d6bSBaptiste Daroussin 1683*61d06d6bSBaptiste Daroussin static enum rofferr 1684*61d06d6bSBaptiste Daroussin roff_cblock(ROFF_ARGS) 1685*61d06d6bSBaptiste Daroussin { 1686*61d06d6bSBaptiste Daroussin 1687*61d06d6bSBaptiste Daroussin /* 1688*61d06d6bSBaptiste Daroussin * A block-close `..' should only be invoked as a child of an 1689*61d06d6bSBaptiste Daroussin * ignore macro, otherwise raise a warning and just ignore it. 1690*61d06d6bSBaptiste Daroussin */ 1691*61d06d6bSBaptiste Daroussin 1692*61d06d6bSBaptiste Daroussin if (r->last == NULL) { 1693*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, 1694*61d06d6bSBaptiste Daroussin ln, ppos, ".."); 1695*61d06d6bSBaptiste Daroussin return ROFF_IGN; 1696*61d06d6bSBaptiste Daroussin } 1697*61d06d6bSBaptiste Daroussin 1698*61d06d6bSBaptiste Daroussin switch (r->last->tok) { 1699*61d06d6bSBaptiste Daroussin case ROFF_am: 1700*61d06d6bSBaptiste Daroussin /* ROFF_am1 is remapped to ROFF_am in roff_block(). */ 1701*61d06d6bSBaptiste Daroussin case ROFF_ami: 1702*61d06d6bSBaptiste Daroussin case ROFF_de: 1703*61d06d6bSBaptiste Daroussin /* ROFF_de1 is remapped to ROFF_de in roff_block(). */ 1704*61d06d6bSBaptiste Daroussin case ROFF_dei: 1705*61d06d6bSBaptiste Daroussin case ROFF_ig: 1706*61d06d6bSBaptiste Daroussin break; 1707*61d06d6bSBaptiste Daroussin default: 1708*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, 1709*61d06d6bSBaptiste Daroussin ln, ppos, ".."); 1710*61d06d6bSBaptiste Daroussin return ROFF_IGN; 1711*61d06d6bSBaptiste Daroussin } 1712*61d06d6bSBaptiste Daroussin 1713*61d06d6bSBaptiste Daroussin if (buf->buf[pos] != '\0') 1714*61d06d6bSBaptiste Daroussin mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos, 1715*61d06d6bSBaptiste Daroussin ".. %s", buf->buf + pos); 1716*61d06d6bSBaptiste Daroussin 1717*61d06d6bSBaptiste Daroussin roffnode_pop(r); 1718*61d06d6bSBaptiste Daroussin roffnode_cleanscope(r); 1719*61d06d6bSBaptiste Daroussin return ROFF_IGN; 1720*61d06d6bSBaptiste Daroussin 1721*61d06d6bSBaptiste Daroussin } 1722*61d06d6bSBaptiste Daroussin 1723*61d06d6bSBaptiste Daroussin static void 1724*61d06d6bSBaptiste Daroussin roffnode_cleanscope(struct roff *r) 1725*61d06d6bSBaptiste Daroussin { 1726*61d06d6bSBaptiste Daroussin 1727*61d06d6bSBaptiste Daroussin while (r->last) { 1728*61d06d6bSBaptiste Daroussin if (--r->last->endspan != 0) 1729*61d06d6bSBaptiste Daroussin break; 1730*61d06d6bSBaptiste Daroussin roffnode_pop(r); 1731*61d06d6bSBaptiste Daroussin } 1732*61d06d6bSBaptiste Daroussin } 1733*61d06d6bSBaptiste Daroussin 1734*61d06d6bSBaptiste Daroussin static void 1735*61d06d6bSBaptiste Daroussin roff_ccond(struct roff *r, int ln, int ppos) 1736*61d06d6bSBaptiste Daroussin { 1737*61d06d6bSBaptiste Daroussin 1738*61d06d6bSBaptiste Daroussin if (NULL == r->last) { 1739*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, 1740*61d06d6bSBaptiste Daroussin ln, ppos, "\\}"); 1741*61d06d6bSBaptiste Daroussin return; 1742*61d06d6bSBaptiste Daroussin } 1743*61d06d6bSBaptiste Daroussin 1744*61d06d6bSBaptiste Daroussin switch (r->last->tok) { 1745*61d06d6bSBaptiste Daroussin case ROFF_el: 1746*61d06d6bSBaptiste Daroussin case ROFF_ie: 1747*61d06d6bSBaptiste Daroussin case ROFF_if: 1748*61d06d6bSBaptiste Daroussin break; 1749*61d06d6bSBaptiste Daroussin default: 1750*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, 1751*61d06d6bSBaptiste Daroussin ln, ppos, "\\}"); 1752*61d06d6bSBaptiste Daroussin return; 1753*61d06d6bSBaptiste Daroussin } 1754*61d06d6bSBaptiste Daroussin 1755*61d06d6bSBaptiste Daroussin if (r->last->endspan > -1) { 1756*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, 1757*61d06d6bSBaptiste Daroussin ln, ppos, "\\}"); 1758*61d06d6bSBaptiste Daroussin return; 1759*61d06d6bSBaptiste Daroussin } 1760*61d06d6bSBaptiste Daroussin 1761*61d06d6bSBaptiste Daroussin roffnode_pop(r); 1762*61d06d6bSBaptiste Daroussin roffnode_cleanscope(r); 1763*61d06d6bSBaptiste Daroussin return; 1764*61d06d6bSBaptiste Daroussin } 1765*61d06d6bSBaptiste Daroussin 1766*61d06d6bSBaptiste Daroussin static enum rofferr 1767*61d06d6bSBaptiste Daroussin roff_block(ROFF_ARGS) 1768*61d06d6bSBaptiste Daroussin { 1769*61d06d6bSBaptiste Daroussin const char *name, *value; 1770*61d06d6bSBaptiste Daroussin char *call, *cp, *iname, *rname; 1771*61d06d6bSBaptiste Daroussin size_t csz, namesz, rsz; 1772*61d06d6bSBaptiste Daroussin int deftype; 1773*61d06d6bSBaptiste Daroussin 1774*61d06d6bSBaptiste Daroussin /* Ignore groff compatibility mode for now. */ 1775*61d06d6bSBaptiste Daroussin 1776*61d06d6bSBaptiste Daroussin if (tok == ROFF_de1) 1777*61d06d6bSBaptiste Daroussin tok = ROFF_de; 1778*61d06d6bSBaptiste Daroussin else if (tok == ROFF_dei1) 1779*61d06d6bSBaptiste Daroussin tok = ROFF_dei; 1780*61d06d6bSBaptiste Daroussin else if (tok == ROFF_am1) 1781*61d06d6bSBaptiste Daroussin tok = ROFF_am; 1782*61d06d6bSBaptiste Daroussin else if (tok == ROFF_ami1) 1783*61d06d6bSBaptiste Daroussin tok = ROFF_ami; 1784*61d06d6bSBaptiste Daroussin 1785*61d06d6bSBaptiste Daroussin /* Parse the macro name argument. */ 1786*61d06d6bSBaptiste Daroussin 1787*61d06d6bSBaptiste Daroussin cp = buf->buf + pos; 1788*61d06d6bSBaptiste Daroussin if (tok == ROFF_ig) { 1789*61d06d6bSBaptiste Daroussin iname = NULL; 1790*61d06d6bSBaptiste Daroussin namesz = 0; 1791*61d06d6bSBaptiste Daroussin } else { 1792*61d06d6bSBaptiste Daroussin iname = cp; 1793*61d06d6bSBaptiste Daroussin namesz = roff_getname(r, &cp, ln, ppos); 1794*61d06d6bSBaptiste Daroussin iname[namesz] = '\0'; 1795*61d06d6bSBaptiste Daroussin } 1796*61d06d6bSBaptiste Daroussin 1797*61d06d6bSBaptiste Daroussin /* Resolve the macro name argument if it is indirect. */ 1798*61d06d6bSBaptiste Daroussin 1799*61d06d6bSBaptiste Daroussin if (namesz && (tok == ROFF_dei || tok == ROFF_ami)) { 1800*61d06d6bSBaptiste Daroussin deftype = ROFFDEF_USER; 1801*61d06d6bSBaptiste Daroussin name = roff_getstrn(r, iname, namesz, &deftype); 1802*61d06d6bSBaptiste Daroussin if (name == NULL) { 1803*61d06d6bSBaptiste Daroussin mandoc_vmsg(MANDOCERR_STR_UNDEF, 1804*61d06d6bSBaptiste Daroussin r->parse, ln, (int)(iname - buf->buf), 1805*61d06d6bSBaptiste Daroussin "%.*s", (int)namesz, iname); 1806*61d06d6bSBaptiste Daroussin namesz = 0; 1807*61d06d6bSBaptiste Daroussin } else 1808*61d06d6bSBaptiste Daroussin namesz = strlen(name); 1809*61d06d6bSBaptiste Daroussin } else 1810*61d06d6bSBaptiste Daroussin name = iname; 1811*61d06d6bSBaptiste Daroussin 1812*61d06d6bSBaptiste Daroussin if (namesz == 0 && tok != ROFF_ig) { 1813*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_REQ_EMPTY, r->parse, 1814*61d06d6bSBaptiste Daroussin ln, ppos, roff_name[tok]); 1815*61d06d6bSBaptiste Daroussin return ROFF_IGN; 1816*61d06d6bSBaptiste Daroussin } 1817*61d06d6bSBaptiste Daroussin 1818*61d06d6bSBaptiste Daroussin roffnode_push(r, tok, name, ln, ppos); 1819*61d06d6bSBaptiste Daroussin 1820*61d06d6bSBaptiste Daroussin /* 1821*61d06d6bSBaptiste Daroussin * At the beginning of a `de' macro, clear the existing string 1822*61d06d6bSBaptiste Daroussin * with the same name, if there is one. New content will be 1823*61d06d6bSBaptiste Daroussin * appended from roff_block_text() in multiline mode. 1824*61d06d6bSBaptiste Daroussin */ 1825*61d06d6bSBaptiste Daroussin 1826*61d06d6bSBaptiste Daroussin if (tok == ROFF_de || tok == ROFF_dei) { 1827*61d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, name, namesz, "", 0, 0); 1828*61d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0); 1829*61d06d6bSBaptiste Daroussin } else if (tok == ROFF_am || tok == ROFF_ami) { 1830*61d06d6bSBaptiste Daroussin deftype = ROFFDEF_ANY; 1831*61d06d6bSBaptiste Daroussin value = roff_getstrn(r, iname, namesz, &deftype); 1832*61d06d6bSBaptiste Daroussin switch (deftype) { /* Before appending, ... */ 1833*61d06d6bSBaptiste Daroussin case ROFFDEF_PRE: /* copy predefined to user-defined. */ 1834*61d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, name, namesz, 1835*61d06d6bSBaptiste Daroussin value, strlen(value), 0); 1836*61d06d6bSBaptiste Daroussin break; 1837*61d06d6bSBaptiste Daroussin case ROFFDEF_REN: /* call original standard macro. */ 1838*61d06d6bSBaptiste Daroussin csz = mandoc_asprintf(&call, ".%.*s \\$* \\\"\n", 1839*61d06d6bSBaptiste Daroussin (int)strlen(value), value); 1840*61d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, name, namesz, call, csz, 0); 1841*61d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0); 1842*61d06d6bSBaptiste Daroussin free(call); 1843*61d06d6bSBaptiste Daroussin break; 1844*61d06d6bSBaptiste Daroussin case ROFFDEF_STD: /* rename and call standard macro. */ 1845*61d06d6bSBaptiste Daroussin rsz = mandoc_asprintf(&rname, "__%s_renamed", name); 1846*61d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, rname, rsz, name, namesz, 0); 1847*61d06d6bSBaptiste Daroussin csz = mandoc_asprintf(&call, ".%.*s \\$* \\\"\n", 1848*61d06d6bSBaptiste Daroussin (int)rsz, rname); 1849*61d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, name, namesz, call, csz, 0); 1850*61d06d6bSBaptiste Daroussin free(call); 1851*61d06d6bSBaptiste Daroussin free(rname); 1852*61d06d6bSBaptiste Daroussin break; 1853*61d06d6bSBaptiste Daroussin default: 1854*61d06d6bSBaptiste Daroussin break; 1855*61d06d6bSBaptiste Daroussin } 1856*61d06d6bSBaptiste Daroussin } 1857*61d06d6bSBaptiste Daroussin 1858*61d06d6bSBaptiste Daroussin if (*cp == '\0') 1859*61d06d6bSBaptiste Daroussin return ROFF_IGN; 1860*61d06d6bSBaptiste Daroussin 1861*61d06d6bSBaptiste Daroussin /* Get the custom end marker. */ 1862*61d06d6bSBaptiste Daroussin 1863*61d06d6bSBaptiste Daroussin iname = cp; 1864*61d06d6bSBaptiste Daroussin namesz = roff_getname(r, &cp, ln, ppos); 1865*61d06d6bSBaptiste Daroussin 1866*61d06d6bSBaptiste Daroussin /* Resolve the end marker if it is indirect. */ 1867*61d06d6bSBaptiste Daroussin 1868*61d06d6bSBaptiste Daroussin if (namesz && (tok == ROFF_dei || tok == ROFF_ami)) { 1869*61d06d6bSBaptiste Daroussin deftype = ROFFDEF_USER; 1870*61d06d6bSBaptiste Daroussin name = roff_getstrn(r, iname, namesz, &deftype); 1871*61d06d6bSBaptiste Daroussin if (name == NULL) { 1872*61d06d6bSBaptiste Daroussin mandoc_vmsg(MANDOCERR_STR_UNDEF, 1873*61d06d6bSBaptiste Daroussin r->parse, ln, (int)(iname - buf->buf), 1874*61d06d6bSBaptiste Daroussin "%.*s", (int)namesz, iname); 1875*61d06d6bSBaptiste Daroussin namesz = 0; 1876*61d06d6bSBaptiste Daroussin } else 1877*61d06d6bSBaptiste Daroussin namesz = strlen(name); 1878*61d06d6bSBaptiste Daroussin } else 1879*61d06d6bSBaptiste Daroussin name = iname; 1880*61d06d6bSBaptiste Daroussin 1881*61d06d6bSBaptiste Daroussin if (namesz) 1882*61d06d6bSBaptiste Daroussin r->last->end = mandoc_strndup(name, namesz); 1883*61d06d6bSBaptiste Daroussin 1884*61d06d6bSBaptiste Daroussin if (*cp != '\0') 1885*61d06d6bSBaptiste Daroussin mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse, 1886*61d06d6bSBaptiste Daroussin ln, pos, ".%s ... %s", roff_name[tok], cp); 1887*61d06d6bSBaptiste Daroussin 1888*61d06d6bSBaptiste Daroussin return ROFF_IGN; 1889*61d06d6bSBaptiste Daroussin } 1890*61d06d6bSBaptiste Daroussin 1891*61d06d6bSBaptiste Daroussin static enum rofferr 1892*61d06d6bSBaptiste Daroussin roff_block_sub(ROFF_ARGS) 1893*61d06d6bSBaptiste Daroussin { 1894*61d06d6bSBaptiste Daroussin enum roff_tok t; 1895*61d06d6bSBaptiste Daroussin int i, j; 1896*61d06d6bSBaptiste Daroussin 1897*61d06d6bSBaptiste Daroussin /* 1898*61d06d6bSBaptiste Daroussin * First check whether a custom macro exists at this level. If 1899*61d06d6bSBaptiste Daroussin * it does, then check against it. This is some of groff's 1900*61d06d6bSBaptiste Daroussin * stranger behaviours. If we encountered a custom end-scope 1901*61d06d6bSBaptiste Daroussin * tag and that tag also happens to be a "real" macro, then we 1902*61d06d6bSBaptiste Daroussin * need to try interpreting it again as a real macro. If it's 1903*61d06d6bSBaptiste Daroussin * not, then return ignore. Else continue. 1904*61d06d6bSBaptiste Daroussin */ 1905*61d06d6bSBaptiste Daroussin 1906*61d06d6bSBaptiste Daroussin if (r->last->end) { 1907*61d06d6bSBaptiste Daroussin for (i = pos, j = 0; r->last->end[j]; j++, i++) 1908*61d06d6bSBaptiste Daroussin if (buf->buf[i] != r->last->end[j]) 1909*61d06d6bSBaptiste Daroussin break; 1910*61d06d6bSBaptiste Daroussin 1911*61d06d6bSBaptiste Daroussin if (r->last->end[j] == '\0' && 1912*61d06d6bSBaptiste Daroussin (buf->buf[i] == '\0' || 1913*61d06d6bSBaptiste Daroussin buf->buf[i] == ' ' || 1914*61d06d6bSBaptiste Daroussin buf->buf[i] == '\t')) { 1915*61d06d6bSBaptiste Daroussin roffnode_pop(r); 1916*61d06d6bSBaptiste Daroussin roffnode_cleanscope(r); 1917*61d06d6bSBaptiste Daroussin 1918*61d06d6bSBaptiste Daroussin while (buf->buf[i] == ' ' || buf->buf[i] == '\t') 1919*61d06d6bSBaptiste Daroussin i++; 1920*61d06d6bSBaptiste Daroussin 1921*61d06d6bSBaptiste Daroussin pos = i; 1922*61d06d6bSBaptiste Daroussin if (roff_parse(r, buf->buf, &pos, ln, ppos) != 1923*61d06d6bSBaptiste Daroussin TOKEN_NONE) 1924*61d06d6bSBaptiste Daroussin return ROFF_RERUN; 1925*61d06d6bSBaptiste Daroussin return ROFF_IGN; 1926*61d06d6bSBaptiste Daroussin } 1927*61d06d6bSBaptiste Daroussin } 1928*61d06d6bSBaptiste Daroussin 1929*61d06d6bSBaptiste Daroussin /* 1930*61d06d6bSBaptiste Daroussin * If we have no custom end-query or lookup failed, then try 1931*61d06d6bSBaptiste Daroussin * pulling it out of the hashtable. 1932*61d06d6bSBaptiste Daroussin */ 1933*61d06d6bSBaptiste Daroussin 1934*61d06d6bSBaptiste Daroussin t = roff_parse(r, buf->buf, &pos, ln, ppos); 1935*61d06d6bSBaptiste Daroussin 1936*61d06d6bSBaptiste Daroussin if (t != ROFF_cblock) { 1937*61d06d6bSBaptiste Daroussin if (tok != ROFF_ig) 1938*61d06d6bSBaptiste Daroussin roff_setstr(r, r->last->name, buf->buf + ppos, 2); 1939*61d06d6bSBaptiste Daroussin return ROFF_IGN; 1940*61d06d6bSBaptiste Daroussin } 1941*61d06d6bSBaptiste Daroussin 1942*61d06d6bSBaptiste Daroussin return (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs); 1943*61d06d6bSBaptiste Daroussin } 1944*61d06d6bSBaptiste Daroussin 1945*61d06d6bSBaptiste Daroussin static enum rofferr 1946*61d06d6bSBaptiste Daroussin roff_block_text(ROFF_ARGS) 1947*61d06d6bSBaptiste Daroussin { 1948*61d06d6bSBaptiste Daroussin 1949*61d06d6bSBaptiste Daroussin if (tok != ROFF_ig) 1950*61d06d6bSBaptiste Daroussin roff_setstr(r, r->last->name, buf->buf + pos, 2); 1951*61d06d6bSBaptiste Daroussin 1952*61d06d6bSBaptiste Daroussin return ROFF_IGN; 1953*61d06d6bSBaptiste Daroussin } 1954*61d06d6bSBaptiste Daroussin 1955*61d06d6bSBaptiste Daroussin static enum rofferr 1956*61d06d6bSBaptiste Daroussin roff_cond_sub(ROFF_ARGS) 1957*61d06d6bSBaptiste Daroussin { 1958*61d06d6bSBaptiste Daroussin enum roff_tok t; 1959*61d06d6bSBaptiste Daroussin char *ep; 1960*61d06d6bSBaptiste Daroussin int rr; 1961*61d06d6bSBaptiste Daroussin 1962*61d06d6bSBaptiste Daroussin rr = r->last->rule; 1963*61d06d6bSBaptiste Daroussin roffnode_cleanscope(r); 1964*61d06d6bSBaptiste Daroussin 1965*61d06d6bSBaptiste Daroussin /* 1966*61d06d6bSBaptiste Daroussin * If `\}' occurs on a macro line without a preceding macro, 1967*61d06d6bSBaptiste Daroussin * drop the line completely. 1968*61d06d6bSBaptiste Daroussin */ 1969*61d06d6bSBaptiste Daroussin 1970*61d06d6bSBaptiste Daroussin ep = buf->buf + pos; 1971*61d06d6bSBaptiste Daroussin if (ep[0] == '\\' && ep[1] == '}') 1972*61d06d6bSBaptiste Daroussin rr = 0; 1973*61d06d6bSBaptiste Daroussin 1974*61d06d6bSBaptiste Daroussin /* Always check for the closing delimiter `\}'. */ 1975*61d06d6bSBaptiste Daroussin 1976*61d06d6bSBaptiste Daroussin while ((ep = strchr(ep, '\\')) != NULL) { 1977*61d06d6bSBaptiste Daroussin switch (ep[1]) { 1978*61d06d6bSBaptiste Daroussin case '}': 1979*61d06d6bSBaptiste Daroussin memmove(ep, ep + 2, strlen(ep + 2) + 1); 1980*61d06d6bSBaptiste Daroussin roff_ccond(r, ln, ep - buf->buf); 1981*61d06d6bSBaptiste Daroussin break; 1982*61d06d6bSBaptiste Daroussin case '\0': 1983*61d06d6bSBaptiste Daroussin ++ep; 1984*61d06d6bSBaptiste Daroussin break; 1985*61d06d6bSBaptiste Daroussin default: 1986*61d06d6bSBaptiste Daroussin ep += 2; 1987*61d06d6bSBaptiste Daroussin break; 1988*61d06d6bSBaptiste Daroussin } 1989*61d06d6bSBaptiste Daroussin } 1990*61d06d6bSBaptiste Daroussin 1991*61d06d6bSBaptiste Daroussin /* 1992*61d06d6bSBaptiste Daroussin * Fully handle known macros when they are structurally 1993*61d06d6bSBaptiste Daroussin * required or when the conditional evaluated to true. 1994*61d06d6bSBaptiste Daroussin */ 1995*61d06d6bSBaptiste Daroussin 1996*61d06d6bSBaptiste Daroussin t = roff_parse(r, buf->buf, &pos, ln, ppos); 1997*61d06d6bSBaptiste Daroussin return t != TOKEN_NONE && (rr || roffs[t].flags & ROFFMAC_STRUCT) 1998*61d06d6bSBaptiste Daroussin ? (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs) : rr 1999*61d06d6bSBaptiste Daroussin ? ROFF_CONT : ROFF_IGN; 2000*61d06d6bSBaptiste Daroussin } 2001*61d06d6bSBaptiste Daroussin 2002*61d06d6bSBaptiste Daroussin static enum rofferr 2003*61d06d6bSBaptiste Daroussin roff_cond_text(ROFF_ARGS) 2004*61d06d6bSBaptiste Daroussin { 2005*61d06d6bSBaptiste Daroussin char *ep; 2006*61d06d6bSBaptiste Daroussin int rr; 2007*61d06d6bSBaptiste Daroussin 2008*61d06d6bSBaptiste Daroussin rr = r->last->rule; 2009*61d06d6bSBaptiste Daroussin roffnode_cleanscope(r); 2010*61d06d6bSBaptiste Daroussin 2011*61d06d6bSBaptiste Daroussin ep = buf->buf + pos; 2012*61d06d6bSBaptiste Daroussin while ((ep = strchr(ep, '\\')) != NULL) { 2013*61d06d6bSBaptiste Daroussin if (*(++ep) == '}') { 2014*61d06d6bSBaptiste Daroussin *ep = '&'; 2015*61d06d6bSBaptiste Daroussin roff_ccond(r, ln, ep - buf->buf - 1); 2016*61d06d6bSBaptiste Daroussin } 2017*61d06d6bSBaptiste Daroussin if (*ep != '\0') 2018*61d06d6bSBaptiste Daroussin ++ep; 2019*61d06d6bSBaptiste Daroussin } 2020*61d06d6bSBaptiste Daroussin return rr ? ROFF_CONT : ROFF_IGN; 2021*61d06d6bSBaptiste Daroussin } 2022*61d06d6bSBaptiste Daroussin 2023*61d06d6bSBaptiste Daroussin /* --- handling of numeric and conditional expressions -------------------- */ 2024*61d06d6bSBaptiste Daroussin 2025*61d06d6bSBaptiste Daroussin /* 2026*61d06d6bSBaptiste Daroussin * Parse a single signed integer number. Stop at the first non-digit. 2027*61d06d6bSBaptiste Daroussin * If there is at least one digit, return success and advance the 2028*61d06d6bSBaptiste Daroussin * parse point, else return failure and let the parse point unchanged. 2029*61d06d6bSBaptiste Daroussin * Ignore overflows, treat them just like the C language. 2030*61d06d6bSBaptiste Daroussin */ 2031*61d06d6bSBaptiste Daroussin static int 2032*61d06d6bSBaptiste Daroussin roff_getnum(const char *v, int *pos, int *res, int flags) 2033*61d06d6bSBaptiste Daroussin { 2034*61d06d6bSBaptiste Daroussin int myres, scaled, n, p; 2035*61d06d6bSBaptiste Daroussin 2036*61d06d6bSBaptiste Daroussin if (NULL == res) 2037*61d06d6bSBaptiste Daroussin res = &myres; 2038*61d06d6bSBaptiste Daroussin 2039*61d06d6bSBaptiste Daroussin p = *pos; 2040*61d06d6bSBaptiste Daroussin n = v[p] == '-'; 2041*61d06d6bSBaptiste Daroussin if (n || v[p] == '+') 2042*61d06d6bSBaptiste Daroussin p++; 2043*61d06d6bSBaptiste Daroussin 2044*61d06d6bSBaptiste Daroussin if (flags & ROFFNUM_WHITE) 2045*61d06d6bSBaptiste Daroussin while (isspace((unsigned char)v[p])) 2046*61d06d6bSBaptiste Daroussin p++; 2047*61d06d6bSBaptiste Daroussin 2048*61d06d6bSBaptiste Daroussin for (*res = 0; isdigit((unsigned char)v[p]); p++) 2049*61d06d6bSBaptiste Daroussin *res = 10 * *res + v[p] - '0'; 2050*61d06d6bSBaptiste Daroussin if (p == *pos + n) 2051*61d06d6bSBaptiste Daroussin return 0; 2052*61d06d6bSBaptiste Daroussin 2053*61d06d6bSBaptiste Daroussin if (n) 2054*61d06d6bSBaptiste Daroussin *res = -*res; 2055*61d06d6bSBaptiste Daroussin 2056*61d06d6bSBaptiste Daroussin /* Each number may be followed by one optional scaling unit. */ 2057*61d06d6bSBaptiste Daroussin 2058*61d06d6bSBaptiste Daroussin switch (v[p]) { 2059*61d06d6bSBaptiste Daroussin case 'f': 2060*61d06d6bSBaptiste Daroussin scaled = *res * 65536; 2061*61d06d6bSBaptiste Daroussin break; 2062*61d06d6bSBaptiste Daroussin case 'i': 2063*61d06d6bSBaptiste Daroussin scaled = *res * 240; 2064*61d06d6bSBaptiste Daroussin break; 2065*61d06d6bSBaptiste Daroussin case 'c': 2066*61d06d6bSBaptiste Daroussin scaled = *res * 240 / 2.54; 2067*61d06d6bSBaptiste Daroussin break; 2068*61d06d6bSBaptiste Daroussin case 'v': 2069*61d06d6bSBaptiste Daroussin case 'P': 2070*61d06d6bSBaptiste Daroussin scaled = *res * 40; 2071*61d06d6bSBaptiste Daroussin break; 2072*61d06d6bSBaptiste Daroussin case 'm': 2073*61d06d6bSBaptiste Daroussin case 'n': 2074*61d06d6bSBaptiste Daroussin scaled = *res * 24; 2075*61d06d6bSBaptiste Daroussin break; 2076*61d06d6bSBaptiste Daroussin case 'p': 2077*61d06d6bSBaptiste Daroussin scaled = *res * 10 / 3; 2078*61d06d6bSBaptiste Daroussin break; 2079*61d06d6bSBaptiste Daroussin case 'u': 2080*61d06d6bSBaptiste Daroussin scaled = *res; 2081*61d06d6bSBaptiste Daroussin break; 2082*61d06d6bSBaptiste Daroussin case 'M': 2083*61d06d6bSBaptiste Daroussin scaled = *res * 6 / 25; 2084*61d06d6bSBaptiste Daroussin break; 2085*61d06d6bSBaptiste Daroussin default: 2086*61d06d6bSBaptiste Daroussin scaled = *res; 2087*61d06d6bSBaptiste Daroussin p--; 2088*61d06d6bSBaptiste Daroussin break; 2089*61d06d6bSBaptiste Daroussin } 2090*61d06d6bSBaptiste Daroussin if (flags & ROFFNUM_SCALE) 2091*61d06d6bSBaptiste Daroussin *res = scaled; 2092*61d06d6bSBaptiste Daroussin 2093*61d06d6bSBaptiste Daroussin *pos = p + 1; 2094*61d06d6bSBaptiste Daroussin return 1; 2095*61d06d6bSBaptiste Daroussin } 2096*61d06d6bSBaptiste Daroussin 2097*61d06d6bSBaptiste Daroussin /* 2098*61d06d6bSBaptiste Daroussin * Evaluate a string comparison condition. 2099*61d06d6bSBaptiste Daroussin * The first character is the delimiter. 2100*61d06d6bSBaptiste Daroussin * Succeed if the string up to its second occurrence 2101*61d06d6bSBaptiste Daroussin * matches the string up to its third occurence. 2102*61d06d6bSBaptiste Daroussin * Advance the cursor after the third occurrence 2103*61d06d6bSBaptiste Daroussin * or lacking that, to the end of the line. 2104*61d06d6bSBaptiste Daroussin */ 2105*61d06d6bSBaptiste Daroussin static int 2106*61d06d6bSBaptiste Daroussin roff_evalstrcond(const char *v, int *pos) 2107*61d06d6bSBaptiste Daroussin { 2108*61d06d6bSBaptiste Daroussin const char *s1, *s2, *s3; 2109*61d06d6bSBaptiste Daroussin int match; 2110*61d06d6bSBaptiste Daroussin 2111*61d06d6bSBaptiste Daroussin match = 0; 2112*61d06d6bSBaptiste Daroussin s1 = v + *pos; /* initial delimiter */ 2113*61d06d6bSBaptiste Daroussin s2 = s1 + 1; /* for scanning the first string */ 2114*61d06d6bSBaptiste Daroussin s3 = strchr(s2, *s1); /* for scanning the second string */ 2115*61d06d6bSBaptiste Daroussin 2116*61d06d6bSBaptiste Daroussin if (NULL == s3) /* found no middle delimiter */ 2117*61d06d6bSBaptiste Daroussin goto out; 2118*61d06d6bSBaptiste Daroussin 2119*61d06d6bSBaptiste Daroussin while ('\0' != *++s3) { 2120*61d06d6bSBaptiste Daroussin if (*s2 != *s3) { /* mismatch */ 2121*61d06d6bSBaptiste Daroussin s3 = strchr(s3, *s1); 2122*61d06d6bSBaptiste Daroussin break; 2123*61d06d6bSBaptiste Daroussin } 2124*61d06d6bSBaptiste Daroussin if (*s3 == *s1) { /* found the final delimiter */ 2125*61d06d6bSBaptiste Daroussin match = 1; 2126*61d06d6bSBaptiste Daroussin break; 2127*61d06d6bSBaptiste Daroussin } 2128*61d06d6bSBaptiste Daroussin s2++; 2129*61d06d6bSBaptiste Daroussin } 2130*61d06d6bSBaptiste Daroussin 2131*61d06d6bSBaptiste Daroussin out: 2132*61d06d6bSBaptiste Daroussin if (NULL == s3) 2133*61d06d6bSBaptiste Daroussin s3 = strchr(s2, '\0'); 2134*61d06d6bSBaptiste Daroussin else if (*s3 != '\0') 2135*61d06d6bSBaptiste Daroussin s3++; 2136*61d06d6bSBaptiste Daroussin *pos = s3 - v; 2137*61d06d6bSBaptiste Daroussin return match; 2138*61d06d6bSBaptiste Daroussin } 2139*61d06d6bSBaptiste Daroussin 2140*61d06d6bSBaptiste Daroussin /* 2141*61d06d6bSBaptiste Daroussin * Evaluate an optionally negated single character, numerical, 2142*61d06d6bSBaptiste Daroussin * or string condition. 2143*61d06d6bSBaptiste Daroussin */ 2144*61d06d6bSBaptiste Daroussin static int 2145*61d06d6bSBaptiste Daroussin roff_evalcond(struct roff *r, int ln, char *v, int *pos) 2146*61d06d6bSBaptiste Daroussin { 2147*61d06d6bSBaptiste Daroussin char *cp, *name; 2148*61d06d6bSBaptiste Daroussin size_t sz; 2149*61d06d6bSBaptiste Daroussin int deftype, number, savepos, istrue, wanttrue; 2150*61d06d6bSBaptiste Daroussin 2151*61d06d6bSBaptiste Daroussin if ('!' == v[*pos]) { 2152*61d06d6bSBaptiste Daroussin wanttrue = 0; 2153*61d06d6bSBaptiste Daroussin (*pos)++; 2154*61d06d6bSBaptiste Daroussin } else 2155*61d06d6bSBaptiste Daroussin wanttrue = 1; 2156*61d06d6bSBaptiste Daroussin 2157*61d06d6bSBaptiste Daroussin switch (v[*pos]) { 2158*61d06d6bSBaptiste Daroussin case '\0': 2159*61d06d6bSBaptiste Daroussin return 0; 2160*61d06d6bSBaptiste Daroussin case 'n': 2161*61d06d6bSBaptiste Daroussin case 'o': 2162*61d06d6bSBaptiste Daroussin (*pos)++; 2163*61d06d6bSBaptiste Daroussin return wanttrue; 2164*61d06d6bSBaptiste Daroussin case 'c': 2165*61d06d6bSBaptiste Daroussin case 'e': 2166*61d06d6bSBaptiste Daroussin case 't': 2167*61d06d6bSBaptiste Daroussin case 'v': 2168*61d06d6bSBaptiste Daroussin (*pos)++; 2169*61d06d6bSBaptiste Daroussin return !wanttrue; 2170*61d06d6bSBaptiste Daroussin case 'd': 2171*61d06d6bSBaptiste Daroussin case 'r': 2172*61d06d6bSBaptiste Daroussin cp = v + *pos + 1; 2173*61d06d6bSBaptiste Daroussin while (*cp == ' ') 2174*61d06d6bSBaptiste Daroussin cp++; 2175*61d06d6bSBaptiste Daroussin name = cp; 2176*61d06d6bSBaptiste Daroussin sz = roff_getname(r, &cp, ln, cp - v); 2177*61d06d6bSBaptiste Daroussin if (sz == 0) 2178*61d06d6bSBaptiste Daroussin istrue = 0; 2179*61d06d6bSBaptiste Daroussin else if (v[*pos] == 'r') 2180*61d06d6bSBaptiste Daroussin istrue = roff_hasregn(r, name, sz); 2181*61d06d6bSBaptiste Daroussin else { 2182*61d06d6bSBaptiste Daroussin deftype = ROFFDEF_ANY; 2183*61d06d6bSBaptiste Daroussin roff_getstrn(r, name, sz, &deftype); 2184*61d06d6bSBaptiste Daroussin istrue = !!deftype; 2185*61d06d6bSBaptiste Daroussin } 2186*61d06d6bSBaptiste Daroussin *pos = cp - v; 2187*61d06d6bSBaptiste Daroussin return istrue == wanttrue; 2188*61d06d6bSBaptiste Daroussin default: 2189*61d06d6bSBaptiste Daroussin break; 2190*61d06d6bSBaptiste Daroussin } 2191*61d06d6bSBaptiste Daroussin 2192*61d06d6bSBaptiste Daroussin savepos = *pos; 2193*61d06d6bSBaptiste Daroussin if (roff_evalnum(r, ln, v, pos, &number, ROFFNUM_SCALE)) 2194*61d06d6bSBaptiste Daroussin return (number > 0) == wanttrue; 2195*61d06d6bSBaptiste Daroussin else if (*pos == savepos) 2196*61d06d6bSBaptiste Daroussin return roff_evalstrcond(v, pos) == wanttrue; 2197*61d06d6bSBaptiste Daroussin else 2198*61d06d6bSBaptiste Daroussin return 0; 2199*61d06d6bSBaptiste Daroussin } 2200*61d06d6bSBaptiste Daroussin 2201*61d06d6bSBaptiste Daroussin static enum rofferr 2202*61d06d6bSBaptiste Daroussin roff_line_ignore(ROFF_ARGS) 2203*61d06d6bSBaptiste Daroussin { 2204*61d06d6bSBaptiste Daroussin 2205*61d06d6bSBaptiste Daroussin return ROFF_IGN; 2206*61d06d6bSBaptiste Daroussin } 2207*61d06d6bSBaptiste Daroussin 2208*61d06d6bSBaptiste Daroussin static enum rofferr 2209*61d06d6bSBaptiste Daroussin roff_insec(ROFF_ARGS) 2210*61d06d6bSBaptiste Daroussin { 2211*61d06d6bSBaptiste Daroussin 2212*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_REQ_INSEC, r->parse, 2213*61d06d6bSBaptiste Daroussin ln, ppos, roff_name[tok]); 2214*61d06d6bSBaptiste Daroussin return ROFF_IGN; 2215*61d06d6bSBaptiste Daroussin } 2216*61d06d6bSBaptiste Daroussin 2217*61d06d6bSBaptiste Daroussin static enum rofferr 2218*61d06d6bSBaptiste Daroussin roff_unsupp(ROFF_ARGS) 2219*61d06d6bSBaptiste Daroussin { 2220*61d06d6bSBaptiste Daroussin 2221*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_REQ_UNSUPP, r->parse, 2222*61d06d6bSBaptiste Daroussin ln, ppos, roff_name[tok]); 2223*61d06d6bSBaptiste Daroussin return ROFF_IGN; 2224*61d06d6bSBaptiste Daroussin } 2225*61d06d6bSBaptiste Daroussin 2226*61d06d6bSBaptiste Daroussin static enum rofferr 2227*61d06d6bSBaptiste Daroussin roff_cond(ROFF_ARGS) 2228*61d06d6bSBaptiste Daroussin { 2229*61d06d6bSBaptiste Daroussin 2230*61d06d6bSBaptiste Daroussin roffnode_push(r, tok, NULL, ln, ppos); 2231*61d06d6bSBaptiste Daroussin 2232*61d06d6bSBaptiste Daroussin /* 2233*61d06d6bSBaptiste Daroussin * An `.el' has no conditional body: it will consume the value 2234*61d06d6bSBaptiste Daroussin * of the current rstack entry set in prior `ie' calls or 2235*61d06d6bSBaptiste Daroussin * defaults to DENY. 2236*61d06d6bSBaptiste Daroussin * 2237*61d06d6bSBaptiste Daroussin * If we're not an `el', however, then evaluate the conditional. 2238*61d06d6bSBaptiste Daroussin */ 2239*61d06d6bSBaptiste Daroussin 2240*61d06d6bSBaptiste Daroussin r->last->rule = tok == ROFF_el ? 2241*61d06d6bSBaptiste Daroussin (r->rstackpos < 0 ? 0 : r->rstack[r->rstackpos--]) : 2242*61d06d6bSBaptiste Daroussin roff_evalcond(r, ln, buf->buf, &pos); 2243*61d06d6bSBaptiste Daroussin 2244*61d06d6bSBaptiste Daroussin /* 2245*61d06d6bSBaptiste Daroussin * An if-else will put the NEGATION of the current evaluated 2246*61d06d6bSBaptiste Daroussin * conditional into the stack of rules. 2247*61d06d6bSBaptiste Daroussin */ 2248*61d06d6bSBaptiste Daroussin 2249*61d06d6bSBaptiste Daroussin if (tok == ROFF_ie) { 2250*61d06d6bSBaptiste Daroussin if (r->rstackpos + 1 == r->rstacksz) { 2251*61d06d6bSBaptiste Daroussin r->rstacksz += 16; 2252*61d06d6bSBaptiste Daroussin r->rstack = mandoc_reallocarray(r->rstack, 2253*61d06d6bSBaptiste Daroussin r->rstacksz, sizeof(int)); 2254*61d06d6bSBaptiste Daroussin } 2255*61d06d6bSBaptiste Daroussin r->rstack[++r->rstackpos] = !r->last->rule; 2256*61d06d6bSBaptiste Daroussin } 2257*61d06d6bSBaptiste Daroussin 2258*61d06d6bSBaptiste Daroussin /* If the parent has false as its rule, then so do we. */ 2259*61d06d6bSBaptiste Daroussin 2260*61d06d6bSBaptiste Daroussin if (r->last->parent && !r->last->parent->rule) 2261*61d06d6bSBaptiste Daroussin r->last->rule = 0; 2262*61d06d6bSBaptiste Daroussin 2263*61d06d6bSBaptiste Daroussin /* 2264*61d06d6bSBaptiste Daroussin * Determine scope. 2265*61d06d6bSBaptiste Daroussin * If there is nothing on the line after the conditional, 2266*61d06d6bSBaptiste Daroussin * not even whitespace, use next-line scope. 2267*61d06d6bSBaptiste Daroussin */ 2268*61d06d6bSBaptiste Daroussin 2269*61d06d6bSBaptiste Daroussin if (buf->buf[pos] == '\0') { 2270*61d06d6bSBaptiste Daroussin r->last->endspan = 2; 2271*61d06d6bSBaptiste Daroussin goto out; 2272*61d06d6bSBaptiste Daroussin } 2273*61d06d6bSBaptiste Daroussin 2274*61d06d6bSBaptiste Daroussin while (buf->buf[pos] == ' ') 2275*61d06d6bSBaptiste Daroussin pos++; 2276*61d06d6bSBaptiste Daroussin 2277*61d06d6bSBaptiste Daroussin /* An opening brace requests multiline scope. */ 2278*61d06d6bSBaptiste Daroussin 2279*61d06d6bSBaptiste Daroussin if (buf->buf[pos] == '\\' && buf->buf[pos + 1] == '{') { 2280*61d06d6bSBaptiste Daroussin r->last->endspan = -1; 2281*61d06d6bSBaptiste Daroussin pos += 2; 2282*61d06d6bSBaptiste Daroussin while (buf->buf[pos] == ' ') 2283*61d06d6bSBaptiste Daroussin pos++; 2284*61d06d6bSBaptiste Daroussin goto out; 2285*61d06d6bSBaptiste Daroussin } 2286*61d06d6bSBaptiste Daroussin 2287*61d06d6bSBaptiste Daroussin /* 2288*61d06d6bSBaptiste Daroussin * Anything else following the conditional causes 2289*61d06d6bSBaptiste Daroussin * single-line scope. Warn if the scope contains 2290*61d06d6bSBaptiste Daroussin * nothing but trailing whitespace. 2291*61d06d6bSBaptiste Daroussin */ 2292*61d06d6bSBaptiste Daroussin 2293*61d06d6bSBaptiste Daroussin if (buf->buf[pos] == '\0') 2294*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_COND_EMPTY, r->parse, 2295*61d06d6bSBaptiste Daroussin ln, ppos, roff_name[tok]); 2296*61d06d6bSBaptiste Daroussin 2297*61d06d6bSBaptiste Daroussin r->last->endspan = 1; 2298*61d06d6bSBaptiste Daroussin 2299*61d06d6bSBaptiste Daroussin out: 2300*61d06d6bSBaptiste Daroussin *offs = pos; 2301*61d06d6bSBaptiste Daroussin return ROFF_RERUN; 2302*61d06d6bSBaptiste Daroussin } 2303*61d06d6bSBaptiste Daroussin 2304*61d06d6bSBaptiste Daroussin static enum rofferr 2305*61d06d6bSBaptiste Daroussin roff_ds(ROFF_ARGS) 2306*61d06d6bSBaptiste Daroussin { 2307*61d06d6bSBaptiste Daroussin char *string; 2308*61d06d6bSBaptiste Daroussin const char *name; 2309*61d06d6bSBaptiste Daroussin size_t namesz; 2310*61d06d6bSBaptiste Daroussin 2311*61d06d6bSBaptiste Daroussin /* Ignore groff compatibility mode for now. */ 2312*61d06d6bSBaptiste Daroussin 2313*61d06d6bSBaptiste Daroussin if (tok == ROFF_ds1) 2314*61d06d6bSBaptiste Daroussin tok = ROFF_ds; 2315*61d06d6bSBaptiste Daroussin else if (tok == ROFF_as1) 2316*61d06d6bSBaptiste Daroussin tok = ROFF_as; 2317*61d06d6bSBaptiste Daroussin 2318*61d06d6bSBaptiste Daroussin /* 2319*61d06d6bSBaptiste Daroussin * The first word is the name of the string. 2320*61d06d6bSBaptiste Daroussin * If it is empty or terminated by an escape sequence, 2321*61d06d6bSBaptiste Daroussin * abort the `ds' request without defining anything. 2322*61d06d6bSBaptiste Daroussin */ 2323*61d06d6bSBaptiste Daroussin 2324*61d06d6bSBaptiste Daroussin name = string = buf->buf + pos; 2325*61d06d6bSBaptiste Daroussin if (*name == '\0') 2326*61d06d6bSBaptiste Daroussin return ROFF_IGN; 2327*61d06d6bSBaptiste Daroussin 2328*61d06d6bSBaptiste Daroussin namesz = roff_getname(r, &string, ln, pos); 2329*61d06d6bSBaptiste Daroussin if (name[namesz] == '\\') 2330*61d06d6bSBaptiste Daroussin return ROFF_IGN; 2331*61d06d6bSBaptiste Daroussin 2332*61d06d6bSBaptiste Daroussin /* Read past the initial double-quote, if any. */ 2333*61d06d6bSBaptiste Daroussin if (*string == '"') 2334*61d06d6bSBaptiste Daroussin string++; 2335*61d06d6bSBaptiste Daroussin 2336*61d06d6bSBaptiste Daroussin /* The rest is the value. */ 2337*61d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, name, namesz, string, strlen(string), 2338*61d06d6bSBaptiste Daroussin ROFF_as == tok); 2339*61d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0); 2340*61d06d6bSBaptiste Daroussin return ROFF_IGN; 2341*61d06d6bSBaptiste Daroussin } 2342*61d06d6bSBaptiste Daroussin 2343*61d06d6bSBaptiste Daroussin /* 2344*61d06d6bSBaptiste Daroussin * Parse a single operator, one or two characters long. 2345*61d06d6bSBaptiste Daroussin * If the operator is recognized, return success and advance the 2346*61d06d6bSBaptiste Daroussin * parse point, else return failure and let the parse point unchanged. 2347*61d06d6bSBaptiste Daroussin */ 2348*61d06d6bSBaptiste Daroussin static int 2349*61d06d6bSBaptiste Daroussin roff_getop(const char *v, int *pos, char *res) 2350*61d06d6bSBaptiste Daroussin { 2351*61d06d6bSBaptiste Daroussin 2352*61d06d6bSBaptiste Daroussin *res = v[*pos]; 2353*61d06d6bSBaptiste Daroussin 2354*61d06d6bSBaptiste Daroussin switch (*res) { 2355*61d06d6bSBaptiste Daroussin case '+': 2356*61d06d6bSBaptiste Daroussin case '-': 2357*61d06d6bSBaptiste Daroussin case '*': 2358*61d06d6bSBaptiste Daroussin case '/': 2359*61d06d6bSBaptiste Daroussin case '%': 2360*61d06d6bSBaptiste Daroussin case '&': 2361*61d06d6bSBaptiste Daroussin case ':': 2362*61d06d6bSBaptiste Daroussin break; 2363*61d06d6bSBaptiste Daroussin case '<': 2364*61d06d6bSBaptiste Daroussin switch (v[*pos + 1]) { 2365*61d06d6bSBaptiste Daroussin case '=': 2366*61d06d6bSBaptiste Daroussin *res = 'l'; 2367*61d06d6bSBaptiste Daroussin (*pos)++; 2368*61d06d6bSBaptiste Daroussin break; 2369*61d06d6bSBaptiste Daroussin case '>': 2370*61d06d6bSBaptiste Daroussin *res = '!'; 2371*61d06d6bSBaptiste Daroussin (*pos)++; 2372*61d06d6bSBaptiste Daroussin break; 2373*61d06d6bSBaptiste Daroussin case '?': 2374*61d06d6bSBaptiste Daroussin *res = 'i'; 2375*61d06d6bSBaptiste Daroussin (*pos)++; 2376*61d06d6bSBaptiste Daroussin break; 2377*61d06d6bSBaptiste Daroussin default: 2378*61d06d6bSBaptiste Daroussin break; 2379*61d06d6bSBaptiste Daroussin } 2380*61d06d6bSBaptiste Daroussin break; 2381*61d06d6bSBaptiste Daroussin case '>': 2382*61d06d6bSBaptiste Daroussin switch (v[*pos + 1]) { 2383*61d06d6bSBaptiste Daroussin case '=': 2384*61d06d6bSBaptiste Daroussin *res = 'g'; 2385*61d06d6bSBaptiste Daroussin (*pos)++; 2386*61d06d6bSBaptiste Daroussin break; 2387*61d06d6bSBaptiste Daroussin case '?': 2388*61d06d6bSBaptiste Daroussin *res = 'a'; 2389*61d06d6bSBaptiste Daroussin (*pos)++; 2390*61d06d6bSBaptiste Daroussin break; 2391*61d06d6bSBaptiste Daroussin default: 2392*61d06d6bSBaptiste Daroussin break; 2393*61d06d6bSBaptiste Daroussin } 2394*61d06d6bSBaptiste Daroussin break; 2395*61d06d6bSBaptiste Daroussin case '=': 2396*61d06d6bSBaptiste Daroussin if ('=' == v[*pos + 1]) 2397*61d06d6bSBaptiste Daroussin (*pos)++; 2398*61d06d6bSBaptiste Daroussin break; 2399*61d06d6bSBaptiste Daroussin default: 2400*61d06d6bSBaptiste Daroussin return 0; 2401*61d06d6bSBaptiste Daroussin } 2402*61d06d6bSBaptiste Daroussin (*pos)++; 2403*61d06d6bSBaptiste Daroussin 2404*61d06d6bSBaptiste Daroussin return *res; 2405*61d06d6bSBaptiste Daroussin } 2406*61d06d6bSBaptiste Daroussin 2407*61d06d6bSBaptiste Daroussin /* 2408*61d06d6bSBaptiste Daroussin * Evaluate either a parenthesized numeric expression 2409*61d06d6bSBaptiste Daroussin * or a single signed integer number. 2410*61d06d6bSBaptiste Daroussin */ 2411*61d06d6bSBaptiste Daroussin static int 2412*61d06d6bSBaptiste Daroussin roff_evalpar(struct roff *r, int ln, 2413*61d06d6bSBaptiste Daroussin const char *v, int *pos, int *res, int flags) 2414*61d06d6bSBaptiste Daroussin { 2415*61d06d6bSBaptiste Daroussin 2416*61d06d6bSBaptiste Daroussin if ('(' != v[*pos]) 2417*61d06d6bSBaptiste Daroussin return roff_getnum(v, pos, res, flags); 2418*61d06d6bSBaptiste Daroussin 2419*61d06d6bSBaptiste Daroussin (*pos)++; 2420*61d06d6bSBaptiste Daroussin if ( ! roff_evalnum(r, ln, v, pos, res, flags | ROFFNUM_WHITE)) 2421*61d06d6bSBaptiste Daroussin return 0; 2422*61d06d6bSBaptiste Daroussin 2423*61d06d6bSBaptiste Daroussin /* 2424*61d06d6bSBaptiste Daroussin * Omission of the closing parenthesis 2425*61d06d6bSBaptiste Daroussin * is an error in validation mode, 2426*61d06d6bSBaptiste Daroussin * but ignored in evaluation mode. 2427*61d06d6bSBaptiste Daroussin */ 2428*61d06d6bSBaptiste Daroussin 2429*61d06d6bSBaptiste Daroussin if (')' == v[*pos]) 2430*61d06d6bSBaptiste Daroussin (*pos)++; 2431*61d06d6bSBaptiste Daroussin else if (NULL == res) 2432*61d06d6bSBaptiste Daroussin return 0; 2433*61d06d6bSBaptiste Daroussin 2434*61d06d6bSBaptiste Daroussin return 1; 2435*61d06d6bSBaptiste Daroussin } 2436*61d06d6bSBaptiste Daroussin 2437*61d06d6bSBaptiste Daroussin /* 2438*61d06d6bSBaptiste Daroussin * Evaluate a complete numeric expression. 2439*61d06d6bSBaptiste Daroussin * Proceed left to right, there is no concept of precedence. 2440*61d06d6bSBaptiste Daroussin */ 2441*61d06d6bSBaptiste Daroussin static int 2442*61d06d6bSBaptiste Daroussin roff_evalnum(struct roff *r, int ln, const char *v, 2443*61d06d6bSBaptiste Daroussin int *pos, int *res, int flags) 2444*61d06d6bSBaptiste Daroussin { 2445*61d06d6bSBaptiste Daroussin int mypos, operand2; 2446*61d06d6bSBaptiste Daroussin char operator; 2447*61d06d6bSBaptiste Daroussin 2448*61d06d6bSBaptiste Daroussin if (NULL == pos) { 2449*61d06d6bSBaptiste Daroussin mypos = 0; 2450*61d06d6bSBaptiste Daroussin pos = &mypos; 2451*61d06d6bSBaptiste Daroussin } 2452*61d06d6bSBaptiste Daroussin 2453*61d06d6bSBaptiste Daroussin if (flags & ROFFNUM_WHITE) 2454*61d06d6bSBaptiste Daroussin while (isspace((unsigned char)v[*pos])) 2455*61d06d6bSBaptiste Daroussin (*pos)++; 2456*61d06d6bSBaptiste Daroussin 2457*61d06d6bSBaptiste Daroussin if ( ! roff_evalpar(r, ln, v, pos, res, flags)) 2458*61d06d6bSBaptiste Daroussin return 0; 2459*61d06d6bSBaptiste Daroussin 2460*61d06d6bSBaptiste Daroussin while (1) { 2461*61d06d6bSBaptiste Daroussin if (flags & ROFFNUM_WHITE) 2462*61d06d6bSBaptiste Daroussin while (isspace((unsigned char)v[*pos])) 2463*61d06d6bSBaptiste Daroussin (*pos)++; 2464*61d06d6bSBaptiste Daroussin 2465*61d06d6bSBaptiste Daroussin if ( ! roff_getop(v, pos, &operator)) 2466*61d06d6bSBaptiste Daroussin break; 2467*61d06d6bSBaptiste Daroussin 2468*61d06d6bSBaptiste Daroussin if (flags & ROFFNUM_WHITE) 2469*61d06d6bSBaptiste Daroussin while (isspace((unsigned char)v[*pos])) 2470*61d06d6bSBaptiste Daroussin (*pos)++; 2471*61d06d6bSBaptiste Daroussin 2472*61d06d6bSBaptiste Daroussin if ( ! roff_evalpar(r, ln, v, pos, &operand2, flags)) 2473*61d06d6bSBaptiste Daroussin return 0; 2474*61d06d6bSBaptiste Daroussin 2475*61d06d6bSBaptiste Daroussin if (flags & ROFFNUM_WHITE) 2476*61d06d6bSBaptiste Daroussin while (isspace((unsigned char)v[*pos])) 2477*61d06d6bSBaptiste Daroussin (*pos)++; 2478*61d06d6bSBaptiste Daroussin 2479*61d06d6bSBaptiste Daroussin if (NULL == res) 2480*61d06d6bSBaptiste Daroussin continue; 2481*61d06d6bSBaptiste Daroussin 2482*61d06d6bSBaptiste Daroussin switch (operator) { 2483*61d06d6bSBaptiste Daroussin case '+': 2484*61d06d6bSBaptiste Daroussin *res += operand2; 2485*61d06d6bSBaptiste Daroussin break; 2486*61d06d6bSBaptiste Daroussin case '-': 2487*61d06d6bSBaptiste Daroussin *res -= operand2; 2488*61d06d6bSBaptiste Daroussin break; 2489*61d06d6bSBaptiste Daroussin case '*': 2490*61d06d6bSBaptiste Daroussin *res *= operand2; 2491*61d06d6bSBaptiste Daroussin break; 2492*61d06d6bSBaptiste Daroussin case '/': 2493*61d06d6bSBaptiste Daroussin if (operand2 == 0) { 2494*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_DIVZERO, 2495*61d06d6bSBaptiste Daroussin r->parse, ln, *pos, v); 2496*61d06d6bSBaptiste Daroussin *res = 0; 2497*61d06d6bSBaptiste Daroussin break; 2498*61d06d6bSBaptiste Daroussin } 2499*61d06d6bSBaptiste Daroussin *res /= operand2; 2500*61d06d6bSBaptiste Daroussin break; 2501*61d06d6bSBaptiste Daroussin case '%': 2502*61d06d6bSBaptiste Daroussin if (operand2 == 0) { 2503*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_DIVZERO, 2504*61d06d6bSBaptiste Daroussin r->parse, ln, *pos, v); 2505*61d06d6bSBaptiste Daroussin *res = 0; 2506*61d06d6bSBaptiste Daroussin break; 2507*61d06d6bSBaptiste Daroussin } 2508*61d06d6bSBaptiste Daroussin *res %= operand2; 2509*61d06d6bSBaptiste Daroussin break; 2510*61d06d6bSBaptiste Daroussin case '<': 2511*61d06d6bSBaptiste Daroussin *res = *res < operand2; 2512*61d06d6bSBaptiste Daroussin break; 2513*61d06d6bSBaptiste Daroussin case '>': 2514*61d06d6bSBaptiste Daroussin *res = *res > operand2; 2515*61d06d6bSBaptiste Daroussin break; 2516*61d06d6bSBaptiste Daroussin case 'l': 2517*61d06d6bSBaptiste Daroussin *res = *res <= operand2; 2518*61d06d6bSBaptiste Daroussin break; 2519*61d06d6bSBaptiste Daroussin case 'g': 2520*61d06d6bSBaptiste Daroussin *res = *res >= operand2; 2521*61d06d6bSBaptiste Daroussin break; 2522*61d06d6bSBaptiste Daroussin case '=': 2523*61d06d6bSBaptiste Daroussin *res = *res == operand2; 2524*61d06d6bSBaptiste Daroussin break; 2525*61d06d6bSBaptiste Daroussin case '!': 2526*61d06d6bSBaptiste Daroussin *res = *res != operand2; 2527*61d06d6bSBaptiste Daroussin break; 2528*61d06d6bSBaptiste Daroussin case '&': 2529*61d06d6bSBaptiste Daroussin *res = *res && operand2; 2530*61d06d6bSBaptiste Daroussin break; 2531*61d06d6bSBaptiste Daroussin case ':': 2532*61d06d6bSBaptiste Daroussin *res = *res || operand2; 2533*61d06d6bSBaptiste Daroussin break; 2534*61d06d6bSBaptiste Daroussin case 'i': 2535*61d06d6bSBaptiste Daroussin if (operand2 < *res) 2536*61d06d6bSBaptiste Daroussin *res = operand2; 2537*61d06d6bSBaptiste Daroussin break; 2538*61d06d6bSBaptiste Daroussin case 'a': 2539*61d06d6bSBaptiste Daroussin if (operand2 > *res) 2540*61d06d6bSBaptiste Daroussin *res = operand2; 2541*61d06d6bSBaptiste Daroussin break; 2542*61d06d6bSBaptiste Daroussin default: 2543*61d06d6bSBaptiste Daroussin abort(); 2544*61d06d6bSBaptiste Daroussin } 2545*61d06d6bSBaptiste Daroussin } 2546*61d06d6bSBaptiste Daroussin return 1; 2547*61d06d6bSBaptiste Daroussin } 2548*61d06d6bSBaptiste Daroussin 2549*61d06d6bSBaptiste Daroussin /* --- register management ------------------------------------------------ */ 2550*61d06d6bSBaptiste Daroussin 2551*61d06d6bSBaptiste Daroussin void 2552*61d06d6bSBaptiste Daroussin roff_setreg(struct roff *r, const char *name, int val, char sign) 2553*61d06d6bSBaptiste Daroussin { 2554*61d06d6bSBaptiste Daroussin roff_setregn(r, name, strlen(name), val, sign, INT_MIN); 2555*61d06d6bSBaptiste Daroussin } 2556*61d06d6bSBaptiste Daroussin 2557*61d06d6bSBaptiste Daroussin static void 2558*61d06d6bSBaptiste Daroussin roff_setregn(struct roff *r, const char *name, size_t len, 2559*61d06d6bSBaptiste Daroussin int val, char sign, int step) 2560*61d06d6bSBaptiste Daroussin { 2561*61d06d6bSBaptiste Daroussin struct roffreg *reg; 2562*61d06d6bSBaptiste Daroussin 2563*61d06d6bSBaptiste Daroussin /* Search for an existing register with the same name. */ 2564*61d06d6bSBaptiste Daroussin reg = r->regtab; 2565*61d06d6bSBaptiste Daroussin 2566*61d06d6bSBaptiste Daroussin while (reg != NULL && (reg->key.sz != len || 2567*61d06d6bSBaptiste Daroussin strncmp(reg->key.p, name, len) != 0)) 2568*61d06d6bSBaptiste Daroussin reg = reg->next; 2569*61d06d6bSBaptiste Daroussin 2570*61d06d6bSBaptiste Daroussin if (NULL == reg) { 2571*61d06d6bSBaptiste Daroussin /* Create a new register. */ 2572*61d06d6bSBaptiste Daroussin reg = mandoc_malloc(sizeof(struct roffreg)); 2573*61d06d6bSBaptiste Daroussin reg->key.p = mandoc_strndup(name, len); 2574*61d06d6bSBaptiste Daroussin reg->key.sz = len; 2575*61d06d6bSBaptiste Daroussin reg->val = 0; 2576*61d06d6bSBaptiste Daroussin reg->step = 0; 2577*61d06d6bSBaptiste Daroussin reg->next = r->regtab; 2578*61d06d6bSBaptiste Daroussin r->regtab = reg; 2579*61d06d6bSBaptiste Daroussin } 2580*61d06d6bSBaptiste Daroussin 2581*61d06d6bSBaptiste Daroussin if ('+' == sign) 2582*61d06d6bSBaptiste Daroussin reg->val += val; 2583*61d06d6bSBaptiste Daroussin else if ('-' == sign) 2584*61d06d6bSBaptiste Daroussin reg->val -= val; 2585*61d06d6bSBaptiste Daroussin else 2586*61d06d6bSBaptiste Daroussin reg->val = val; 2587*61d06d6bSBaptiste Daroussin if (step != INT_MIN) 2588*61d06d6bSBaptiste Daroussin reg->step = step; 2589*61d06d6bSBaptiste Daroussin } 2590*61d06d6bSBaptiste Daroussin 2591*61d06d6bSBaptiste Daroussin /* 2592*61d06d6bSBaptiste Daroussin * Handle some predefined read-only number registers. 2593*61d06d6bSBaptiste Daroussin * For now, return -1 if the requested register is not predefined; 2594*61d06d6bSBaptiste Daroussin * in case a predefined read-only register having the value -1 2595*61d06d6bSBaptiste Daroussin * were to turn up, another special value would have to be chosen. 2596*61d06d6bSBaptiste Daroussin */ 2597*61d06d6bSBaptiste Daroussin static int 2598*61d06d6bSBaptiste Daroussin roff_getregro(const struct roff *r, const char *name) 2599*61d06d6bSBaptiste Daroussin { 2600*61d06d6bSBaptiste Daroussin 2601*61d06d6bSBaptiste Daroussin switch (*name) { 2602*61d06d6bSBaptiste Daroussin case '$': /* Number of arguments of the last macro evaluated. */ 2603*61d06d6bSBaptiste Daroussin return r->argc; 2604*61d06d6bSBaptiste Daroussin case 'A': /* ASCII approximation mode is always off. */ 2605*61d06d6bSBaptiste Daroussin return 0; 2606*61d06d6bSBaptiste Daroussin case 'g': /* Groff compatibility mode is always on. */ 2607*61d06d6bSBaptiste Daroussin return 1; 2608*61d06d6bSBaptiste Daroussin case 'H': /* Fixed horizontal resolution. */ 2609*61d06d6bSBaptiste Daroussin return 24; 2610*61d06d6bSBaptiste Daroussin case 'j': /* Always adjust left margin only. */ 2611*61d06d6bSBaptiste Daroussin return 0; 2612*61d06d6bSBaptiste Daroussin case 'T': /* Some output device is always defined. */ 2613*61d06d6bSBaptiste Daroussin return 1; 2614*61d06d6bSBaptiste Daroussin case 'V': /* Fixed vertical resolution. */ 2615*61d06d6bSBaptiste Daroussin return 40; 2616*61d06d6bSBaptiste Daroussin default: 2617*61d06d6bSBaptiste Daroussin return -1; 2618*61d06d6bSBaptiste Daroussin } 2619*61d06d6bSBaptiste Daroussin } 2620*61d06d6bSBaptiste Daroussin 2621*61d06d6bSBaptiste Daroussin int 2622*61d06d6bSBaptiste Daroussin roff_getreg(struct roff *r, const char *name) 2623*61d06d6bSBaptiste Daroussin { 2624*61d06d6bSBaptiste Daroussin return roff_getregn(r, name, strlen(name), '\0'); 2625*61d06d6bSBaptiste Daroussin } 2626*61d06d6bSBaptiste Daroussin 2627*61d06d6bSBaptiste Daroussin static int 2628*61d06d6bSBaptiste Daroussin roff_getregn(struct roff *r, const char *name, size_t len, char sign) 2629*61d06d6bSBaptiste Daroussin { 2630*61d06d6bSBaptiste Daroussin struct roffreg *reg; 2631*61d06d6bSBaptiste Daroussin int val; 2632*61d06d6bSBaptiste Daroussin 2633*61d06d6bSBaptiste Daroussin if ('.' == name[0] && 2 == len) { 2634*61d06d6bSBaptiste Daroussin val = roff_getregro(r, name + 1); 2635*61d06d6bSBaptiste Daroussin if (-1 != val) 2636*61d06d6bSBaptiste Daroussin return val; 2637*61d06d6bSBaptiste Daroussin } 2638*61d06d6bSBaptiste Daroussin 2639*61d06d6bSBaptiste Daroussin for (reg = r->regtab; reg; reg = reg->next) { 2640*61d06d6bSBaptiste Daroussin if (len == reg->key.sz && 2641*61d06d6bSBaptiste Daroussin 0 == strncmp(name, reg->key.p, len)) { 2642*61d06d6bSBaptiste Daroussin switch (sign) { 2643*61d06d6bSBaptiste Daroussin case '+': 2644*61d06d6bSBaptiste Daroussin reg->val += reg->step; 2645*61d06d6bSBaptiste Daroussin break; 2646*61d06d6bSBaptiste Daroussin case '-': 2647*61d06d6bSBaptiste Daroussin reg->val -= reg->step; 2648*61d06d6bSBaptiste Daroussin break; 2649*61d06d6bSBaptiste Daroussin default: 2650*61d06d6bSBaptiste Daroussin break; 2651*61d06d6bSBaptiste Daroussin } 2652*61d06d6bSBaptiste Daroussin return reg->val; 2653*61d06d6bSBaptiste Daroussin } 2654*61d06d6bSBaptiste Daroussin } 2655*61d06d6bSBaptiste Daroussin 2656*61d06d6bSBaptiste Daroussin roff_setregn(r, name, len, 0, '\0', INT_MIN); 2657*61d06d6bSBaptiste Daroussin return 0; 2658*61d06d6bSBaptiste Daroussin } 2659*61d06d6bSBaptiste Daroussin 2660*61d06d6bSBaptiste Daroussin static int 2661*61d06d6bSBaptiste Daroussin roff_hasregn(const struct roff *r, const char *name, size_t len) 2662*61d06d6bSBaptiste Daroussin { 2663*61d06d6bSBaptiste Daroussin struct roffreg *reg; 2664*61d06d6bSBaptiste Daroussin int val; 2665*61d06d6bSBaptiste Daroussin 2666*61d06d6bSBaptiste Daroussin if ('.' == name[0] && 2 == len) { 2667*61d06d6bSBaptiste Daroussin val = roff_getregro(r, name + 1); 2668*61d06d6bSBaptiste Daroussin if (-1 != val) 2669*61d06d6bSBaptiste Daroussin return 1; 2670*61d06d6bSBaptiste Daroussin } 2671*61d06d6bSBaptiste Daroussin 2672*61d06d6bSBaptiste Daroussin for (reg = r->regtab; reg; reg = reg->next) 2673*61d06d6bSBaptiste Daroussin if (len == reg->key.sz && 2674*61d06d6bSBaptiste Daroussin 0 == strncmp(name, reg->key.p, len)) 2675*61d06d6bSBaptiste Daroussin return 1; 2676*61d06d6bSBaptiste Daroussin 2677*61d06d6bSBaptiste Daroussin return 0; 2678*61d06d6bSBaptiste Daroussin } 2679*61d06d6bSBaptiste Daroussin 2680*61d06d6bSBaptiste Daroussin static void 2681*61d06d6bSBaptiste Daroussin roff_freereg(struct roffreg *reg) 2682*61d06d6bSBaptiste Daroussin { 2683*61d06d6bSBaptiste Daroussin struct roffreg *old_reg; 2684*61d06d6bSBaptiste Daroussin 2685*61d06d6bSBaptiste Daroussin while (NULL != reg) { 2686*61d06d6bSBaptiste Daroussin free(reg->key.p); 2687*61d06d6bSBaptiste Daroussin old_reg = reg; 2688*61d06d6bSBaptiste Daroussin reg = reg->next; 2689*61d06d6bSBaptiste Daroussin free(old_reg); 2690*61d06d6bSBaptiste Daroussin } 2691*61d06d6bSBaptiste Daroussin } 2692*61d06d6bSBaptiste Daroussin 2693*61d06d6bSBaptiste Daroussin static enum rofferr 2694*61d06d6bSBaptiste Daroussin roff_nr(ROFF_ARGS) 2695*61d06d6bSBaptiste Daroussin { 2696*61d06d6bSBaptiste Daroussin char *key, *val, *step; 2697*61d06d6bSBaptiste Daroussin size_t keysz; 2698*61d06d6bSBaptiste Daroussin int iv, is, len; 2699*61d06d6bSBaptiste Daroussin char sign; 2700*61d06d6bSBaptiste Daroussin 2701*61d06d6bSBaptiste Daroussin key = val = buf->buf + pos; 2702*61d06d6bSBaptiste Daroussin if (*key == '\0') 2703*61d06d6bSBaptiste Daroussin return ROFF_IGN; 2704*61d06d6bSBaptiste Daroussin 2705*61d06d6bSBaptiste Daroussin keysz = roff_getname(r, &val, ln, pos); 2706*61d06d6bSBaptiste Daroussin if (key[keysz] == '\\') 2707*61d06d6bSBaptiste Daroussin return ROFF_IGN; 2708*61d06d6bSBaptiste Daroussin 2709*61d06d6bSBaptiste Daroussin sign = *val; 2710*61d06d6bSBaptiste Daroussin if (sign == '+' || sign == '-') 2711*61d06d6bSBaptiste Daroussin val++; 2712*61d06d6bSBaptiste Daroussin 2713*61d06d6bSBaptiste Daroussin len = 0; 2714*61d06d6bSBaptiste Daroussin if (roff_evalnum(r, ln, val, &len, &iv, ROFFNUM_SCALE) == 0) 2715*61d06d6bSBaptiste Daroussin return ROFF_IGN; 2716*61d06d6bSBaptiste Daroussin 2717*61d06d6bSBaptiste Daroussin step = val + len; 2718*61d06d6bSBaptiste Daroussin while (isspace((unsigned char)*step)) 2719*61d06d6bSBaptiste Daroussin step++; 2720*61d06d6bSBaptiste Daroussin if (roff_evalnum(r, ln, step, NULL, &is, 0) == 0) 2721*61d06d6bSBaptiste Daroussin is = INT_MIN; 2722*61d06d6bSBaptiste Daroussin 2723*61d06d6bSBaptiste Daroussin roff_setregn(r, key, keysz, iv, sign, is); 2724*61d06d6bSBaptiste Daroussin return ROFF_IGN; 2725*61d06d6bSBaptiste Daroussin } 2726*61d06d6bSBaptiste Daroussin 2727*61d06d6bSBaptiste Daroussin static enum rofferr 2728*61d06d6bSBaptiste Daroussin roff_rr(ROFF_ARGS) 2729*61d06d6bSBaptiste Daroussin { 2730*61d06d6bSBaptiste Daroussin struct roffreg *reg, **prev; 2731*61d06d6bSBaptiste Daroussin char *name, *cp; 2732*61d06d6bSBaptiste Daroussin size_t namesz; 2733*61d06d6bSBaptiste Daroussin 2734*61d06d6bSBaptiste Daroussin name = cp = buf->buf + pos; 2735*61d06d6bSBaptiste Daroussin if (*name == '\0') 2736*61d06d6bSBaptiste Daroussin return ROFF_IGN; 2737*61d06d6bSBaptiste Daroussin namesz = roff_getname(r, &cp, ln, pos); 2738*61d06d6bSBaptiste Daroussin name[namesz] = '\0'; 2739*61d06d6bSBaptiste Daroussin 2740*61d06d6bSBaptiste Daroussin prev = &r->regtab; 2741*61d06d6bSBaptiste Daroussin while (1) { 2742*61d06d6bSBaptiste Daroussin reg = *prev; 2743*61d06d6bSBaptiste Daroussin if (reg == NULL || !strcmp(name, reg->key.p)) 2744*61d06d6bSBaptiste Daroussin break; 2745*61d06d6bSBaptiste Daroussin prev = ®->next; 2746*61d06d6bSBaptiste Daroussin } 2747*61d06d6bSBaptiste Daroussin if (reg != NULL) { 2748*61d06d6bSBaptiste Daroussin *prev = reg->next; 2749*61d06d6bSBaptiste Daroussin free(reg->key.p); 2750*61d06d6bSBaptiste Daroussin free(reg); 2751*61d06d6bSBaptiste Daroussin } 2752*61d06d6bSBaptiste Daroussin return ROFF_IGN; 2753*61d06d6bSBaptiste Daroussin } 2754*61d06d6bSBaptiste Daroussin 2755*61d06d6bSBaptiste Daroussin /* --- handler functions for roff requests -------------------------------- */ 2756*61d06d6bSBaptiste Daroussin 2757*61d06d6bSBaptiste Daroussin static enum rofferr 2758*61d06d6bSBaptiste Daroussin roff_rm(ROFF_ARGS) 2759*61d06d6bSBaptiste Daroussin { 2760*61d06d6bSBaptiste Daroussin const char *name; 2761*61d06d6bSBaptiste Daroussin char *cp; 2762*61d06d6bSBaptiste Daroussin size_t namesz; 2763*61d06d6bSBaptiste Daroussin 2764*61d06d6bSBaptiste Daroussin cp = buf->buf + pos; 2765*61d06d6bSBaptiste Daroussin while (*cp != '\0') { 2766*61d06d6bSBaptiste Daroussin name = cp; 2767*61d06d6bSBaptiste Daroussin namesz = roff_getname(r, &cp, ln, (int)(cp - buf->buf)); 2768*61d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, name, namesz, NULL, 0, 0); 2769*61d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0); 2770*61d06d6bSBaptiste Daroussin if (name[namesz] == '\\') 2771*61d06d6bSBaptiste Daroussin break; 2772*61d06d6bSBaptiste Daroussin } 2773*61d06d6bSBaptiste Daroussin return ROFF_IGN; 2774*61d06d6bSBaptiste Daroussin } 2775*61d06d6bSBaptiste Daroussin 2776*61d06d6bSBaptiste Daroussin static enum rofferr 2777*61d06d6bSBaptiste Daroussin roff_it(ROFF_ARGS) 2778*61d06d6bSBaptiste Daroussin { 2779*61d06d6bSBaptiste Daroussin int iv; 2780*61d06d6bSBaptiste Daroussin 2781*61d06d6bSBaptiste Daroussin /* Parse the number of lines. */ 2782*61d06d6bSBaptiste Daroussin 2783*61d06d6bSBaptiste Daroussin if ( ! roff_evalnum(r, ln, buf->buf, &pos, &iv, 0)) { 2784*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_IT_NONUM, r->parse, 2785*61d06d6bSBaptiste Daroussin ln, ppos, buf->buf + 1); 2786*61d06d6bSBaptiste Daroussin return ROFF_IGN; 2787*61d06d6bSBaptiste Daroussin } 2788*61d06d6bSBaptiste Daroussin 2789*61d06d6bSBaptiste Daroussin while (isspace((unsigned char)buf->buf[pos])) 2790*61d06d6bSBaptiste Daroussin pos++; 2791*61d06d6bSBaptiste Daroussin 2792*61d06d6bSBaptiste Daroussin /* 2793*61d06d6bSBaptiste Daroussin * Arm the input line trap. 2794*61d06d6bSBaptiste Daroussin * Special-casing "an-trap" is an ugly workaround to cope 2795*61d06d6bSBaptiste Daroussin * with DocBook stupidly fiddling with man(7) internals. 2796*61d06d6bSBaptiste Daroussin */ 2797*61d06d6bSBaptiste Daroussin 2798*61d06d6bSBaptiste Daroussin roffit_lines = iv; 2799*61d06d6bSBaptiste Daroussin roffit_macro = mandoc_strdup(iv != 1 || 2800*61d06d6bSBaptiste Daroussin strcmp(buf->buf + pos, "an-trap") ? 2801*61d06d6bSBaptiste Daroussin buf->buf + pos : "br"); 2802*61d06d6bSBaptiste Daroussin return ROFF_IGN; 2803*61d06d6bSBaptiste Daroussin } 2804*61d06d6bSBaptiste Daroussin 2805*61d06d6bSBaptiste Daroussin static enum rofferr 2806*61d06d6bSBaptiste Daroussin roff_Dd(ROFF_ARGS) 2807*61d06d6bSBaptiste Daroussin { 2808*61d06d6bSBaptiste Daroussin int mask; 2809*61d06d6bSBaptiste Daroussin enum roff_tok t, te; 2810*61d06d6bSBaptiste Daroussin 2811*61d06d6bSBaptiste Daroussin switch (tok) { 2812*61d06d6bSBaptiste Daroussin case ROFF_Dd: 2813*61d06d6bSBaptiste Daroussin tok = MDOC_Dd; 2814*61d06d6bSBaptiste Daroussin te = MDOC_MAX; 2815*61d06d6bSBaptiste Daroussin if (r->format == 0) 2816*61d06d6bSBaptiste Daroussin r->format = MPARSE_MDOC; 2817*61d06d6bSBaptiste Daroussin mask = MPARSE_MDOC | MPARSE_QUICK; 2818*61d06d6bSBaptiste Daroussin break; 2819*61d06d6bSBaptiste Daroussin case ROFF_TH: 2820*61d06d6bSBaptiste Daroussin tok = MAN_TH; 2821*61d06d6bSBaptiste Daroussin te = MAN_MAX; 2822*61d06d6bSBaptiste Daroussin if (r->format == 0) 2823*61d06d6bSBaptiste Daroussin r->format = MPARSE_MAN; 2824*61d06d6bSBaptiste Daroussin mask = MPARSE_QUICK; 2825*61d06d6bSBaptiste Daroussin break; 2826*61d06d6bSBaptiste Daroussin default: 2827*61d06d6bSBaptiste Daroussin abort(); 2828*61d06d6bSBaptiste Daroussin } 2829*61d06d6bSBaptiste Daroussin if ((r->options & mask) == 0) 2830*61d06d6bSBaptiste Daroussin for (t = tok; t < te; t++) 2831*61d06d6bSBaptiste Daroussin roff_setstr(r, roff_name[t], NULL, 0); 2832*61d06d6bSBaptiste Daroussin return ROFF_CONT; 2833*61d06d6bSBaptiste Daroussin } 2834*61d06d6bSBaptiste Daroussin 2835*61d06d6bSBaptiste Daroussin static enum rofferr 2836*61d06d6bSBaptiste Daroussin roff_TE(ROFF_ARGS) 2837*61d06d6bSBaptiste Daroussin { 2838*61d06d6bSBaptiste Daroussin if (r->tbl == NULL) { 2839*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, 2840*61d06d6bSBaptiste Daroussin ln, ppos, "TE"); 2841*61d06d6bSBaptiste Daroussin return ROFF_IGN; 2842*61d06d6bSBaptiste Daroussin } 2843*61d06d6bSBaptiste Daroussin if (tbl_end(r->tbl) == 0) { 2844*61d06d6bSBaptiste Daroussin r->tbl = NULL; 2845*61d06d6bSBaptiste Daroussin free(buf->buf); 2846*61d06d6bSBaptiste Daroussin buf->buf = mandoc_strdup(".sp"); 2847*61d06d6bSBaptiste Daroussin buf->sz = 4; 2848*61d06d6bSBaptiste Daroussin *offs = 0; 2849*61d06d6bSBaptiste Daroussin return ROFF_REPARSE; 2850*61d06d6bSBaptiste Daroussin } 2851*61d06d6bSBaptiste Daroussin r->tbl = NULL; 2852*61d06d6bSBaptiste Daroussin return ROFF_IGN; 2853*61d06d6bSBaptiste Daroussin } 2854*61d06d6bSBaptiste Daroussin 2855*61d06d6bSBaptiste Daroussin static enum rofferr 2856*61d06d6bSBaptiste Daroussin roff_T_(ROFF_ARGS) 2857*61d06d6bSBaptiste Daroussin { 2858*61d06d6bSBaptiste Daroussin 2859*61d06d6bSBaptiste Daroussin if (NULL == r->tbl) 2860*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, 2861*61d06d6bSBaptiste Daroussin ln, ppos, "T&"); 2862*61d06d6bSBaptiste Daroussin else 2863*61d06d6bSBaptiste Daroussin tbl_restart(ln, ppos, r->tbl); 2864*61d06d6bSBaptiste Daroussin 2865*61d06d6bSBaptiste Daroussin return ROFF_IGN; 2866*61d06d6bSBaptiste Daroussin } 2867*61d06d6bSBaptiste Daroussin 2868*61d06d6bSBaptiste Daroussin /* 2869*61d06d6bSBaptiste Daroussin * Handle in-line equation delimiters. 2870*61d06d6bSBaptiste Daroussin */ 2871*61d06d6bSBaptiste Daroussin static enum rofferr 2872*61d06d6bSBaptiste Daroussin roff_eqndelim(struct roff *r, struct buf *buf, int pos) 2873*61d06d6bSBaptiste Daroussin { 2874*61d06d6bSBaptiste Daroussin char *cp1, *cp2; 2875*61d06d6bSBaptiste Daroussin const char *bef_pr, *bef_nl, *mac, *aft_nl, *aft_pr; 2876*61d06d6bSBaptiste Daroussin 2877*61d06d6bSBaptiste Daroussin /* 2878*61d06d6bSBaptiste Daroussin * Outside equations, look for an opening delimiter. 2879*61d06d6bSBaptiste Daroussin * If we are inside an equation, we already know it is 2880*61d06d6bSBaptiste Daroussin * in-line, or this function wouldn't have been called; 2881*61d06d6bSBaptiste Daroussin * so look for a closing delimiter. 2882*61d06d6bSBaptiste Daroussin */ 2883*61d06d6bSBaptiste Daroussin 2884*61d06d6bSBaptiste Daroussin cp1 = buf->buf + pos; 2885*61d06d6bSBaptiste Daroussin cp2 = strchr(cp1, r->eqn == NULL ? 2886*61d06d6bSBaptiste Daroussin r->last_eqn->odelim : r->last_eqn->cdelim); 2887*61d06d6bSBaptiste Daroussin if (cp2 == NULL) 2888*61d06d6bSBaptiste Daroussin return ROFF_CONT; 2889*61d06d6bSBaptiste Daroussin 2890*61d06d6bSBaptiste Daroussin *cp2++ = '\0'; 2891*61d06d6bSBaptiste Daroussin bef_pr = bef_nl = aft_nl = aft_pr = ""; 2892*61d06d6bSBaptiste Daroussin 2893*61d06d6bSBaptiste Daroussin /* Handle preceding text, protecting whitespace. */ 2894*61d06d6bSBaptiste Daroussin 2895*61d06d6bSBaptiste Daroussin if (*buf->buf != '\0') { 2896*61d06d6bSBaptiste Daroussin if (r->eqn == NULL) 2897*61d06d6bSBaptiste Daroussin bef_pr = "\\&"; 2898*61d06d6bSBaptiste Daroussin bef_nl = "\n"; 2899*61d06d6bSBaptiste Daroussin } 2900*61d06d6bSBaptiste Daroussin 2901*61d06d6bSBaptiste Daroussin /* 2902*61d06d6bSBaptiste Daroussin * Prepare replacing the delimiter with an equation macro 2903*61d06d6bSBaptiste Daroussin * and drop leading white space from the equation. 2904*61d06d6bSBaptiste Daroussin */ 2905*61d06d6bSBaptiste Daroussin 2906*61d06d6bSBaptiste Daroussin if (r->eqn == NULL) { 2907*61d06d6bSBaptiste Daroussin while (*cp2 == ' ') 2908*61d06d6bSBaptiste Daroussin cp2++; 2909*61d06d6bSBaptiste Daroussin mac = ".EQ"; 2910*61d06d6bSBaptiste Daroussin } else 2911*61d06d6bSBaptiste Daroussin mac = ".EN"; 2912*61d06d6bSBaptiste Daroussin 2913*61d06d6bSBaptiste Daroussin /* Handle following text, protecting whitespace. */ 2914*61d06d6bSBaptiste Daroussin 2915*61d06d6bSBaptiste Daroussin if (*cp2 != '\0') { 2916*61d06d6bSBaptiste Daroussin aft_nl = "\n"; 2917*61d06d6bSBaptiste Daroussin if (r->eqn != NULL) 2918*61d06d6bSBaptiste Daroussin aft_pr = "\\&"; 2919*61d06d6bSBaptiste Daroussin } 2920*61d06d6bSBaptiste Daroussin 2921*61d06d6bSBaptiste Daroussin /* Do the actual replacement. */ 2922*61d06d6bSBaptiste Daroussin 2923*61d06d6bSBaptiste Daroussin buf->sz = mandoc_asprintf(&cp1, "%s%s%s%s%s%s%s", buf->buf, 2924*61d06d6bSBaptiste Daroussin bef_pr, bef_nl, mac, aft_nl, aft_pr, cp2) + 1; 2925*61d06d6bSBaptiste Daroussin free(buf->buf); 2926*61d06d6bSBaptiste Daroussin buf->buf = cp1; 2927*61d06d6bSBaptiste Daroussin 2928*61d06d6bSBaptiste Daroussin /* Toggle the in-line state of the eqn subsystem. */ 2929*61d06d6bSBaptiste Daroussin 2930*61d06d6bSBaptiste Daroussin r->eqn_inline = r->eqn == NULL; 2931*61d06d6bSBaptiste Daroussin return ROFF_REPARSE; 2932*61d06d6bSBaptiste Daroussin } 2933*61d06d6bSBaptiste Daroussin 2934*61d06d6bSBaptiste Daroussin static enum rofferr 2935*61d06d6bSBaptiste Daroussin roff_EQ(ROFF_ARGS) 2936*61d06d6bSBaptiste Daroussin { 2937*61d06d6bSBaptiste Daroussin struct roff_node *n; 2938*61d06d6bSBaptiste Daroussin 2939*61d06d6bSBaptiste Daroussin if (r->man->macroset == MACROSET_MAN) 2940*61d06d6bSBaptiste Daroussin man_breakscope(r->man, ROFF_EQ); 2941*61d06d6bSBaptiste Daroussin n = roff_node_alloc(r->man, ln, ppos, ROFFT_EQN, TOKEN_NONE); 2942*61d06d6bSBaptiste Daroussin if (ln > r->man->last->line) 2943*61d06d6bSBaptiste Daroussin n->flags |= NODE_LINE; 2944*61d06d6bSBaptiste Daroussin n->eqn = mandoc_calloc(1, sizeof(*n->eqn)); 2945*61d06d6bSBaptiste Daroussin n->eqn->expectargs = UINT_MAX; 2946*61d06d6bSBaptiste Daroussin roff_node_append(r->man, n); 2947*61d06d6bSBaptiste Daroussin r->man->next = ROFF_NEXT_SIBLING; 2948*61d06d6bSBaptiste Daroussin 2949*61d06d6bSBaptiste Daroussin assert(r->eqn == NULL); 2950*61d06d6bSBaptiste Daroussin if (r->last_eqn == NULL) 2951*61d06d6bSBaptiste Daroussin r->last_eqn = eqn_alloc(r->parse); 2952*61d06d6bSBaptiste Daroussin else 2953*61d06d6bSBaptiste Daroussin eqn_reset(r->last_eqn); 2954*61d06d6bSBaptiste Daroussin r->eqn = r->last_eqn; 2955*61d06d6bSBaptiste Daroussin r->eqn->node = n; 2956*61d06d6bSBaptiste Daroussin 2957*61d06d6bSBaptiste Daroussin if (buf->buf[pos] != '\0') 2958*61d06d6bSBaptiste Daroussin mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos, 2959*61d06d6bSBaptiste Daroussin ".EQ %s", buf->buf + pos); 2960*61d06d6bSBaptiste Daroussin 2961*61d06d6bSBaptiste Daroussin return ROFF_IGN; 2962*61d06d6bSBaptiste Daroussin } 2963*61d06d6bSBaptiste Daroussin 2964*61d06d6bSBaptiste Daroussin static enum rofferr 2965*61d06d6bSBaptiste Daroussin roff_EN(ROFF_ARGS) 2966*61d06d6bSBaptiste Daroussin { 2967*61d06d6bSBaptiste Daroussin if (r->eqn != NULL) { 2968*61d06d6bSBaptiste Daroussin eqn_parse(r->eqn); 2969*61d06d6bSBaptiste Daroussin r->eqn = NULL; 2970*61d06d6bSBaptiste Daroussin } else 2971*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, ln, ppos, "EN"); 2972*61d06d6bSBaptiste Daroussin if (buf->buf[pos] != '\0') 2973*61d06d6bSBaptiste Daroussin mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos, 2974*61d06d6bSBaptiste Daroussin "EN %s", buf->buf + pos); 2975*61d06d6bSBaptiste Daroussin return ROFF_IGN; 2976*61d06d6bSBaptiste Daroussin } 2977*61d06d6bSBaptiste Daroussin 2978*61d06d6bSBaptiste Daroussin static enum rofferr 2979*61d06d6bSBaptiste Daroussin roff_TS(ROFF_ARGS) 2980*61d06d6bSBaptiste Daroussin { 2981*61d06d6bSBaptiste Daroussin if (r->tbl != NULL) { 2982*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_BROKEN, r->parse, 2983*61d06d6bSBaptiste Daroussin ln, ppos, "TS breaks TS"); 2984*61d06d6bSBaptiste Daroussin tbl_end(r->tbl); 2985*61d06d6bSBaptiste Daroussin } 2986*61d06d6bSBaptiste Daroussin r->tbl = tbl_alloc(ppos, ln, r->parse); 2987*61d06d6bSBaptiste Daroussin if (r->last_tbl) 2988*61d06d6bSBaptiste Daroussin r->last_tbl->next = r->tbl; 2989*61d06d6bSBaptiste Daroussin else 2990*61d06d6bSBaptiste Daroussin r->first_tbl = r->tbl; 2991*61d06d6bSBaptiste Daroussin r->last_tbl = r->tbl; 2992*61d06d6bSBaptiste Daroussin return ROFF_IGN; 2993*61d06d6bSBaptiste Daroussin } 2994*61d06d6bSBaptiste Daroussin 2995*61d06d6bSBaptiste Daroussin static enum rofferr 2996*61d06d6bSBaptiste Daroussin roff_onearg(ROFF_ARGS) 2997*61d06d6bSBaptiste Daroussin { 2998*61d06d6bSBaptiste Daroussin struct roff_node *n; 2999*61d06d6bSBaptiste Daroussin char *cp; 3000*61d06d6bSBaptiste Daroussin int npos; 3001*61d06d6bSBaptiste Daroussin 3002*61d06d6bSBaptiste Daroussin if (r->man->flags & (MAN_BLINE | MAN_ELINE) && 3003*61d06d6bSBaptiste Daroussin (tok == ROFF_ce || tok == ROFF_rj || tok == ROFF_sp || 3004*61d06d6bSBaptiste Daroussin tok == ROFF_ti)) 3005*61d06d6bSBaptiste Daroussin man_breakscope(r->man, tok); 3006*61d06d6bSBaptiste Daroussin 3007*61d06d6bSBaptiste Daroussin if (roffce_node != NULL && (tok == ROFF_ce || tok == ROFF_rj)) { 3008*61d06d6bSBaptiste Daroussin r->man->last = roffce_node; 3009*61d06d6bSBaptiste Daroussin r->man->next = ROFF_NEXT_SIBLING; 3010*61d06d6bSBaptiste Daroussin } 3011*61d06d6bSBaptiste Daroussin 3012*61d06d6bSBaptiste Daroussin roff_elem_alloc(r->man, ln, ppos, tok); 3013*61d06d6bSBaptiste Daroussin n = r->man->last; 3014*61d06d6bSBaptiste Daroussin 3015*61d06d6bSBaptiste Daroussin cp = buf->buf + pos; 3016*61d06d6bSBaptiste Daroussin if (*cp != '\0') { 3017*61d06d6bSBaptiste Daroussin while (*cp != '\0' && *cp != ' ') 3018*61d06d6bSBaptiste Daroussin cp++; 3019*61d06d6bSBaptiste Daroussin while (*cp == ' ') 3020*61d06d6bSBaptiste Daroussin *cp++ = '\0'; 3021*61d06d6bSBaptiste Daroussin if (*cp != '\0') 3022*61d06d6bSBaptiste Daroussin mandoc_vmsg(MANDOCERR_ARG_EXCESS, 3023*61d06d6bSBaptiste Daroussin r->parse, ln, cp - buf->buf, 3024*61d06d6bSBaptiste Daroussin "%s ... %s", roff_name[tok], cp); 3025*61d06d6bSBaptiste Daroussin roff_word_alloc(r->man, ln, pos, buf->buf + pos); 3026*61d06d6bSBaptiste Daroussin } 3027*61d06d6bSBaptiste Daroussin 3028*61d06d6bSBaptiste Daroussin if (tok == ROFF_ce || tok == ROFF_rj) { 3029*61d06d6bSBaptiste Daroussin if (r->man->last->type == ROFFT_ELEM) { 3030*61d06d6bSBaptiste Daroussin roff_word_alloc(r->man, ln, pos, "1"); 3031*61d06d6bSBaptiste Daroussin r->man->last->flags |= NODE_NOSRC; 3032*61d06d6bSBaptiste Daroussin } 3033*61d06d6bSBaptiste Daroussin npos = 0; 3034*61d06d6bSBaptiste Daroussin if (roff_evalnum(r, ln, r->man->last->string, &npos, 3035*61d06d6bSBaptiste Daroussin &roffce_lines, 0) == 0) { 3036*61d06d6bSBaptiste Daroussin mandoc_vmsg(MANDOCERR_CE_NONUM, 3037*61d06d6bSBaptiste Daroussin r->parse, ln, pos, "ce %s", buf->buf + pos); 3038*61d06d6bSBaptiste Daroussin roffce_lines = 1; 3039*61d06d6bSBaptiste Daroussin } 3040*61d06d6bSBaptiste Daroussin if (roffce_lines < 1) { 3041*61d06d6bSBaptiste Daroussin r->man->last = r->man->last->parent; 3042*61d06d6bSBaptiste Daroussin roffce_node = NULL; 3043*61d06d6bSBaptiste Daroussin roffce_lines = 0; 3044*61d06d6bSBaptiste Daroussin } else 3045*61d06d6bSBaptiste Daroussin roffce_node = r->man->last->parent; 3046*61d06d6bSBaptiste Daroussin } else { 3047*61d06d6bSBaptiste Daroussin n->flags |= NODE_VALID | NODE_ENDED; 3048*61d06d6bSBaptiste Daroussin r->man->last = n; 3049*61d06d6bSBaptiste Daroussin } 3050*61d06d6bSBaptiste Daroussin n->flags |= NODE_LINE; 3051*61d06d6bSBaptiste Daroussin r->man->next = ROFF_NEXT_SIBLING; 3052*61d06d6bSBaptiste Daroussin return ROFF_IGN; 3053*61d06d6bSBaptiste Daroussin } 3054*61d06d6bSBaptiste Daroussin 3055*61d06d6bSBaptiste Daroussin static enum rofferr 3056*61d06d6bSBaptiste Daroussin roff_manyarg(ROFF_ARGS) 3057*61d06d6bSBaptiste Daroussin { 3058*61d06d6bSBaptiste Daroussin struct roff_node *n; 3059*61d06d6bSBaptiste Daroussin char *sp, *ep; 3060*61d06d6bSBaptiste Daroussin 3061*61d06d6bSBaptiste Daroussin roff_elem_alloc(r->man, ln, ppos, tok); 3062*61d06d6bSBaptiste Daroussin n = r->man->last; 3063*61d06d6bSBaptiste Daroussin 3064*61d06d6bSBaptiste Daroussin for (sp = ep = buf->buf + pos; *sp != '\0'; sp = ep) { 3065*61d06d6bSBaptiste Daroussin while (*ep != '\0' && *ep != ' ') 3066*61d06d6bSBaptiste Daroussin ep++; 3067*61d06d6bSBaptiste Daroussin while (*ep == ' ') 3068*61d06d6bSBaptiste Daroussin *ep++ = '\0'; 3069*61d06d6bSBaptiste Daroussin roff_word_alloc(r->man, ln, sp - buf->buf, sp); 3070*61d06d6bSBaptiste Daroussin } 3071*61d06d6bSBaptiste Daroussin 3072*61d06d6bSBaptiste Daroussin n->flags |= NODE_LINE | NODE_VALID | NODE_ENDED; 3073*61d06d6bSBaptiste Daroussin r->man->last = n; 3074*61d06d6bSBaptiste Daroussin r->man->next = ROFF_NEXT_SIBLING; 3075*61d06d6bSBaptiste Daroussin return ROFF_IGN; 3076*61d06d6bSBaptiste Daroussin } 3077*61d06d6bSBaptiste Daroussin 3078*61d06d6bSBaptiste Daroussin static enum rofferr 3079*61d06d6bSBaptiste Daroussin roff_als(ROFF_ARGS) 3080*61d06d6bSBaptiste Daroussin { 3081*61d06d6bSBaptiste Daroussin char *oldn, *newn, *end, *value; 3082*61d06d6bSBaptiste Daroussin size_t oldsz, newsz, valsz; 3083*61d06d6bSBaptiste Daroussin 3084*61d06d6bSBaptiste Daroussin newn = oldn = buf->buf + pos; 3085*61d06d6bSBaptiste Daroussin if (*newn == '\0') 3086*61d06d6bSBaptiste Daroussin return ROFF_IGN; 3087*61d06d6bSBaptiste Daroussin 3088*61d06d6bSBaptiste Daroussin newsz = roff_getname(r, &oldn, ln, pos); 3089*61d06d6bSBaptiste Daroussin if (newn[newsz] == '\\' || *oldn == '\0') 3090*61d06d6bSBaptiste Daroussin return ROFF_IGN; 3091*61d06d6bSBaptiste Daroussin 3092*61d06d6bSBaptiste Daroussin end = oldn; 3093*61d06d6bSBaptiste Daroussin oldsz = roff_getname(r, &end, ln, oldn - buf->buf); 3094*61d06d6bSBaptiste Daroussin if (oldsz == 0) 3095*61d06d6bSBaptiste Daroussin return ROFF_IGN; 3096*61d06d6bSBaptiste Daroussin 3097*61d06d6bSBaptiste Daroussin valsz = mandoc_asprintf(&value, ".%.*s \\$*\\\"\n", 3098*61d06d6bSBaptiste Daroussin (int)oldsz, oldn); 3099*61d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, newn, newsz, value, valsz, 0); 3100*61d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0); 3101*61d06d6bSBaptiste Daroussin free(value); 3102*61d06d6bSBaptiste Daroussin return ROFF_IGN; 3103*61d06d6bSBaptiste Daroussin } 3104*61d06d6bSBaptiste Daroussin 3105*61d06d6bSBaptiste Daroussin static enum rofferr 3106*61d06d6bSBaptiste Daroussin roff_br(ROFF_ARGS) 3107*61d06d6bSBaptiste Daroussin { 3108*61d06d6bSBaptiste Daroussin if (r->man->flags & (MAN_BLINE | MAN_ELINE)) 3109*61d06d6bSBaptiste Daroussin man_breakscope(r->man, ROFF_br); 3110*61d06d6bSBaptiste Daroussin roff_elem_alloc(r->man, ln, ppos, ROFF_br); 3111*61d06d6bSBaptiste Daroussin if (buf->buf[pos] != '\0') 3112*61d06d6bSBaptiste Daroussin mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos, 3113*61d06d6bSBaptiste Daroussin "%s %s", roff_name[tok], buf->buf + pos); 3114*61d06d6bSBaptiste Daroussin r->man->last->flags |= NODE_LINE | NODE_VALID | NODE_ENDED; 3115*61d06d6bSBaptiste Daroussin r->man->next = ROFF_NEXT_SIBLING; 3116*61d06d6bSBaptiste Daroussin return ROFF_IGN; 3117*61d06d6bSBaptiste Daroussin } 3118*61d06d6bSBaptiste Daroussin 3119*61d06d6bSBaptiste Daroussin static enum rofferr 3120*61d06d6bSBaptiste Daroussin roff_cc(ROFF_ARGS) 3121*61d06d6bSBaptiste Daroussin { 3122*61d06d6bSBaptiste Daroussin const char *p; 3123*61d06d6bSBaptiste Daroussin 3124*61d06d6bSBaptiste Daroussin p = buf->buf + pos; 3125*61d06d6bSBaptiste Daroussin 3126*61d06d6bSBaptiste Daroussin if (*p == '\0' || (r->control = *p++) == '.') 3127*61d06d6bSBaptiste Daroussin r->control = '\0'; 3128*61d06d6bSBaptiste Daroussin 3129*61d06d6bSBaptiste Daroussin if (*p != '\0') 3130*61d06d6bSBaptiste Daroussin mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse, 3131*61d06d6bSBaptiste Daroussin ln, p - buf->buf, "cc ... %s", p); 3132*61d06d6bSBaptiste Daroussin 3133*61d06d6bSBaptiste Daroussin return ROFF_IGN; 3134*61d06d6bSBaptiste Daroussin } 3135*61d06d6bSBaptiste Daroussin 3136*61d06d6bSBaptiste Daroussin static enum rofferr 3137*61d06d6bSBaptiste Daroussin roff_ec(ROFF_ARGS) 3138*61d06d6bSBaptiste Daroussin { 3139*61d06d6bSBaptiste Daroussin const char *p; 3140*61d06d6bSBaptiste Daroussin 3141*61d06d6bSBaptiste Daroussin p = buf->buf + pos; 3142*61d06d6bSBaptiste Daroussin if (*p == '\0') 3143*61d06d6bSBaptiste Daroussin r->escape = '\\'; 3144*61d06d6bSBaptiste Daroussin else { 3145*61d06d6bSBaptiste Daroussin r->escape = *p; 3146*61d06d6bSBaptiste Daroussin if (*++p != '\0') 3147*61d06d6bSBaptiste Daroussin mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse, 3148*61d06d6bSBaptiste Daroussin ln, p - buf->buf, "ec ... %s", p); 3149*61d06d6bSBaptiste Daroussin } 3150*61d06d6bSBaptiste Daroussin return ROFF_IGN; 3151*61d06d6bSBaptiste Daroussin } 3152*61d06d6bSBaptiste Daroussin 3153*61d06d6bSBaptiste Daroussin static enum rofferr 3154*61d06d6bSBaptiste Daroussin roff_eo(ROFF_ARGS) 3155*61d06d6bSBaptiste Daroussin { 3156*61d06d6bSBaptiste Daroussin r->escape = '\0'; 3157*61d06d6bSBaptiste Daroussin if (buf->buf[pos] != '\0') 3158*61d06d6bSBaptiste Daroussin mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, 3159*61d06d6bSBaptiste Daroussin ln, pos, "eo %s", buf->buf + pos); 3160*61d06d6bSBaptiste Daroussin return ROFF_IGN; 3161*61d06d6bSBaptiste Daroussin } 3162*61d06d6bSBaptiste Daroussin 3163*61d06d6bSBaptiste Daroussin static enum rofferr 3164*61d06d6bSBaptiste Daroussin roff_tr(ROFF_ARGS) 3165*61d06d6bSBaptiste Daroussin { 3166*61d06d6bSBaptiste Daroussin const char *p, *first, *second; 3167*61d06d6bSBaptiste Daroussin size_t fsz, ssz; 3168*61d06d6bSBaptiste Daroussin enum mandoc_esc esc; 3169*61d06d6bSBaptiste Daroussin 3170*61d06d6bSBaptiste Daroussin p = buf->buf + pos; 3171*61d06d6bSBaptiste Daroussin 3172*61d06d6bSBaptiste Daroussin if (*p == '\0') { 3173*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_REQ_EMPTY, r->parse, ln, ppos, "tr"); 3174*61d06d6bSBaptiste Daroussin return ROFF_IGN; 3175*61d06d6bSBaptiste Daroussin } 3176*61d06d6bSBaptiste Daroussin 3177*61d06d6bSBaptiste Daroussin while (*p != '\0') { 3178*61d06d6bSBaptiste Daroussin fsz = ssz = 1; 3179*61d06d6bSBaptiste Daroussin 3180*61d06d6bSBaptiste Daroussin first = p++; 3181*61d06d6bSBaptiste Daroussin if (*first == '\\') { 3182*61d06d6bSBaptiste Daroussin esc = mandoc_escape(&p, NULL, NULL); 3183*61d06d6bSBaptiste Daroussin if (esc == ESCAPE_ERROR) { 3184*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_ESC_BAD, r->parse, 3185*61d06d6bSBaptiste Daroussin ln, (int)(p - buf->buf), first); 3186*61d06d6bSBaptiste Daroussin return ROFF_IGN; 3187*61d06d6bSBaptiste Daroussin } 3188*61d06d6bSBaptiste Daroussin fsz = (size_t)(p - first); 3189*61d06d6bSBaptiste Daroussin } 3190*61d06d6bSBaptiste Daroussin 3191*61d06d6bSBaptiste Daroussin second = p++; 3192*61d06d6bSBaptiste Daroussin if (*second == '\\') { 3193*61d06d6bSBaptiste Daroussin esc = mandoc_escape(&p, NULL, NULL); 3194*61d06d6bSBaptiste Daroussin if (esc == ESCAPE_ERROR) { 3195*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_ESC_BAD, r->parse, 3196*61d06d6bSBaptiste Daroussin ln, (int)(p - buf->buf), second); 3197*61d06d6bSBaptiste Daroussin return ROFF_IGN; 3198*61d06d6bSBaptiste Daroussin } 3199*61d06d6bSBaptiste Daroussin ssz = (size_t)(p - second); 3200*61d06d6bSBaptiste Daroussin } else if (*second == '\0') { 3201*61d06d6bSBaptiste Daroussin mandoc_vmsg(MANDOCERR_TR_ODD, r->parse, 3202*61d06d6bSBaptiste Daroussin ln, first - buf->buf, "tr %s", first); 3203*61d06d6bSBaptiste Daroussin second = " "; 3204*61d06d6bSBaptiste Daroussin p--; 3205*61d06d6bSBaptiste Daroussin } 3206*61d06d6bSBaptiste Daroussin 3207*61d06d6bSBaptiste Daroussin if (fsz > 1) { 3208*61d06d6bSBaptiste Daroussin roff_setstrn(&r->xmbtab, first, fsz, 3209*61d06d6bSBaptiste Daroussin second, ssz, 0); 3210*61d06d6bSBaptiste Daroussin continue; 3211*61d06d6bSBaptiste Daroussin } 3212*61d06d6bSBaptiste Daroussin 3213*61d06d6bSBaptiste Daroussin if (r->xtab == NULL) 3214*61d06d6bSBaptiste Daroussin r->xtab = mandoc_calloc(128, 3215*61d06d6bSBaptiste Daroussin sizeof(struct roffstr)); 3216*61d06d6bSBaptiste Daroussin 3217*61d06d6bSBaptiste Daroussin free(r->xtab[(int)*first].p); 3218*61d06d6bSBaptiste Daroussin r->xtab[(int)*first].p = mandoc_strndup(second, ssz); 3219*61d06d6bSBaptiste Daroussin r->xtab[(int)*first].sz = ssz; 3220*61d06d6bSBaptiste Daroussin } 3221*61d06d6bSBaptiste Daroussin 3222*61d06d6bSBaptiste Daroussin return ROFF_IGN; 3223*61d06d6bSBaptiste Daroussin } 3224*61d06d6bSBaptiste Daroussin 3225*61d06d6bSBaptiste Daroussin static enum rofferr 3226*61d06d6bSBaptiste Daroussin roff_rn(ROFF_ARGS) 3227*61d06d6bSBaptiste Daroussin { 3228*61d06d6bSBaptiste Daroussin const char *value; 3229*61d06d6bSBaptiste Daroussin char *oldn, *newn, *end; 3230*61d06d6bSBaptiste Daroussin size_t oldsz, newsz; 3231*61d06d6bSBaptiste Daroussin int deftype; 3232*61d06d6bSBaptiste Daroussin 3233*61d06d6bSBaptiste Daroussin oldn = newn = buf->buf + pos; 3234*61d06d6bSBaptiste Daroussin if (*oldn == '\0') 3235*61d06d6bSBaptiste Daroussin return ROFF_IGN; 3236*61d06d6bSBaptiste Daroussin 3237*61d06d6bSBaptiste Daroussin oldsz = roff_getname(r, &newn, ln, pos); 3238*61d06d6bSBaptiste Daroussin if (oldn[oldsz] == '\\' || *newn == '\0') 3239*61d06d6bSBaptiste Daroussin return ROFF_IGN; 3240*61d06d6bSBaptiste Daroussin 3241*61d06d6bSBaptiste Daroussin end = newn; 3242*61d06d6bSBaptiste Daroussin newsz = roff_getname(r, &end, ln, newn - buf->buf); 3243*61d06d6bSBaptiste Daroussin if (newsz == 0) 3244*61d06d6bSBaptiste Daroussin return ROFF_IGN; 3245*61d06d6bSBaptiste Daroussin 3246*61d06d6bSBaptiste Daroussin deftype = ROFFDEF_ANY; 3247*61d06d6bSBaptiste Daroussin value = roff_getstrn(r, oldn, oldsz, &deftype); 3248*61d06d6bSBaptiste Daroussin switch (deftype) { 3249*61d06d6bSBaptiste Daroussin case ROFFDEF_USER: 3250*61d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, newn, newsz, value, strlen(value), 0); 3251*61d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, oldn, oldsz, NULL, 0, 0); 3252*61d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0); 3253*61d06d6bSBaptiste Daroussin break; 3254*61d06d6bSBaptiste Daroussin case ROFFDEF_PRE: 3255*61d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, newn, newsz, value, strlen(value), 0); 3256*61d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0); 3257*61d06d6bSBaptiste Daroussin break; 3258*61d06d6bSBaptiste Daroussin case ROFFDEF_REN: 3259*61d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, newn, newsz, value, strlen(value), 0); 3260*61d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, oldn, oldsz, NULL, 0, 0); 3261*61d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, newn, newsz, NULL, 0, 0); 3262*61d06d6bSBaptiste Daroussin break; 3263*61d06d6bSBaptiste Daroussin case ROFFDEF_STD: 3264*61d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, newn, newsz, oldn, oldsz, 0); 3265*61d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, newn, newsz, NULL, 0, 0); 3266*61d06d6bSBaptiste Daroussin break; 3267*61d06d6bSBaptiste Daroussin default: 3268*61d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, newn, newsz, NULL, 0, 0); 3269*61d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0); 3270*61d06d6bSBaptiste Daroussin break; 3271*61d06d6bSBaptiste Daroussin } 3272*61d06d6bSBaptiste Daroussin return ROFF_IGN; 3273*61d06d6bSBaptiste Daroussin } 3274*61d06d6bSBaptiste Daroussin 3275*61d06d6bSBaptiste Daroussin static enum rofferr 3276*61d06d6bSBaptiste Daroussin roff_so(ROFF_ARGS) 3277*61d06d6bSBaptiste Daroussin { 3278*61d06d6bSBaptiste Daroussin char *name, *cp; 3279*61d06d6bSBaptiste Daroussin 3280*61d06d6bSBaptiste Daroussin name = buf->buf + pos; 3281*61d06d6bSBaptiste Daroussin mandoc_vmsg(MANDOCERR_SO, r->parse, ln, ppos, "so %s", name); 3282*61d06d6bSBaptiste Daroussin 3283*61d06d6bSBaptiste Daroussin /* 3284*61d06d6bSBaptiste Daroussin * Handle `so'. Be EXTREMELY careful, as we shouldn't be 3285*61d06d6bSBaptiste Daroussin * opening anything that's not in our cwd or anything beneath 3286*61d06d6bSBaptiste Daroussin * it. Thus, explicitly disallow traversing up the file-system 3287*61d06d6bSBaptiste Daroussin * or using absolute paths. 3288*61d06d6bSBaptiste Daroussin */ 3289*61d06d6bSBaptiste Daroussin 3290*61d06d6bSBaptiste Daroussin if (*name == '/' || strstr(name, "../") || strstr(name, "/..")) { 3291*61d06d6bSBaptiste Daroussin mandoc_vmsg(MANDOCERR_SO_PATH, r->parse, ln, ppos, 3292*61d06d6bSBaptiste Daroussin ".so %s", name); 3293*61d06d6bSBaptiste Daroussin buf->sz = mandoc_asprintf(&cp, 3294*61d06d6bSBaptiste Daroussin ".sp\nSee the file %s.\n.sp", name) + 1; 3295*61d06d6bSBaptiste Daroussin free(buf->buf); 3296*61d06d6bSBaptiste Daroussin buf->buf = cp; 3297*61d06d6bSBaptiste Daroussin *offs = 0; 3298*61d06d6bSBaptiste Daroussin return ROFF_REPARSE; 3299*61d06d6bSBaptiste Daroussin } 3300*61d06d6bSBaptiste Daroussin 3301*61d06d6bSBaptiste Daroussin *offs = pos; 3302*61d06d6bSBaptiste Daroussin return ROFF_SO; 3303*61d06d6bSBaptiste Daroussin } 3304*61d06d6bSBaptiste Daroussin 3305*61d06d6bSBaptiste Daroussin /* --- user defined strings and macros ------------------------------------ */ 3306*61d06d6bSBaptiste Daroussin 3307*61d06d6bSBaptiste Daroussin static enum rofferr 3308*61d06d6bSBaptiste Daroussin roff_userdef(ROFF_ARGS) 3309*61d06d6bSBaptiste Daroussin { 3310*61d06d6bSBaptiste Daroussin const char *arg[16], *ap; 3311*61d06d6bSBaptiste Daroussin char *cp, *n1, *n2; 3312*61d06d6bSBaptiste Daroussin int expand_count, i, ib, ie; 3313*61d06d6bSBaptiste Daroussin size_t asz, rsz; 3314*61d06d6bSBaptiste Daroussin 3315*61d06d6bSBaptiste Daroussin /* 3316*61d06d6bSBaptiste Daroussin * Collect pointers to macro argument strings 3317*61d06d6bSBaptiste Daroussin * and NUL-terminate them. 3318*61d06d6bSBaptiste Daroussin */ 3319*61d06d6bSBaptiste Daroussin 3320*61d06d6bSBaptiste Daroussin r->argc = 0; 3321*61d06d6bSBaptiste Daroussin cp = buf->buf + pos; 3322*61d06d6bSBaptiste Daroussin for (i = 0; i < 16; i++) { 3323*61d06d6bSBaptiste Daroussin if (*cp == '\0') 3324*61d06d6bSBaptiste Daroussin arg[i] = ""; 3325*61d06d6bSBaptiste Daroussin else { 3326*61d06d6bSBaptiste Daroussin arg[i] = mandoc_getarg(r->parse, &cp, ln, &pos); 3327*61d06d6bSBaptiste Daroussin r->argc = i + 1; 3328*61d06d6bSBaptiste Daroussin } 3329*61d06d6bSBaptiste Daroussin } 3330*61d06d6bSBaptiste Daroussin 3331*61d06d6bSBaptiste Daroussin /* 3332*61d06d6bSBaptiste Daroussin * Expand macro arguments. 3333*61d06d6bSBaptiste Daroussin */ 3334*61d06d6bSBaptiste Daroussin 3335*61d06d6bSBaptiste Daroussin buf->sz = strlen(r->current_string) + 1; 3336*61d06d6bSBaptiste Daroussin n1 = n2 = cp = mandoc_malloc(buf->sz); 3337*61d06d6bSBaptiste Daroussin memcpy(n1, r->current_string, buf->sz); 3338*61d06d6bSBaptiste Daroussin expand_count = 0; 3339*61d06d6bSBaptiste Daroussin while (*cp != '\0') { 3340*61d06d6bSBaptiste Daroussin 3341*61d06d6bSBaptiste Daroussin /* Scan ahead for the next argument invocation. */ 3342*61d06d6bSBaptiste Daroussin 3343*61d06d6bSBaptiste Daroussin if (*cp++ != '\\') 3344*61d06d6bSBaptiste Daroussin continue; 3345*61d06d6bSBaptiste Daroussin if (*cp++ != '$') 3346*61d06d6bSBaptiste Daroussin continue; 3347*61d06d6bSBaptiste Daroussin if (*cp == '*') { /* \\$* inserts all arguments */ 3348*61d06d6bSBaptiste Daroussin ib = 0; 3349*61d06d6bSBaptiste Daroussin ie = r->argc - 1; 3350*61d06d6bSBaptiste Daroussin } else { /* \\$1 .. \\$9 insert one argument */ 3351*61d06d6bSBaptiste Daroussin ib = ie = *cp - '1'; 3352*61d06d6bSBaptiste Daroussin if (ib < 0 || ib > 8) 3353*61d06d6bSBaptiste Daroussin continue; 3354*61d06d6bSBaptiste Daroussin } 3355*61d06d6bSBaptiste Daroussin cp -= 2; 3356*61d06d6bSBaptiste Daroussin 3357*61d06d6bSBaptiste Daroussin /* 3358*61d06d6bSBaptiste Daroussin * Prevent infinite recursion. 3359*61d06d6bSBaptiste Daroussin */ 3360*61d06d6bSBaptiste Daroussin 3361*61d06d6bSBaptiste Daroussin if (cp >= n2) 3362*61d06d6bSBaptiste Daroussin expand_count = 1; 3363*61d06d6bSBaptiste Daroussin else if (++expand_count > EXPAND_LIMIT) { 3364*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, 3365*61d06d6bSBaptiste Daroussin ln, (int)(cp - n1), NULL); 3366*61d06d6bSBaptiste Daroussin free(buf->buf); 3367*61d06d6bSBaptiste Daroussin buf->buf = n1; 3368*61d06d6bSBaptiste Daroussin *offs = 0; 3369*61d06d6bSBaptiste Daroussin return ROFF_IGN; 3370*61d06d6bSBaptiste Daroussin } 3371*61d06d6bSBaptiste Daroussin 3372*61d06d6bSBaptiste Daroussin /* 3373*61d06d6bSBaptiste Daroussin * Determine the size of the expanded argument, 3374*61d06d6bSBaptiste Daroussin * taking escaping of quotes into account. 3375*61d06d6bSBaptiste Daroussin */ 3376*61d06d6bSBaptiste Daroussin 3377*61d06d6bSBaptiste Daroussin asz = ie > ib ? ie - ib : 0; /* for blanks */ 3378*61d06d6bSBaptiste Daroussin for (i = ib; i <= ie; i++) { 3379*61d06d6bSBaptiste Daroussin for (ap = arg[i]; *ap != '\0'; ap++) { 3380*61d06d6bSBaptiste Daroussin asz++; 3381*61d06d6bSBaptiste Daroussin if (*ap == '"') 3382*61d06d6bSBaptiste Daroussin asz += 3; 3383*61d06d6bSBaptiste Daroussin } 3384*61d06d6bSBaptiste Daroussin } 3385*61d06d6bSBaptiste Daroussin if (asz != 3) { 3386*61d06d6bSBaptiste Daroussin 3387*61d06d6bSBaptiste Daroussin /* 3388*61d06d6bSBaptiste Daroussin * Determine the size of the rest of the 3389*61d06d6bSBaptiste Daroussin * unexpanded macro, including the NUL. 3390*61d06d6bSBaptiste Daroussin */ 3391*61d06d6bSBaptiste Daroussin 3392*61d06d6bSBaptiste Daroussin rsz = buf->sz - (cp - n1) - 3; 3393*61d06d6bSBaptiste Daroussin 3394*61d06d6bSBaptiste Daroussin /* 3395*61d06d6bSBaptiste Daroussin * When shrinking, move before 3396*61d06d6bSBaptiste Daroussin * releasing the storage. 3397*61d06d6bSBaptiste Daroussin */ 3398*61d06d6bSBaptiste Daroussin 3399*61d06d6bSBaptiste Daroussin if (asz < 3) 3400*61d06d6bSBaptiste Daroussin memmove(cp + asz, cp + 3, rsz); 3401*61d06d6bSBaptiste Daroussin 3402*61d06d6bSBaptiste Daroussin /* 3403*61d06d6bSBaptiste Daroussin * Resize the storage for the macro 3404*61d06d6bSBaptiste Daroussin * and readjust the parse pointer. 3405*61d06d6bSBaptiste Daroussin */ 3406*61d06d6bSBaptiste Daroussin 3407*61d06d6bSBaptiste Daroussin buf->sz += asz - 3; 3408*61d06d6bSBaptiste Daroussin n2 = mandoc_realloc(n1, buf->sz); 3409*61d06d6bSBaptiste Daroussin cp = n2 + (cp - n1); 3410*61d06d6bSBaptiste Daroussin n1 = n2; 3411*61d06d6bSBaptiste Daroussin 3412*61d06d6bSBaptiste Daroussin /* 3413*61d06d6bSBaptiste Daroussin * When growing, make room 3414*61d06d6bSBaptiste Daroussin * for the expanded argument. 3415*61d06d6bSBaptiste Daroussin */ 3416*61d06d6bSBaptiste Daroussin 3417*61d06d6bSBaptiste Daroussin if (asz > 3) 3418*61d06d6bSBaptiste Daroussin memmove(cp + asz, cp + 3, rsz); 3419*61d06d6bSBaptiste Daroussin } 3420*61d06d6bSBaptiste Daroussin 3421*61d06d6bSBaptiste Daroussin /* Copy the expanded argument, escaping quotes. */ 3422*61d06d6bSBaptiste Daroussin 3423*61d06d6bSBaptiste Daroussin n2 = cp; 3424*61d06d6bSBaptiste Daroussin for (i = ib; i <= ie; i++) { 3425*61d06d6bSBaptiste Daroussin for (ap = arg[i]; *ap != '\0'; ap++) { 3426*61d06d6bSBaptiste Daroussin if (*ap == '"') { 3427*61d06d6bSBaptiste Daroussin memcpy(n2, "\\(dq", 4); 3428*61d06d6bSBaptiste Daroussin n2 += 4; 3429*61d06d6bSBaptiste Daroussin } else 3430*61d06d6bSBaptiste Daroussin *n2++ = *ap; 3431*61d06d6bSBaptiste Daroussin } 3432*61d06d6bSBaptiste Daroussin if (i < ie) 3433*61d06d6bSBaptiste Daroussin *n2++ = ' '; 3434*61d06d6bSBaptiste Daroussin } 3435*61d06d6bSBaptiste Daroussin } 3436*61d06d6bSBaptiste Daroussin 3437*61d06d6bSBaptiste Daroussin /* 3438*61d06d6bSBaptiste Daroussin * Replace the macro invocation 3439*61d06d6bSBaptiste Daroussin * by the expanded macro. 3440*61d06d6bSBaptiste Daroussin */ 3441*61d06d6bSBaptiste Daroussin 3442*61d06d6bSBaptiste Daroussin free(buf->buf); 3443*61d06d6bSBaptiste Daroussin buf->buf = n1; 3444*61d06d6bSBaptiste Daroussin *offs = 0; 3445*61d06d6bSBaptiste Daroussin 3446*61d06d6bSBaptiste Daroussin return buf->sz > 1 && buf->buf[buf->sz - 2] == '\n' ? 3447*61d06d6bSBaptiste Daroussin ROFF_REPARSE : ROFF_APPEND; 3448*61d06d6bSBaptiste Daroussin } 3449*61d06d6bSBaptiste Daroussin 3450*61d06d6bSBaptiste Daroussin /* 3451*61d06d6bSBaptiste Daroussin * Calling a high-level macro that was renamed with .rn. 3452*61d06d6bSBaptiste Daroussin * r->current_string has already been set up by roff_parse(). 3453*61d06d6bSBaptiste Daroussin */ 3454*61d06d6bSBaptiste Daroussin static enum rofferr 3455*61d06d6bSBaptiste Daroussin roff_renamed(ROFF_ARGS) 3456*61d06d6bSBaptiste Daroussin { 3457*61d06d6bSBaptiste Daroussin char *nbuf; 3458*61d06d6bSBaptiste Daroussin 3459*61d06d6bSBaptiste Daroussin buf->sz = mandoc_asprintf(&nbuf, ".%s%s%s", r->current_string, 3460*61d06d6bSBaptiste Daroussin buf->buf[pos] == '\0' ? "" : " ", buf->buf + pos) + 1; 3461*61d06d6bSBaptiste Daroussin free(buf->buf); 3462*61d06d6bSBaptiste Daroussin buf->buf = nbuf; 3463*61d06d6bSBaptiste Daroussin *offs = 0; 3464*61d06d6bSBaptiste Daroussin return ROFF_CONT; 3465*61d06d6bSBaptiste Daroussin } 3466*61d06d6bSBaptiste Daroussin 3467*61d06d6bSBaptiste Daroussin static size_t 3468*61d06d6bSBaptiste Daroussin roff_getname(struct roff *r, char **cpp, int ln, int pos) 3469*61d06d6bSBaptiste Daroussin { 3470*61d06d6bSBaptiste Daroussin char *name, *cp; 3471*61d06d6bSBaptiste Daroussin size_t namesz; 3472*61d06d6bSBaptiste Daroussin 3473*61d06d6bSBaptiste Daroussin name = *cpp; 3474*61d06d6bSBaptiste Daroussin if ('\0' == *name) 3475*61d06d6bSBaptiste Daroussin return 0; 3476*61d06d6bSBaptiste Daroussin 3477*61d06d6bSBaptiste Daroussin /* Read until end of name and terminate it with NUL. */ 3478*61d06d6bSBaptiste Daroussin for (cp = name; 1; cp++) { 3479*61d06d6bSBaptiste Daroussin if ('\0' == *cp || ' ' == *cp) { 3480*61d06d6bSBaptiste Daroussin namesz = cp - name; 3481*61d06d6bSBaptiste Daroussin break; 3482*61d06d6bSBaptiste Daroussin } 3483*61d06d6bSBaptiste Daroussin if ('\\' != *cp) 3484*61d06d6bSBaptiste Daroussin continue; 3485*61d06d6bSBaptiste Daroussin namesz = cp - name; 3486*61d06d6bSBaptiste Daroussin if ('{' == cp[1] || '}' == cp[1]) 3487*61d06d6bSBaptiste Daroussin break; 3488*61d06d6bSBaptiste Daroussin cp++; 3489*61d06d6bSBaptiste Daroussin if ('\\' == *cp) 3490*61d06d6bSBaptiste Daroussin continue; 3491*61d06d6bSBaptiste Daroussin mandoc_vmsg(MANDOCERR_NAMESC, r->parse, ln, pos, 3492*61d06d6bSBaptiste Daroussin "%.*s", (int)(cp - name + 1), name); 3493*61d06d6bSBaptiste Daroussin mandoc_escape((const char **)&cp, NULL, NULL); 3494*61d06d6bSBaptiste Daroussin break; 3495*61d06d6bSBaptiste Daroussin } 3496*61d06d6bSBaptiste Daroussin 3497*61d06d6bSBaptiste Daroussin /* Read past spaces. */ 3498*61d06d6bSBaptiste Daroussin while (' ' == *cp) 3499*61d06d6bSBaptiste Daroussin cp++; 3500*61d06d6bSBaptiste Daroussin 3501*61d06d6bSBaptiste Daroussin *cpp = cp; 3502*61d06d6bSBaptiste Daroussin return namesz; 3503*61d06d6bSBaptiste Daroussin } 3504*61d06d6bSBaptiste Daroussin 3505*61d06d6bSBaptiste Daroussin /* 3506*61d06d6bSBaptiste Daroussin * Store *string into the user-defined string called *name. 3507*61d06d6bSBaptiste Daroussin * To clear an existing entry, call with (*r, *name, NULL, 0). 3508*61d06d6bSBaptiste Daroussin * append == 0: replace mode 3509*61d06d6bSBaptiste Daroussin * append == 1: single-line append mode 3510*61d06d6bSBaptiste Daroussin * append == 2: multiline append mode, append '\n' after each call 3511*61d06d6bSBaptiste Daroussin */ 3512*61d06d6bSBaptiste Daroussin static void 3513*61d06d6bSBaptiste Daroussin roff_setstr(struct roff *r, const char *name, const char *string, 3514*61d06d6bSBaptiste Daroussin int append) 3515*61d06d6bSBaptiste Daroussin { 3516*61d06d6bSBaptiste Daroussin size_t namesz; 3517*61d06d6bSBaptiste Daroussin 3518*61d06d6bSBaptiste Daroussin namesz = strlen(name); 3519*61d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, name, namesz, string, 3520*61d06d6bSBaptiste Daroussin string ? strlen(string) : 0, append); 3521*61d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0); 3522*61d06d6bSBaptiste Daroussin } 3523*61d06d6bSBaptiste Daroussin 3524*61d06d6bSBaptiste Daroussin static void 3525*61d06d6bSBaptiste Daroussin roff_setstrn(struct roffkv **r, const char *name, size_t namesz, 3526*61d06d6bSBaptiste Daroussin const char *string, size_t stringsz, int append) 3527*61d06d6bSBaptiste Daroussin { 3528*61d06d6bSBaptiste Daroussin struct roffkv *n; 3529*61d06d6bSBaptiste Daroussin char *c; 3530*61d06d6bSBaptiste Daroussin int i; 3531*61d06d6bSBaptiste Daroussin size_t oldch, newch; 3532*61d06d6bSBaptiste Daroussin 3533*61d06d6bSBaptiste Daroussin /* Search for an existing string with the same name. */ 3534*61d06d6bSBaptiste Daroussin n = *r; 3535*61d06d6bSBaptiste Daroussin 3536*61d06d6bSBaptiste Daroussin while (n && (namesz != n->key.sz || 3537*61d06d6bSBaptiste Daroussin strncmp(n->key.p, name, namesz))) 3538*61d06d6bSBaptiste Daroussin n = n->next; 3539*61d06d6bSBaptiste Daroussin 3540*61d06d6bSBaptiste Daroussin if (NULL == n) { 3541*61d06d6bSBaptiste Daroussin /* Create a new string table entry. */ 3542*61d06d6bSBaptiste Daroussin n = mandoc_malloc(sizeof(struct roffkv)); 3543*61d06d6bSBaptiste Daroussin n->key.p = mandoc_strndup(name, namesz); 3544*61d06d6bSBaptiste Daroussin n->key.sz = namesz; 3545*61d06d6bSBaptiste Daroussin n->val.p = NULL; 3546*61d06d6bSBaptiste Daroussin n->val.sz = 0; 3547*61d06d6bSBaptiste Daroussin n->next = *r; 3548*61d06d6bSBaptiste Daroussin *r = n; 3549*61d06d6bSBaptiste Daroussin } else if (0 == append) { 3550*61d06d6bSBaptiste Daroussin free(n->val.p); 3551*61d06d6bSBaptiste Daroussin n->val.p = NULL; 3552*61d06d6bSBaptiste Daroussin n->val.sz = 0; 3553*61d06d6bSBaptiste Daroussin } 3554*61d06d6bSBaptiste Daroussin 3555*61d06d6bSBaptiste Daroussin if (NULL == string) 3556*61d06d6bSBaptiste Daroussin return; 3557*61d06d6bSBaptiste Daroussin 3558*61d06d6bSBaptiste Daroussin /* 3559*61d06d6bSBaptiste Daroussin * One additional byte for the '\n' in multiline mode, 3560*61d06d6bSBaptiste Daroussin * and one for the terminating '\0'. 3561*61d06d6bSBaptiste Daroussin */ 3562*61d06d6bSBaptiste Daroussin newch = stringsz + (1 < append ? 2u : 1u); 3563*61d06d6bSBaptiste Daroussin 3564*61d06d6bSBaptiste Daroussin if (NULL == n->val.p) { 3565*61d06d6bSBaptiste Daroussin n->val.p = mandoc_malloc(newch); 3566*61d06d6bSBaptiste Daroussin *n->val.p = '\0'; 3567*61d06d6bSBaptiste Daroussin oldch = 0; 3568*61d06d6bSBaptiste Daroussin } else { 3569*61d06d6bSBaptiste Daroussin oldch = n->val.sz; 3570*61d06d6bSBaptiste Daroussin n->val.p = mandoc_realloc(n->val.p, oldch + newch); 3571*61d06d6bSBaptiste Daroussin } 3572*61d06d6bSBaptiste Daroussin 3573*61d06d6bSBaptiste Daroussin /* Skip existing content in the destination buffer. */ 3574*61d06d6bSBaptiste Daroussin c = n->val.p + (int)oldch; 3575*61d06d6bSBaptiste Daroussin 3576*61d06d6bSBaptiste Daroussin /* Append new content to the destination buffer. */ 3577*61d06d6bSBaptiste Daroussin i = 0; 3578*61d06d6bSBaptiste Daroussin while (i < (int)stringsz) { 3579*61d06d6bSBaptiste Daroussin /* 3580*61d06d6bSBaptiste Daroussin * Rudimentary roff copy mode: 3581*61d06d6bSBaptiste Daroussin * Handle escaped backslashes. 3582*61d06d6bSBaptiste Daroussin */ 3583*61d06d6bSBaptiste Daroussin if ('\\' == string[i] && '\\' == string[i + 1]) 3584*61d06d6bSBaptiste Daroussin i++; 3585*61d06d6bSBaptiste Daroussin *c++ = string[i++]; 3586*61d06d6bSBaptiste Daroussin } 3587*61d06d6bSBaptiste Daroussin 3588*61d06d6bSBaptiste Daroussin /* Append terminating bytes. */ 3589*61d06d6bSBaptiste Daroussin if (1 < append) 3590*61d06d6bSBaptiste Daroussin *c++ = '\n'; 3591*61d06d6bSBaptiste Daroussin 3592*61d06d6bSBaptiste Daroussin *c = '\0'; 3593*61d06d6bSBaptiste Daroussin n->val.sz = (int)(c - n->val.p); 3594*61d06d6bSBaptiste Daroussin } 3595*61d06d6bSBaptiste Daroussin 3596*61d06d6bSBaptiste Daroussin static const char * 3597*61d06d6bSBaptiste Daroussin roff_getstrn(struct roff *r, const char *name, size_t len, 3598*61d06d6bSBaptiste Daroussin int *deftype) 3599*61d06d6bSBaptiste Daroussin { 3600*61d06d6bSBaptiste Daroussin const struct roffkv *n; 3601*61d06d6bSBaptiste Daroussin int found, i; 3602*61d06d6bSBaptiste Daroussin enum roff_tok tok; 3603*61d06d6bSBaptiste Daroussin 3604*61d06d6bSBaptiste Daroussin found = 0; 3605*61d06d6bSBaptiste Daroussin for (n = r->strtab; n != NULL; n = n->next) { 3606*61d06d6bSBaptiste Daroussin if (strncmp(name, n->key.p, len) != 0 || 3607*61d06d6bSBaptiste Daroussin n->key.p[len] != '\0' || n->val.p == NULL) 3608*61d06d6bSBaptiste Daroussin continue; 3609*61d06d6bSBaptiste Daroussin if (*deftype & ROFFDEF_USER) { 3610*61d06d6bSBaptiste Daroussin *deftype = ROFFDEF_USER; 3611*61d06d6bSBaptiste Daroussin return n->val.p; 3612*61d06d6bSBaptiste Daroussin } else { 3613*61d06d6bSBaptiste Daroussin found = 1; 3614*61d06d6bSBaptiste Daroussin break; 3615*61d06d6bSBaptiste Daroussin } 3616*61d06d6bSBaptiste Daroussin } 3617*61d06d6bSBaptiste Daroussin for (n = r->rentab; n != NULL; n = n->next) { 3618*61d06d6bSBaptiste Daroussin if (strncmp(name, n->key.p, len) != 0 || 3619*61d06d6bSBaptiste Daroussin n->key.p[len] != '\0' || n->val.p == NULL) 3620*61d06d6bSBaptiste Daroussin continue; 3621*61d06d6bSBaptiste Daroussin if (*deftype & ROFFDEF_REN) { 3622*61d06d6bSBaptiste Daroussin *deftype = ROFFDEF_REN; 3623*61d06d6bSBaptiste Daroussin return n->val.p; 3624*61d06d6bSBaptiste Daroussin } else { 3625*61d06d6bSBaptiste Daroussin found = 1; 3626*61d06d6bSBaptiste Daroussin break; 3627*61d06d6bSBaptiste Daroussin } 3628*61d06d6bSBaptiste Daroussin } 3629*61d06d6bSBaptiste Daroussin for (i = 0; i < PREDEFS_MAX; i++) { 3630*61d06d6bSBaptiste Daroussin if (strncmp(name, predefs[i].name, len) != 0 || 3631*61d06d6bSBaptiste Daroussin predefs[i].name[len] != '\0') 3632*61d06d6bSBaptiste Daroussin continue; 3633*61d06d6bSBaptiste Daroussin if (*deftype & ROFFDEF_PRE) { 3634*61d06d6bSBaptiste Daroussin *deftype = ROFFDEF_PRE; 3635*61d06d6bSBaptiste Daroussin return predefs[i].str; 3636*61d06d6bSBaptiste Daroussin } else { 3637*61d06d6bSBaptiste Daroussin found = 1; 3638*61d06d6bSBaptiste Daroussin break; 3639*61d06d6bSBaptiste Daroussin } 3640*61d06d6bSBaptiste Daroussin } 3641*61d06d6bSBaptiste Daroussin if (r->man->macroset != MACROSET_MAN) { 3642*61d06d6bSBaptiste Daroussin for (tok = MDOC_Dd; tok < MDOC_MAX; tok++) { 3643*61d06d6bSBaptiste Daroussin if (strncmp(name, roff_name[tok], len) != 0 || 3644*61d06d6bSBaptiste Daroussin roff_name[tok][len] != '\0') 3645*61d06d6bSBaptiste Daroussin continue; 3646*61d06d6bSBaptiste Daroussin if (*deftype & ROFFDEF_STD) { 3647*61d06d6bSBaptiste Daroussin *deftype = ROFFDEF_STD; 3648*61d06d6bSBaptiste Daroussin return NULL; 3649*61d06d6bSBaptiste Daroussin } else { 3650*61d06d6bSBaptiste Daroussin found = 1; 3651*61d06d6bSBaptiste Daroussin break; 3652*61d06d6bSBaptiste Daroussin } 3653*61d06d6bSBaptiste Daroussin } 3654*61d06d6bSBaptiste Daroussin } 3655*61d06d6bSBaptiste Daroussin if (r->man->macroset != MACROSET_MDOC) { 3656*61d06d6bSBaptiste Daroussin for (tok = MAN_TH; tok < MAN_MAX; tok++) { 3657*61d06d6bSBaptiste Daroussin if (strncmp(name, roff_name[tok], len) != 0 || 3658*61d06d6bSBaptiste Daroussin roff_name[tok][len] != '\0') 3659*61d06d6bSBaptiste Daroussin continue; 3660*61d06d6bSBaptiste Daroussin if (*deftype & ROFFDEF_STD) { 3661*61d06d6bSBaptiste Daroussin *deftype = ROFFDEF_STD; 3662*61d06d6bSBaptiste Daroussin return NULL; 3663*61d06d6bSBaptiste Daroussin } else { 3664*61d06d6bSBaptiste Daroussin found = 1; 3665*61d06d6bSBaptiste Daroussin break; 3666*61d06d6bSBaptiste Daroussin } 3667*61d06d6bSBaptiste Daroussin } 3668*61d06d6bSBaptiste Daroussin } 3669*61d06d6bSBaptiste Daroussin 3670*61d06d6bSBaptiste Daroussin if (found == 0 && *deftype != ROFFDEF_ANY) { 3671*61d06d6bSBaptiste Daroussin if (*deftype & ROFFDEF_REN) { 3672*61d06d6bSBaptiste Daroussin /* 3673*61d06d6bSBaptiste Daroussin * This might still be a request, 3674*61d06d6bSBaptiste Daroussin * so do not treat it as undefined yet. 3675*61d06d6bSBaptiste Daroussin */ 3676*61d06d6bSBaptiste Daroussin *deftype = ROFFDEF_UNDEF; 3677*61d06d6bSBaptiste Daroussin return NULL; 3678*61d06d6bSBaptiste Daroussin } 3679*61d06d6bSBaptiste Daroussin 3680*61d06d6bSBaptiste Daroussin /* Using an undefined string defines it to be empty. */ 3681*61d06d6bSBaptiste Daroussin 3682*61d06d6bSBaptiste Daroussin roff_setstrn(&r->strtab, name, len, "", 0, 0); 3683*61d06d6bSBaptiste Daroussin roff_setstrn(&r->rentab, name, len, NULL, 0, 0); 3684*61d06d6bSBaptiste Daroussin } 3685*61d06d6bSBaptiste Daroussin 3686*61d06d6bSBaptiste Daroussin *deftype = 0; 3687*61d06d6bSBaptiste Daroussin return NULL; 3688*61d06d6bSBaptiste Daroussin } 3689*61d06d6bSBaptiste Daroussin 3690*61d06d6bSBaptiste Daroussin static void 3691*61d06d6bSBaptiste Daroussin roff_freestr(struct roffkv *r) 3692*61d06d6bSBaptiste Daroussin { 3693*61d06d6bSBaptiste Daroussin struct roffkv *n, *nn; 3694*61d06d6bSBaptiste Daroussin 3695*61d06d6bSBaptiste Daroussin for (n = r; n; n = nn) { 3696*61d06d6bSBaptiste Daroussin free(n->key.p); 3697*61d06d6bSBaptiste Daroussin free(n->val.p); 3698*61d06d6bSBaptiste Daroussin nn = n->next; 3699*61d06d6bSBaptiste Daroussin free(n); 3700*61d06d6bSBaptiste Daroussin } 3701*61d06d6bSBaptiste Daroussin } 3702*61d06d6bSBaptiste Daroussin 3703*61d06d6bSBaptiste Daroussin /* --- accessors and utility functions ------------------------------------ */ 3704*61d06d6bSBaptiste Daroussin 3705*61d06d6bSBaptiste Daroussin /* 3706*61d06d6bSBaptiste Daroussin * Duplicate an input string, making the appropriate character 3707*61d06d6bSBaptiste Daroussin * conversations (as stipulated by `tr') along the way. 3708*61d06d6bSBaptiste Daroussin * Returns a heap-allocated string with all the replacements made. 3709*61d06d6bSBaptiste Daroussin */ 3710*61d06d6bSBaptiste Daroussin char * 3711*61d06d6bSBaptiste Daroussin roff_strdup(const struct roff *r, const char *p) 3712*61d06d6bSBaptiste Daroussin { 3713*61d06d6bSBaptiste Daroussin const struct roffkv *cp; 3714*61d06d6bSBaptiste Daroussin char *res; 3715*61d06d6bSBaptiste Daroussin const char *pp; 3716*61d06d6bSBaptiste Daroussin size_t ssz, sz; 3717*61d06d6bSBaptiste Daroussin enum mandoc_esc esc; 3718*61d06d6bSBaptiste Daroussin 3719*61d06d6bSBaptiste Daroussin if (NULL == r->xmbtab && NULL == r->xtab) 3720*61d06d6bSBaptiste Daroussin return mandoc_strdup(p); 3721*61d06d6bSBaptiste Daroussin else if ('\0' == *p) 3722*61d06d6bSBaptiste Daroussin return mandoc_strdup(""); 3723*61d06d6bSBaptiste Daroussin 3724*61d06d6bSBaptiste Daroussin /* 3725*61d06d6bSBaptiste Daroussin * Step through each character looking for term matches 3726*61d06d6bSBaptiste Daroussin * (remember that a `tr' can be invoked with an escape, which is 3727*61d06d6bSBaptiste Daroussin * a glyph but the escape is multi-character). 3728*61d06d6bSBaptiste Daroussin * We only do this if the character hash has been initialised 3729*61d06d6bSBaptiste Daroussin * and the string is >0 length. 3730*61d06d6bSBaptiste Daroussin */ 3731*61d06d6bSBaptiste Daroussin 3732*61d06d6bSBaptiste Daroussin res = NULL; 3733*61d06d6bSBaptiste Daroussin ssz = 0; 3734*61d06d6bSBaptiste Daroussin 3735*61d06d6bSBaptiste Daroussin while ('\0' != *p) { 3736*61d06d6bSBaptiste Daroussin assert((unsigned int)*p < 128); 3737*61d06d6bSBaptiste Daroussin if ('\\' != *p && r->xtab && r->xtab[(unsigned int)*p].p) { 3738*61d06d6bSBaptiste Daroussin sz = r->xtab[(int)*p].sz; 3739*61d06d6bSBaptiste Daroussin res = mandoc_realloc(res, ssz + sz + 1); 3740*61d06d6bSBaptiste Daroussin memcpy(res + ssz, r->xtab[(int)*p].p, sz); 3741*61d06d6bSBaptiste Daroussin ssz += sz; 3742*61d06d6bSBaptiste Daroussin p++; 3743*61d06d6bSBaptiste Daroussin continue; 3744*61d06d6bSBaptiste Daroussin } else if ('\\' != *p) { 3745*61d06d6bSBaptiste Daroussin res = mandoc_realloc(res, ssz + 2); 3746*61d06d6bSBaptiste Daroussin res[ssz++] = *p++; 3747*61d06d6bSBaptiste Daroussin continue; 3748*61d06d6bSBaptiste Daroussin } 3749*61d06d6bSBaptiste Daroussin 3750*61d06d6bSBaptiste Daroussin /* Search for term matches. */ 3751*61d06d6bSBaptiste Daroussin for (cp = r->xmbtab; cp; cp = cp->next) 3752*61d06d6bSBaptiste Daroussin if (0 == strncmp(p, cp->key.p, cp->key.sz)) 3753*61d06d6bSBaptiste Daroussin break; 3754*61d06d6bSBaptiste Daroussin 3755*61d06d6bSBaptiste Daroussin if (NULL != cp) { 3756*61d06d6bSBaptiste Daroussin /* 3757*61d06d6bSBaptiste Daroussin * A match has been found. 3758*61d06d6bSBaptiste Daroussin * Append the match to the array and move 3759*61d06d6bSBaptiste Daroussin * forward by its keysize. 3760*61d06d6bSBaptiste Daroussin */ 3761*61d06d6bSBaptiste Daroussin res = mandoc_realloc(res, 3762*61d06d6bSBaptiste Daroussin ssz + cp->val.sz + 1); 3763*61d06d6bSBaptiste Daroussin memcpy(res + ssz, cp->val.p, cp->val.sz); 3764*61d06d6bSBaptiste Daroussin ssz += cp->val.sz; 3765*61d06d6bSBaptiste Daroussin p += (int)cp->key.sz; 3766*61d06d6bSBaptiste Daroussin continue; 3767*61d06d6bSBaptiste Daroussin } 3768*61d06d6bSBaptiste Daroussin 3769*61d06d6bSBaptiste Daroussin /* 3770*61d06d6bSBaptiste Daroussin * Handle escapes carefully: we need to copy 3771*61d06d6bSBaptiste Daroussin * over just the escape itself, or else we might 3772*61d06d6bSBaptiste Daroussin * do replacements within the escape itself. 3773*61d06d6bSBaptiste Daroussin * Make sure to pass along the bogus string. 3774*61d06d6bSBaptiste Daroussin */ 3775*61d06d6bSBaptiste Daroussin pp = p++; 3776*61d06d6bSBaptiste Daroussin esc = mandoc_escape(&p, NULL, NULL); 3777*61d06d6bSBaptiste Daroussin if (ESCAPE_ERROR == esc) { 3778*61d06d6bSBaptiste Daroussin sz = strlen(pp); 3779*61d06d6bSBaptiste Daroussin res = mandoc_realloc(res, ssz + sz + 1); 3780*61d06d6bSBaptiste Daroussin memcpy(res + ssz, pp, sz); 3781*61d06d6bSBaptiste Daroussin break; 3782*61d06d6bSBaptiste Daroussin } 3783*61d06d6bSBaptiste Daroussin /* 3784*61d06d6bSBaptiste Daroussin * We bail out on bad escapes. 3785*61d06d6bSBaptiste Daroussin * No need to warn: we already did so when 3786*61d06d6bSBaptiste Daroussin * roff_res() was called. 3787*61d06d6bSBaptiste Daroussin */ 3788*61d06d6bSBaptiste Daroussin sz = (int)(p - pp); 3789*61d06d6bSBaptiste Daroussin res = mandoc_realloc(res, ssz + sz + 1); 3790*61d06d6bSBaptiste Daroussin memcpy(res + ssz, pp, sz); 3791*61d06d6bSBaptiste Daroussin ssz += sz; 3792*61d06d6bSBaptiste Daroussin } 3793*61d06d6bSBaptiste Daroussin 3794*61d06d6bSBaptiste Daroussin res[(int)ssz] = '\0'; 3795*61d06d6bSBaptiste Daroussin return res; 3796*61d06d6bSBaptiste Daroussin } 3797*61d06d6bSBaptiste Daroussin 3798*61d06d6bSBaptiste Daroussin int 3799*61d06d6bSBaptiste Daroussin roff_getformat(const struct roff *r) 3800*61d06d6bSBaptiste Daroussin { 3801*61d06d6bSBaptiste Daroussin 3802*61d06d6bSBaptiste Daroussin return r->format; 3803*61d06d6bSBaptiste Daroussin } 3804*61d06d6bSBaptiste Daroussin 3805*61d06d6bSBaptiste Daroussin /* 3806*61d06d6bSBaptiste Daroussin * Find out whether a line is a macro line or not. 3807*61d06d6bSBaptiste Daroussin * If it is, adjust the current position and return one; if it isn't, 3808*61d06d6bSBaptiste Daroussin * return zero and don't change the current position. 3809*61d06d6bSBaptiste Daroussin * If the control character has been set with `.cc', then let that grain 3810*61d06d6bSBaptiste Daroussin * precedence. 3811*61d06d6bSBaptiste Daroussin * This is slighly contrary to groff, where using the non-breaking 3812*61d06d6bSBaptiste Daroussin * control character when `cc' has been invoked will cause the 3813*61d06d6bSBaptiste Daroussin * non-breaking macro contents to be printed verbatim. 3814*61d06d6bSBaptiste Daroussin */ 3815*61d06d6bSBaptiste Daroussin int 3816*61d06d6bSBaptiste Daroussin roff_getcontrol(const struct roff *r, const char *cp, int *ppos) 3817*61d06d6bSBaptiste Daroussin { 3818*61d06d6bSBaptiste Daroussin int pos; 3819*61d06d6bSBaptiste Daroussin 3820*61d06d6bSBaptiste Daroussin pos = *ppos; 3821*61d06d6bSBaptiste Daroussin 3822*61d06d6bSBaptiste Daroussin if (r->control != '\0' && cp[pos] == r->control) 3823*61d06d6bSBaptiste Daroussin pos++; 3824*61d06d6bSBaptiste Daroussin else if (r->control != '\0') 3825*61d06d6bSBaptiste Daroussin return 0; 3826*61d06d6bSBaptiste Daroussin else if ('\\' == cp[pos] && '.' == cp[pos + 1]) 3827*61d06d6bSBaptiste Daroussin pos += 2; 3828*61d06d6bSBaptiste Daroussin else if ('.' == cp[pos] || '\'' == cp[pos]) 3829*61d06d6bSBaptiste Daroussin pos++; 3830*61d06d6bSBaptiste Daroussin else 3831*61d06d6bSBaptiste Daroussin return 0; 3832*61d06d6bSBaptiste Daroussin 3833*61d06d6bSBaptiste Daroussin while (' ' == cp[pos] || '\t' == cp[pos]) 3834*61d06d6bSBaptiste Daroussin pos++; 3835*61d06d6bSBaptiste Daroussin 3836*61d06d6bSBaptiste Daroussin *ppos = pos; 3837*61d06d6bSBaptiste Daroussin return 1; 3838*61d06d6bSBaptiste Daroussin } 3839