1*95c635efSGarrett D'Amore /* $Id: roff.c,v 1.172 2011/10/24 21:41:45 schwarze Exp $ */ 2*95c635efSGarrett D'Amore /* 3*95c635efSGarrett D'Amore * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4*95c635efSGarrett D'Amore * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> 5*95c635efSGarrett D'Amore * 6*95c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any 7*95c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above 8*95c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies. 9*95c635efSGarrett D'Amore * 10*95c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES 11*95c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*95c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR 13*95c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14*95c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15*95c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16*95c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*95c635efSGarrett D'Amore */ 18*95c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H 19*95c635efSGarrett D'Amore #include "config.h" 20*95c635efSGarrett D'Amore #endif 21*95c635efSGarrett D'Amore 22*95c635efSGarrett D'Amore #include <assert.h> 23*95c635efSGarrett D'Amore #include <ctype.h> 24*95c635efSGarrett D'Amore #include <stdlib.h> 25*95c635efSGarrett D'Amore #include <string.h> 26*95c635efSGarrett D'Amore 27*95c635efSGarrett D'Amore #include "mandoc.h" 28*95c635efSGarrett D'Amore #include "libroff.h" 29*95c635efSGarrett D'Amore #include "libmandoc.h" 30*95c635efSGarrett D'Amore 31*95c635efSGarrett D'Amore /* Maximum number of nested if-else conditionals. */ 32*95c635efSGarrett D'Amore #define RSTACK_MAX 128 33*95c635efSGarrett D'Amore 34*95c635efSGarrett D'Amore /* Maximum number of string expansions per line, to break infinite loops. */ 35*95c635efSGarrett D'Amore #define EXPAND_LIMIT 1000 36*95c635efSGarrett D'Amore 37*95c635efSGarrett D'Amore enum rofft { 38*95c635efSGarrett D'Amore ROFF_ad, 39*95c635efSGarrett D'Amore ROFF_am, 40*95c635efSGarrett D'Amore ROFF_ami, 41*95c635efSGarrett D'Amore ROFF_am1, 42*95c635efSGarrett D'Amore ROFF_de, 43*95c635efSGarrett D'Amore ROFF_dei, 44*95c635efSGarrett D'Amore ROFF_de1, 45*95c635efSGarrett D'Amore ROFF_ds, 46*95c635efSGarrett D'Amore ROFF_el, 47*95c635efSGarrett D'Amore ROFF_hy, 48*95c635efSGarrett D'Amore ROFF_ie, 49*95c635efSGarrett D'Amore ROFF_if, 50*95c635efSGarrett D'Amore ROFF_ig, 51*95c635efSGarrett D'Amore ROFF_it, 52*95c635efSGarrett D'Amore ROFF_ne, 53*95c635efSGarrett D'Amore ROFF_nh, 54*95c635efSGarrett D'Amore ROFF_nr, 55*95c635efSGarrett D'Amore ROFF_ns, 56*95c635efSGarrett D'Amore ROFF_ps, 57*95c635efSGarrett D'Amore ROFF_rm, 58*95c635efSGarrett D'Amore ROFF_so, 59*95c635efSGarrett D'Amore ROFF_ta, 60*95c635efSGarrett D'Amore ROFF_tr, 61*95c635efSGarrett D'Amore ROFF_TS, 62*95c635efSGarrett D'Amore ROFF_TE, 63*95c635efSGarrett D'Amore ROFF_T_, 64*95c635efSGarrett D'Amore ROFF_EQ, 65*95c635efSGarrett D'Amore ROFF_EN, 66*95c635efSGarrett D'Amore ROFF_cblock, 67*95c635efSGarrett D'Amore ROFF_ccond, 68*95c635efSGarrett D'Amore ROFF_USERDEF, 69*95c635efSGarrett D'Amore ROFF_MAX 70*95c635efSGarrett D'Amore }; 71*95c635efSGarrett D'Amore 72*95c635efSGarrett D'Amore enum roffrule { 73*95c635efSGarrett D'Amore ROFFRULE_ALLOW, 74*95c635efSGarrett D'Amore ROFFRULE_DENY 75*95c635efSGarrett D'Amore }; 76*95c635efSGarrett D'Amore 77*95c635efSGarrett D'Amore /* 78*95c635efSGarrett D'Amore * A single register entity. If "set" is zero, the value of the 79*95c635efSGarrett D'Amore * register should be the default one, which is per-register. 80*95c635efSGarrett D'Amore * Registers are assumed to be unsigned ints for now. 81*95c635efSGarrett D'Amore */ 82*95c635efSGarrett D'Amore struct reg { 83*95c635efSGarrett D'Amore int set; /* whether set or not */ 84*95c635efSGarrett D'Amore unsigned int u; /* unsigned integer */ 85*95c635efSGarrett D'Amore }; 86*95c635efSGarrett D'Amore 87*95c635efSGarrett D'Amore /* 88*95c635efSGarrett D'Amore * An incredibly-simple string buffer. 89*95c635efSGarrett D'Amore */ 90*95c635efSGarrett D'Amore struct roffstr { 91*95c635efSGarrett D'Amore char *p; /* nil-terminated buffer */ 92*95c635efSGarrett D'Amore size_t sz; /* saved strlen(p) */ 93*95c635efSGarrett D'Amore }; 94*95c635efSGarrett D'Amore 95*95c635efSGarrett D'Amore /* 96*95c635efSGarrett D'Amore * A key-value roffstr pair as part of a singly-linked list. 97*95c635efSGarrett D'Amore */ 98*95c635efSGarrett D'Amore struct roffkv { 99*95c635efSGarrett D'Amore struct roffstr key; 100*95c635efSGarrett D'Amore struct roffstr val; 101*95c635efSGarrett D'Amore struct roffkv *next; /* next in list */ 102*95c635efSGarrett D'Amore }; 103*95c635efSGarrett D'Amore 104*95c635efSGarrett D'Amore struct roff { 105*95c635efSGarrett D'Amore struct mparse *parse; /* parse point */ 106*95c635efSGarrett D'Amore struct roffnode *last; /* leaf of stack */ 107*95c635efSGarrett D'Amore enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */ 108*95c635efSGarrett D'Amore int rstackpos; /* position in rstack */ 109*95c635efSGarrett D'Amore struct reg regs[REG__MAX]; 110*95c635efSGarrett D'Amore struct roffkv *strtab; /* user-defined strings & macros */ 111*95c635efSGarrett D'Amore struct roffkv *xmbtab; /* multi-byte trans table (`tr') */ 112*95c635efSGarrett D'Amore struct roffstr *xtab; /* single-byte trans table (`tr') */ 113*95c635efSGarrett D'Amore const char *current_string; /* value of last called user macro */ 114*95c635efSGarrett D'Amore struct tbl_node *first_tbl; /* first table parsed */ 115*95c635efSGarrett D'Amore struct tbl_node *last_tbl; /* last table parsed */ 116*95c635efSGarrett D'Amore struct tbl_node *tbl; /* current table being parsed */ 117*95c635efSGarrett D'Amore struct eqn_node *last_eqn; /* last equation parsed */ 118*95c635efSGarrett D'Amore struct eqn_node *first_eqn; /* first equation parsed */ 119*95c635efSGarrett D'Amore struct eqn_node *eqn; /* current equation being parsed */ 120*95c635efSGarrett D'Amore }; 121*95c635efSGarrett D'Amore 122*95c635efSGarrett D'Amore struct roffnode { 123*95c635efSGarrett D'Amore enum rofft tok; /* type of node */ 124*95c635efSGarrett D'Amore struct roffnode *parent; /* up one in stack */ 125*95c635efSGarrett D'Amore int line; /* parse line */ 126*95c635efSGarrett D'Amore int col; /* parse col */ 127*95c635efSGarrett D'Amore char *name; /* node name, e.g. macro name */ 128*95c635efSGarrett D'Amore char *end; /* end-rules: custom token */ 129*95c635efSGarrett D'Amore int endspan; /* end-rules: next-line or infty */ 130*95c635efSGarrett D'Amore enum roffrule rule; /* current evaluation rule */ 131*95c635efSGarrett D'Amore }; 132*95c635efSGarrett D'Amore 133*95c635efSGarrett D'Amore #define ROFF_ARGS struct roff *r, /* parse ctx */ \ 134*95c635efSGarrett D'Amore enum rofft tok, /* tok of macro */ \ 135*95c635efSGarrett D'Amore char **bufp, /* input buffer */ \ 136*95c635efSGarrett D'Amore size_t *szp, /* size of input buffer */ \ 137*95c635efSGarrett D'Amore int ln, /* parse line */ \ 138*95c635efSGarrett D'Amore int ppos, /* original pos in buffer */ \ 139*95c635efSGarrett D'Amore int pos, /* current pos in buffer */ \ 140*95c635efSGarrett D'Amore int *offs /* reset offset of buffer data */ 141*95c635efSGarrett D'Amore 142*95c635efSGarrett D'Amore typedef enum rofferr (*roffproc)(ROFF_ARGS); 143*95c635efSGarrett D'Amore 144*95c635efSGarrett D'Amore struct roffmac { 145*95c635efSGarrett D'Amore const char *name; /* macro name */ 146*95c635efSGarrett D'Amore roffproc proc; /* process new macro */ 147*95c635efSGarrett D'Amore roffproc text; /* process as child text of macro */ 148*95c635efSGarrett D'Amore roffproc sub; /* process as child of macro */ 149*95c635efSGarrett D'Amore int flags; 150*95c635efSGarrett D'Amore #define ROFFMAC_STRUCT (1 << 0) /* always interpret */ 151*95c635efSGarrett D'Amore struct roffmac *next; 152*95c635efSGarrett D'Amore }; 153*95c635efSGarrett D'Amore 154*95c635efSGarrett D'Amore struct predef { 155*95c635efSGarrett D'Amore const char *name; /* predefined input name */ 156*95c635efSGarrett D'Amore const char *str; /* replacement symbol */ 157*95c635efSGarrett D'Amore }; 158*95c635efSGarrett D'Amore 159*95c635efSGarrett D'Amore #define PREDEF(__name, __str) \ 160*95c635efSGarrett D'Amore { (__name), (__str) }, 161*95c635efSGarrett D'Amore 162*95c635efSGarrett D'Amore static enum rofft roffhash_find(const char *, size_t); 163*95c635efSGarrett D'Amore static void roffhash_init(void); 164*95c635efSGarrett D'Amore static void roffnode_cleanscope(struct roff *); 165*95c635efSGarrett D'Amore static void roffnode_pop(struct roff *); 166*95c635efSGarrett D'Amore static void roffnode_push(struct roff *, enum rofft, 167*95c635efSGarrett D'Amore const char *, int, int); 168*95c635efSGarrett D'Amore static enum rofferr roff_block(ROFF_ARGS); 169*95c635efSGarrett D'Amore static enum rofferr roff_block_text(ROFF_ARGS); 170*95c635efSGarrett D'Amore static enum rofferr roff_block_sub(ROFF_ARGS); 171*95c635efSGarrett D'Amore static enum rofferr roff_cblock(ROFF_ARGS); 172*95c635efSGarrett D'Amore static enum rofferr roff_ccond(ROFF_ARGS); 173*95c635efSGarrett D'Amore static enum rofferr roff_cond(ROFF_ARGS); 174*95c635efSGarrett D'Amore static enum rofferr roff_cond_text(ROFF_ARGS); 175*95c635efSGarrett D'Amore static enum rofferr roff_cond_sub(ROFF_ARGS); 176*95c635efSGarrett D'Amore static enum rofferr roff_ds(ROFF_ARGS); 177*95c635efSGarrett D'Amore static enum roffrule roff_evalcond(const char *, int *); 178*95c635efSGarrett D'Amore static void roff_free1(struct roff *); 179*95c635efSGarrett D'Amore static void roff_freestr(struct roffkv *); 180*95c635efSGarrett D'Amore static char *roff_getname(struct roff *, char **, int, int); 181*95c635efSGarrett D'Amore static const char *roff_getstrn(const struct roff *, 182*95c635efSGarrett D'Amore const char *, size_t); 183*95c635efSGarrett D'Amore static enum rofferr roff_line_ignore(ROFF_ARGS); 184*95c635efSGarrett D'Amore static enum rofferr roff_nr(ROFF_ARGS); 185*95c635efSGarrett D'Amore static void roff_openeqn(struct roff *, const char *, 186*95c635efSGarrett D'Amore int, int, const char *); 187*95c635efSGarrett D'Amore static enum rofft roff_parse(struct roff *, const char *, int *); 188*95c635efSGarrett D'Amore static enum rofferr roff_parsetext(char *); 189*95c635efSGarrett D'Amore static enum rofferr roff_res(struct roff *, 190*95c635efSGarrett D'Amore char **, size_t *, int, int); 191*95c635efSGarrett D'Amore static enum rofferr roff_rm(ROFF_ARGS); 192*95c635efSGarrett D'Amore static void roff_setstr(struct roff *, 193*95c635efSGarrett D'Amore const char *, const char *, int); 194*95c635efSGarrett D'Amore static void roff_setstrn(struct roffkv **, const char *, 195*95c635efSGarrett D'Amore size_t, const char *, size_t, int); 196*95c635efSGarrett D'Amore static enum rofferr roff_so(ROFF_ARGS); 197*95c635efSGarrett D'Amore static enum rofferr roff_tr(ROFF_ARGS); 198*95c635efSGarrett D'Amore static enum rofferr roff_TE(ROFF_ARGS); 199*95c635efSGarrett D'Amore static enum rofferr roff_TS(ROFF_ARGS); 200*95c635efSGarrett D'Amore static enum rofferr roff_EQ(ROFF_ARGS); 201*95c635efSGarrett D'Amore static enum rofferr roff_EN(ROFF_ARGS); 202*95c635efSGarrett D'Amore static enum rofferr roff_T_(ROFF_ARGS); 203*95c635efSGarrett D'Amore static enum rofferr roff_userdef(ROFF_ARGS); 204*95c635efSGarrett D'Amore 205*95c635efSGarrett D'Amore /* See roffhash_find() */ 206*95c635efSGarrett D'Amore 207*95c635efSGarrett D'Amore #define ASCII_HI 126 208*95c635efSGarrett D'Amore #define ASCII_LO 33 209*95c635efSGarrett D'Amore #define HASHWIDTH (ASCII_HI - ASCII_LO + 1) 210*95c635efSGarrett D'Amore 211*95c635efSGarrett D'Amore static struct roffmac *hash[HASHWIDTH]; 212*95c635efSGarrett D'Amore 213*95c635efSGarrett D'Amore static struct roffmac roffs[ROFF_MAX] = { 214*95c635efSGarrett D'Amore { "ad", roff_line_ignore, NULL, NULL, 0, NULL }, 215*95c635efSGarrett D'Amore { "am", roff_block, roff_block_text, roff_block_sub, 0, NULL }, 216*95c635efSGarrett D'Amore { "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL }, 217*95c635efSGarrett D'Amore { "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL }, 218*95c635efSGarrett D'Amore { "de", roff_block, roff_block_text, roff_block_sub, 0, NULL }, 219*95c635efSGarrett D'Amore { "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL }, 220*95c635efSGarrett D'Amore { "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL }, 221*95c635efSGarrett D'Amore { "ds", roff_ds, NULL, NULL, 0, NULL }, 222*95c635efSGarrett D'Amore { "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, 223*95c635efSGarrett D'Amore { "hy", roff_line_ignore, NULL, NULL, 0, NULL }, 224*95c635efSGarrett D'Amore { "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, 225*95c635efSGarrett D'Amore { "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, 226*95c635efSGarrett D'Amore { "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL }, 227*95c635efSGarrett D'Amore { "it", roff_line_ignore, NULL, NULL, 0, NULL }, 228*95c635efSGarrett D'Amore { "ne", roff_line_ignore, NULL, NULL, 0, NULL }, 229*95c635efSGarrett D'Amore { "nh", roff_line_ignore, NULL, NULL, 0, NULL }, 230*95c635efSGarrett D'Amore { "nr", roff_nr, NULL, NULL, 0, NULL }, 231*95c635efSGarrett D'Amore { "ns", roff_line_ignore, NULL, NULL, 0, NULL }, 232*95c635efSGarrett D'Amore { "ps", roff_line_ignore, NULL, NULL, 0, NULL }, 233*95c635efSGarrett D'Amore { "rm", roff_rm, NULL, NULL, 0, NULL }, 234*95c635efSGarrett D'Amore { "so", roff_so, NULL, NULL, 0, NULL }, 235*95c635efSGarrett D'Amore { "ta", roff_line_ignore, NULL, NULL, 0, NULL }, 236*95c635efSGarrett D'Amore { "tr", roff_tr, NULL, NULL, 0, NULL }, 237*95c635efSGarrett D'Amore { "TS", roff_TS, NULL, NULL, 0, NULL }, 238*95c635efSGarrett D'Amore { "TE", roff_TE, NULL, NULL, 0, NULL }, 239*95c635efSGarrett D'Amore { "T&", roff_T_, NULL, NULL, 0, NULL }, 240*95c635efSGarrett D'Amore { "EQ", roff_EQ, NULL, NULL, 0, NULL }, 241*95c635efSGarrett D'Amore { "EN", roff_EN, NULL, NULL, 0, NULL }, 242*95c635efSGarrett D'Amore { ".", roff_cblock, NULL, NULL, 0, NULL }, 243*95c635efSGarrett D'Amore { "\\}", roff_ccond, NULL, NULL, 0, NULL }, 244*95c635efSGarrett D'Amore { NULL, roff_userdef, NULL, NULL, 0, NULL }, 245*95c635efSGarrett D'Amore }; 246*95c635efSGarrett D'Amore 247*95c635efSGarrett D'Amore /* Array of injected predefined strings. */ 248*95c635efSGarrett D'Amore #define PREDEFS_MAX 38 249*95c635efSGarrett D'Amore static const struct predef predefs[PREDEFS_MAX] = { 250*95c635efSGarrett D'Amore #include "predefs.in" 251*95c635efSGarrett D'Amore }; 252*95c635efSGarrett D'Amore 253*95c635efSGarrett D'Amore /* See roffhash_find() */ 254*95c635efSGarrett D'Amore #define ROFF_HASH(p) (p[0] - ASCII_LO) 255*95c635efSGarrett D'Amore 256*95c635efSGarrett D'Amore static void 257*95c635efSGarrett D'Amore roffhash_init(void) 258*95c635efSGarrett D'Amore { 259*95c635efSGarrett D'Amore struct roffmac *n; 260*95c635efSGarrett D'Amore int buc, i; 261*95c635efSGarrett D'Amore 262*95c635efSGarrett D'Amore for (i = 0; i < (int)ROFF_USERDEF; i++) { 263*95c635efSGarrett D'Amore assert(roffs[i].name[0] >= ASCII_LO); 264*95c635efSGarrett D'Amore assert(roffs[i].name[0] <= ASCII_HI); 265*95c635efSGarrett D'Amore 266*95c635efSGarrett D'Amore buc = ROFF_HASH(roffs[i].name); 267*95c635efSGarrett D'Amore 268*95c635efSGarrett D'Amore if (NULL != (n = hash[buc])) { 269*95c635efSGarrett D'Amore for ( ; n->next; n = n->next) 270*95c635efSGarrett D'Amore /* Do nothing. */ ; 271*95c635efSGarrett D'Amore n->next = &roffs[i]; 272*95c635efSGarrett D'Amore } else 273*95c635efSGarrett D'Amore hash[buc] = &roffs[i]; 274*95c635efSGarrett D'Amore } 275*95c635efSGarrett D'Amore } 276*95c635efSGarrett D'Amore 277*95c635efSGarrett D'Amore /* 278*95c635efSGarrett D'Amore * Look up a roff token by its name. Returns ROFF_MAX if no macro by 279*95c635efSGarrett D'Amore * the nil-terminated string name could be found. 280*95c635efSGarrett D'Amore */ 281*95c635efSGarrett D'Amore static enum rofft 282*95c635efSGarrett D'Amore roffhash_find(const char *p, size_t s) 283*95c635efSGarrett D'Amore { 284*95c635efSGarrett D'Amore int buc; 285*95c635efSGarrett D'Amore struct roffmac *n; 286*95c635efSGarrett D'Amore 287*95c635efSGarrett D'Amore /* 288*95c635efSGarrett D'Amore * libroff has an extremely simple hashtable, for the time 289*95c635efSGarrett D'Amore * being, which simply keys on the first character, which must 290*95c635efSGarrett D'Amore * be printable, then walks a chain. It works well enough until 291*95c635efSGarrett D'Amore * optimised. 292*95c635efSGarrett D'Amore */ 293*95c635efSGarrett D'Amore 294*95c635efSGarrett D'Amore if (p[0] < ASCII_LO || p[0] > ASCII_HI) 295*95c635efSGarrett D'Amore return(ROFF_MAX); 296*95c635efSGarrett D'Amore 297*95c635efSGarrett D'Amore buc = ROFF_HASH(p); 298*95c635efSGarrett D'Amore 299*95c635efSGarrett D'Amore if (NULL == (n = hash[buc])) 300*95c635efSGarrett D'Amore return(ROFF_MAX); 301*95c635efSGarrett D'Amore for ( ; n; n = n->next) 302*95c635efSGarrett D'Amore if (0 == strncmp(n->name, p, s) && '\0' == n->name[(int)s]) 303*95c635efSGarrett D'Amore return((enum rofft)(n - roffs)); 304*95c635efSGarrett D'Amore 305*95c635efSGarrett D'Amore return(ROFF_MAX); 306*95c635efSGarrett D'Amore } 307*95c635efSGarrett D'Amore 308*95c635efSGarrett D'Amore 309*95c635efSGarrett D'Amore /* 310*95c635efSGarrett D'Amore * Pop the current node off of the stack of roff instructions currently 311*95c635efSGarrett D'Amore * pending. 312*95c635efSGarrett D'Amore */ 313*95c635efSGarrett D'Amore static void 314*95c635efSGarrett D'Amore roffnode_pop(struct roff *r) 315*95c635efSGarrett D'Amore { 316*95c635efSGarrett D'Amore struct roffnode *p; 317*95c635efSGarrett D'Amore 318*95c635efSGarrett D'Amore assert(r->last); 319*95c635efSGarrett D'Amore p = r->last; 320*95c635efSGarrett D'Amore 321*95c635efSGarrett D'Amore r->last = r->last->parent; 322*95c635efSGarrett D'Amore free(p->name); 323*95c635efSGarrett D'Amore free(p->end); 324*95c635efSGarrett D'Amore free(p); 325*95c635efSGarrett D'Amore } 326*95c635efSGarrett D'Amore 327*95c635efSGarrett D'Amore 328*95c635efSGarrett D'Amore /* 329*95c635efSGarrett D'Amore * Push a roff node onto the instruction stack. This must later be 330*95c635efSGarrett D'Amore * removed with roffnode_pop(). 331*95c635efSGarrett D'Amore */ 332*95c635efSGarrett D'Amore static void 333*95c635efSGarrett D'Amore roffnode_push(struct roff *r, enum rofft tok, const char *name, 334*95c635efSGarrett D'Amore int line, int col) 335*95c635efSGarrett D'Amore { 336*95c635efSGarrett D'Amore struct roffnode *p; 337*95c635efSGarrett D'Amore 338*95c635efSGarrett D'Amore p = mandoc_calloc(1, sizeof(struct roffnode)); 339*95c635efSGarrett D'Amore p->tok = tok; 340*95c635efSGarrett D'Amore if (name) 341*95c635efSGarrett D'Amore p->name = mandoc_strdup(name); 342*95c635efSGarrett D'Amore p->parent = r->last; 343*95c635efSGarrett D'Amore p->line = line; 344*95c635efSGarrett D'Amore p->col = col; 345*95c635efSGarrett D'Amore p->rule = p->parent ? p->parent->rule : ROFFRULE_DENY; 346*95c635efSGarrett D'Amore 347*95c635efSGarrett D'Amore r->last = p; 348*95c635efSGarrett D'Amore } 349*95c635efSGarrett D'Amore 350*95c635efSGarrett D'Amore 351*95c635efSGarrett D'Amore static void 352*95c635efSGarrett D'Amore roff_free1(struct roff *r) 353*95c635efSGarrett D'Amore { 354*95c635efSGarrett D'Amore struct tbl_node *t; 355*95c635efSGarrett D'Amore struct eqn_node *e; 356*95c635efSGarrett D'Amore int i; 357*95c635efSGarrett D'Amore 358*95c635efSGarrett D'Amore while (NULL != (t = r->first_tbl)) { 359*95c635efSGarrett D'Amore r->first_tbl = t->next; 360*95c635efSGarrett D'Amore tbl_free(t); 361*95c635efSGarrett D'Amore } 362*95c635efSGarrett D'Amore 363*95c635efSGarrett D'Amore r->first_tbl = r->last_tbl = r->tbl = NULL; 364*95c635efSGarrett D'Amore 365*95c635efSGarrett D'Amore while (NULL != (e = r->first_eqn)) { 366*95c635efSGarrett D'Amore r->first_eqn = e->next; 367*95c635efSGarrett D'Amore eqn_free(e); 368*95c635efSGarrett D'Amore } 369*95c635efSGarrett D'Amore 370*95c635efSGarrett D'Amore r->first_eqn = r->last_eqn = r->eqn = NULL; 371*95c635efSGarrett D'Amore 372*95c635efSGarrett D'Amore while (r->last) 373*95c635efSGarrett D'Amore roffnode_pop(r); 374*95c635efSGarrett D'Amore 375*95c635efSGarrett D'Amore roff_freestr(r->strtab); 376*95c635efSGarrett D'Amore roff_freestr(r->xmbtab); 377*95c635efSGarrett D'Amore 378*95c635efSGarrett D'Amore r->strtab = r->xmbtab = NULL; 379*95c635efSGarrett D'Amore 380*95c635efSGarrett D'Amore if (r->xtab) 381*95c635efSGarrett D'Amore for (i = 0; i < 128; i++) 382*95c635efSGarrett D'Amore free(r->xtab[i].p); 383*95c635efSGarrett D'Amore 384*95c635efSGarrett D'Amore free(r->xtab); 385*95c635efSGarrett D'Amore r->xtab = NULL; 386*95c635efSGarrett D'Amore } 387*95c635efSGarrett D'Amore 388*95c635efSGarrett D'Amore void 389*95c635efSGarrett D'Amore roff_reset(struct roff *r) 390*95c635efSGarrett D'Amore { 391*95c635efSGarrett D'Amore int i; 392*95c635efSGarrett D'Amore 393*95c635efSGarrett D'Amore roff_free1(r); 394*95c635efSGarrett D'Amore 395*95c635efSGarrett D'Amore memset(&r->regs, 0, sizeof(struct reg) * REG__MAX); 396*95c635efSGarrett D'Amore 397*95c635efSGarrett D'Amore for (i = 0; i < PREDEFS_MAX; i++) 398*95c635efSGarrett D'Amore roff_setstr(r, predefs[i].name, predefs[i].str, 0); 399*95c635efSGarrett D'Amore } 400*95c635efSGarrett D'Amore 401*95c635efSGarrett D'Amore 402*95c635efSGarrett D'Amore void 403*95c635efSGarrett D'Amore roff_free(struct roff *r) 404*95c635efSGarrett D'Amore { 405*95c635efSGarrett D'Amore 406*95c635efSGarrett D'Amore roff_free1(r); 407*95c635efSGarrett D'Amore free(r); 408*95c635efSGarrett D'Amore } 409*95c635efSGarrett D'Amore 410*95c635efSGarrett D'Amore 411*95c635efSGarrett D'Amore struct roff * 412*95c635efSGarrett D'Amore roff_alloc(struct mparse *parse) 413*95c635efSGarrett D'Amore { 414*95c635efSGarrett D'Amore struct roff *r; 415*95c635efSGarrett D'Amore int i; 416*95c635efSGarrett D'Amore 417*95c635efSGarrett D'Amore r = mandoc_calloc(1, sizeof(struct roff)); 418*95c635efSGarrett D'Amore r->parse = parse; 419*95c635efSGarrett D'Amore r->rstackpos = -1; 420*95c635efSGarrett D'Amore 421*95c635efSGarrett D'Amore roffhash_init(); 422*95c635efSGarrett D'Amore 423*95c635efSGarrett D'Amore for (i = 0; i < PREDEFS_MAX; i++) 424*95c635efSGarrett D'Amore roff_setstr(r, predefs[i].name, predefs[i].str, 0); 425*95c635efSGarrett D'Amore 426*95c635efSGarrett D'Amore return(r); 427*95c635efSGarrett D'Amore } 428*95c635efSGarrett D'Amore 429*95c635efSGarrett D'Amore /* 430*95c635efSGarrett D'Amore * Pre-filter each and every line for reserved words (one beginning with 431*95c635efSGarrett D'Amore * `\*', e.g., `\*(ab'). These must be handled before the actual line 432*95c635efSGarrett D'Amore * is processed. 433*95c635efSGarrett D'Amore * This also checks the syntax of regular escapes. 434*95c635efSGarrett D'Amore */ 435*95c635efSGarrett D'Amore static enum rofferr 436*95c635efSGarrett D'Amore roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos) 437*95c635efSGarrett D'Amore { 438*95c635efSGarrett D'Amore enum mandoc_esc esc; 439*95c635efSGarrett D'Amore const char *stesc; /* start of an escape sequence ('\\') */ 440*95c635efSGarrett D'Amore const char *stnam; /* start of the name, after "[(*" */ 441*95c635efSGarrett D'Amore const char *cp; /* end of the name, e.g. before ']' */ 442*95c635efSGarrett D'Amore const char *res; /* the string to be substituted */ 443*95c635efSGarrett D'Amore int i, maxl, expand_count; 444*95c635efSGarrett D'Amore size_t nsz; 445*95c635efSGarrett D'Amore char *n; 446*95c635efSGarrett D'Amore 447*95c635efSGarrett D'Amore expand_count = 0; 448*95c635efSGarrett D'Amore 449*95c635efSGarrett D'Amore again: 450*95c635efSGarrett D'Amore cp = *bufp + pos; 451*95c635efSGarrett D'Amore while (NULL != (cp = strchr(cp, '\\'))) { 452*95c635efSGarrett D'Amore stesc = cp++; 453*95c635efSGarrett D'Amore 454*95c635efSGarrett D'Amore /* 455*95c635efSGarrett D'Amore * The second character must be an asterisk. 456*95c635efSGarrett D'Amore * If it isn't, skip it anyway: It is escaped, 457*95c635efSGarrett D'Amore * so it can't start another escape sequence. 458*95c635efSGarrett D'Amore */ 459*95c635efSGarrett D'Amore 460*95c635efSGarrett D'Amore if ('\0' == *cp) 461*95c635efSGarrett D'Amore return(ROFF_CONT); 462*95c635efSGarrett D'Amore 463*95c635efSGarrett D'Amore if ('*' != *cp) { 464*95c635efSGarrett D'Amore res = cp; 465*95c635efSGarrett D'Amore esc = mandoc_escape(&cp, NULL, NULL); 466*95c635efSGarrett D'Amore if (ESCAPE_ERROR != esc) 467*95c635efSGarrett D'Amore continue; 468*95c635efSGarrett D'Amore cp = res; 469*95c635efSGarrett D'Amore mandoc_msg 470*95c635efSGarrett D'Amore (MANDOCERR_BADESCAPE, r->parse, 471*95c635efSGarrett D'Amore ln, (int)(stesc - *bufp), NULL); 472*95c635efSGarrett D'Amore return(ROFF_CONT); 473*95c635efSGarrett D'Amore } 474*95c635efSGarrett D'Amore 475*95c635efSGarrett D'Amore cp++; 476*95c635efSGarrett D'Amore 477*95c635efSGarrett D'Amore /* 478*95c635efSGarrett D'Amore * The third character decides the length 479*95c635efSGarrett D'Amore * of the name of the string. 480*95c635efSGarrett D'Amore * Save a pointer to the name. 481*95c635efSGarrett D'Amore */ 482*95c635efSGarrett D'Amore 483*95c635efSGarrett D'Amore switch (*cp) { 484*95c635efSGarrett D'Amore case ('\0'): 485*95c635efSGarrett D'Amore return(ROFF_CONT); 486*95c635efSGarrett D'Amore case ('('): 487*95c635efSGarrett D'Amore cp++; 488*95c635efSGarrett D'Amore maxl = 2; 489*95c635efSGarrett D'Amore break; 490*95c635efSGarrett D'Amore case ('['): 491*95c635efSGarrett D'Amore cp++; 492*95c635efSGarrett D'Amore maxl = 0; 493*95c635efSGarrett D'Amore break; 494*95c635efSGarrett D'Amore default: 495*95c635efSGarrett D'Amore maxl = 1; 496*95c635efSGarrett D'Amore break; 497*95c635efSGarrett D'Amore } 498*95c635efSGarrett D'Amore stnam = cp; 499*95c635efSGarrett D'Amore 500*95c635efSGarrett D'Amore /* Advance to the end of the name. */ 501*95c635efSGarrett D'Amore 502*95c635efSGarrett D'Amore for (i = 0; 0 == maxl || i < maxl; i++, cp++) { 503*95c635efSGarrett D'Amore if ('\0' == *cp) { 504*95c635efSGarrett D'Amore mandoc_msg 505*95c635efSGarrett D'Amore (MANDOCERR_BADESCAPE, 506*95c635efSGarrett D'Amore r->parse, ln, 507*95c635efSGarrett D'Amore (int)(stesc - *bufp), NULL); 508*95c635efSGarrett D'Amore return(ROFF_CONT); 509*95c635efSGarrett D'Amore } 510*95c635efSGarrett D'Amore if (0 == maxl && ']' == *cp) 511*95c635efSGarrett D'Amore break; 512*95c635efSGarrett D'Amore } 513*95c635efSGarrett D'Amore 514*95c635efSGarrett D'Amore /* 515*95c635efSGarrett D'Amore * Retrieve the replacement string; if it is 516*95c635efSGarrett D'Amore * undefined, resume searching for escapes. 517*95c635efSGarrett D'Amore */ 518*95c635efSGarrett D'Amore 519*95c635efSGarrett D'Amore res = roff_getstrn(r, stnam, (size_t)i); 520*95c635efSGarrett D'Amore 521*95c635efSGarrett D'Amore if (NULL == res) { 522*95c635efSGarrett D'Amore mandoc_msg 523*95c635efSGarrett D'Amore (MANDOCERR_BADESCAPE, r->parse, 524*95c635efSGarrett D'Amore ln, (int)(stesc - *bufp), NULL); 525*95c635efSGarrett D'Amore res = ""; 526*95c635efSGarrett D'Amore } 527*95c635efSGarrett D'Amore 528*95c635efSGarrett D'Amore /* Replace the escape sequence by the string. */ 529*95c635efSGarrett D'Amore 530*95c635efSGarrett D'Amore pos = stesc - *bufp; 531*95c635efSGarrett D'Amore 532*95c635efSGarrett D'Amore nsz = *szp + strlen(res) + 1; 533*95c635efSGarrett D'Amore n = mandoc_malloc(nsz); 534*95c635efSGarrett D'Amore 535*95c635efSGarrett D'Amore strlcpy(n, *bufp, (size_t)(stesc - *bufp + 1)); 536*95c635efSGarrett D'Amore strlcat(n, res, nsz); 537*95c635efSGarrett D'Amore strlcat(n, cp + (maxl ? 0 : 1), nsz); 538*95c635efSGarrett D'Amore 539*95c635efSGarrett D'Amore free(*bufp); 540*95c635efSGarrett D'Amore 541*95c635efSGarrett D'Amore *bufp = n; 542*95c635efSGarrett D'Amore *szp = nsz; 543*95c635efSGarrett D'Amore 544*95c635efSGarrett D'Amore if (EXPAND_LIMIT >= ++expand_count) 545*95c635efSGarrett D'Amore goto again; 546*95c635efSGarrett D'Amore 547*95c635efSGarrett D'Amore /* Just leave the string unexpanded. */ 548*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, ln, pos, NULL); 549*95c635efSGarrett D'Amore return(ROFF_IGN); 550*95c635efSGarrett D'Amore } 551*95c635efSGarrett D'Amore return(ROFF_CONT); 552*95c635efSGarrett D'Amore } 553*95c635efSGarrett D'Amore 554*95c635efSGarrett D'Amore /* 555*95c635efSGarrett D'Amore * Process text streams: convert all breakable hyphens into ASCII_HYPH. 556*95c635efSGarrett D'Amore */ 557*95c635efSGarrett D'Amore static enum rofferr 558*95c635efSGarrett D'Amore roff_parsetext(char *p) 559*95c635efSGarrett D'Amore { 560*95c635efSGarrett D'Amore size_t sz; 561*95c635efSGarrett D'Amore const char *start; 562*95c635efSGarrett D'Amore enum mandoc_esc esc; 563*95c635efSGarrett D'Amore 564*95c635efSGarrett D'Amore start = p; 565*95c635efSGarrett D'Amore 566*95c635efSGarrett D'Amore while ('\0' != *p) { 567*95c635efSGarrett D'Amore sz = strcspn(p, "-\\"); 568*95c635efSGarrett D'Amore p += sz; 569*95c635efSGarrett D'Amore 570*95c635efSGarrett D'Amore if ('\0' == *p) 571*95c635efSGarrett D'Amore break; 572*95c635efSGarrett D'Amore 573*95c635efSGarrett D'Amore if ('\\' == *p) { 574*95c635efSGarrett D'Amore /* Skip over escapes. */ 575*95c635efSGarrett D'Amore p++; 576*95c635efSGarrett D'Amore esc = mandoc_escape 577*95c635efSGarrett D'Amore ((const char **)&p, NULL, NULL); 578*95c635efSGarrett D'Amore if (ESCAPE_ERROR == esc) 579*95c635efSGarrett D'Amore break; 580*95c635efSGarrett D'Amore continue; 581*95c635efSGarrett D'Amore } else if (p == start) { 582*95c635efSGarrett D'Amore p++; 583*95c635efSGarrett D'Amore continue; 584*95c635efSGarrett D'Amore } 585*95c635efSGarrett D'Amore 586*95c635efSGarrett D'Amore if (isalpha((unsigned char)p[-1]) && 587*95c635efSGarrett D'Amore isalpha((unsigned char)p[1])) 588*95c635efSGarrett D'Amore *p = ASCII_HYPH; 589*95c635efSGarrett D'Amore p++; 590*95c635efSGarrett D'Amore } 591*95c635efSGarrett D'Amore 592*95c635efSGarrett D'Amore return(ROFF_CONT); 593*95c635efSGarrett D'Amore } 594*95c635efSGarrett D'Amore 595*95c635efSGarrett D'Amore enum rofferr 596*95c635efSGarrett D'Amore roff_parseln(struct roff *r, int ln, char **bufp, 597*95c635efSGarrett D'Amore size_t *szp, int pos, int *offs) 598*95c635efSGarrett D'Amore { 599*95c635efSGarrett D'Amore enum rofft t; 600*95c635efSGarrett D'Amore enum rofferr e; 601*95c635efSGarrett D'Amore int ppos, ctl; 602*95c635efSGarrett D'Amore 603*95c635efSGarrett D'Amore /* 604*95c635efSGarrett D'Amore * Run the reserved-word filter only if we have some reserved 605*95c635efSGarrett D'Amore * words to fill in. 606*95c635efSGarrett D'Amore */ 607*95c635efSGarrett D'Amore 608*95c635efSGarrett D'Amore e = roff_res(r, bufp, szp, ln, pos); 609*95c635efSGarrett D'Amore if (ROFF_IGN == e) 610*95c635efSGarrett D'Amore return(e); 611*95c635efSGarrett D'Amore assert(ROFF_CONT == e); 612*95c635efSGarrett D'Amore 613*95c635efSGarrett D'Amore ppos = pos; 614*95c635efSGarrett D'Amore ctl = mandoc_getcontrol(*bufp, &pos); 615*95c635efSGarrett D'Amore 616*95c635efSGarrett D'Amore /* 617*95c635efSGarrett D'Amore * First, if a scope is open and we're not a macro, pass the 618*95c635efSGarrett D'Amore * text through the macro's filter. If a scope isn't open and 619*95c635efSGarrett D'Amore * we're not a macro, just let it through. 620*95c635efSGarrett D'Amore * Finally, if there's an equation scope open, divert it into it 621*95c635efSGarrett D'Amore * no matter our state. 622*95c635efSGarrett D'Amore */ 623*95c635efSGarrett D'Amore 624*95c635efSGarrett D'Amore if (r->last && ! ctl) { 625*95c635efSGarrett D'Amore t = r->last->tok; 626*95c635efSGarrett D'Amore assert(roffs[t].text); 627*95c635efSGarrett D'Amore e = (*roffs[t].text) 628*95c635efSGarrett D'Amore (r, t, bufp, szp, ln, pos, pos, offs); 629*95c635efSGarrett D'Amore assert(ROFF_IGN == e || ROFF_CONT == e); 630*95c635efSGarrett D'Amore if (ROFF_CONT != e) 631*95c635efSGarrett D'Amore return(e); 632*95c635efSGarrett D'Amore if (r->eqn) 633*95c635efSGarrett D'Amore return(eqn_read(&r->eqn, ln, *bufp, pos, offs)); 634*95c635efSGarrett D'Amore if (r->tbl) 635*95c635efSGarrett D'Amore return(tbl_read(r->tbl, ln, *bufp, pos)); 636*95c635efSGarrett D'Amore return(roff_parsetext(*bufp + pos)); 637*95c635efSGarrett D'Amore } else if ( ! ctl) { 638*95c635efSGarrett D'Amore if (r->eqn) 639*95c635efSGarrett D'Amore return(eqn_read(&r->eqn, ln, *bufp, pos, offs)); 640*95c635efSGarrett D'Amore if (r->tbl) 641*95c635efSGarrett D'Amore return(tbl_read(r->tbl, ln, *bufp, pos)); 642*95c635efSGarrett D'Amore return(roff_parsetext(*bufp + pos)); 643*95c635efSGarrett D'Amore } else if (r->eqn) 644*95c635efSGarrett D'Amore return(eqn_read(&r->eqn, ln, *bufp, ppos, offs)); 645*95c635efSGarrett D'Amore 646*95c635efSGarrett D'Amore /* 647*95c635efSGarrett D'Amore * If a scope is open, go to the child handler for that macro, 648*95c635efSGarrett D'Amore * as it may want to preprocess before doing anything with it. 649*95c635efSGarrett D'Amore * Don't do so if an equation is open. 650*95c635efSGarrett D'Amore */ 651*95c635efSGarrett D'Amore 652*95c635efSGarrett D'Amore if (r->last) { 653*95c635efSGarrett D'Amore t = r->last->tok; 654*95c635efSGarrett D'Amore assert(roffs[t].sub); 655*95c635efSGarrett D'Amore return((*roffs[t].sub) 656*95c635efSGarrett D'Amore (r, t, bufp, szp, 657*95c635efSGarrett D'Amore ln, ppos, pos, offs)); 658*95c635efSGarrett D'Amore } 659*95c635efSGarrett D'Amore 660*95c635efSGarrett D'Amore /* 661*95c635efSGarrett D'Amore * Lastly, as we've no scope open, try to look up and execute 662*95c635efSGarrett D'Amore * the new macro. If no macro is found, simply return and let 663*95c635efSGarrett D'Amore * the compilers handle it. 664*95c635efSGarrett D'Amore */ 665*95c635efSGarrett D'Amore 666*95c635efSGarrett D'Amore if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos))) 667*95c635efSGarrett D'Amore return(ROFF_CONT); 668*95c635efSGarrett D'Amore 669*95c635efSGarrett D'Amore assert(roffs[t].proc); 670*95c635efSGarrett D'Amore return((*roffs[t].proc) 671*95c635efSGarrett D'Amore (r, t, bufp, szp, 672*95c635efSGarrett D'Amore ln, ppos, pos, offs)); 673*95c635efSGarrett D'Amore } 674*95c635efSGarrett D'Amore 675*95c635efSGarrett D'Amore 676*95c635efSGarrett D'Amore void 677*95c635efSGarrett D'Amore roff_endparse(struct roff *r) 678*95c635efSGarrett D'Amore { 679*95c635efSGarrett D'Amore 680*95c635efSGarrett D'Amore if (r->last) 681*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse, 682*95c635efSGarrett D'Amore r->last->line, r->last->col, NULL); 683*95c635efSGarrett D'Amore 684*95c635efSGarrett D'Amore if (r->eqn) { 685*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse, 686*95c635efSGarrett D'Amore r->eqn->eqn.ln, r->eqn->eqn.pos, NULL); 687*95c635efSGarrett D'Amore eqn_end(&r->eqn); 688*95c635efSGarrett D'Amore } 689*95c635efSGarrett D'Amore 690*95c635efSGarrett D'Amore if (r->tbl) { 691*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse, 692*95c635efSGarrett D'Amore r->tbl->line, r->tbl->pos, NULL); 693*95c635efSGarrett D'Amore tbl_end(&r->tbl); 694*95c635efSGarrett D'Amore } 695*95c635efSGarrett D'Amore } 696*95c635efSGarrett D'Amore 697*95c635efSGarrett D'Amore /* 698*95c635efSGarrett D'Amore * Parse a roff node's type from the input buffer. This must be in the 699*95c635efSGarrett D'Amore * form of ".foo xxx" in the usual way. 700*95c635efSGarrett D'Amore */ 701*95c635efSGarrett D'Amore static enum rofft 702*95c635efSGarrett D'Amore roff_parse(struct roff *r, const char *buf, int *pos) 703*95c635efSGarrett D'Amore { 704*95c635efSGarrett D'Amore const char *mac; 705*95c635efSGarrett D'Amore size_t maclen; 706*95c635efSGarrett D'Amore enum rofft t; 707*95c635efSGarrett D'Amore 708*95c635efSGarrett D'Amore if ('\0' == buf[*pos] || '"' == buf[*pos] || 709*95c635efSGarrett D'Amore '\t' == buf[*pos] || ' ' == buf[*pos]) 710*95c635efSGarrett D'Amore return(ROFF_MAX); 711*95c635efSGarrett D'Amore 712*95c635efSGarrett D'Amore /* 713*95c635efSGarrett D'Amore * We stop the macro parse at an escape, tab, space, or nil. 714*95c635efSGarrett D'Amore * However, `\}' is also a valid macro, so make sure we don't 715*95c635efSGarrett D'Amore * clobber it by seeing the `\' as the end of token. 716*95c635efSGarrett D'Amore */ 717*95c635efSGarrett D'Amore 718*95c635efSGarrett D'Amore mac = buf + *pos; 719*95c635efSGarrett D'Amore maclen = strcspn(mac + 1, " \\\t\0") + 1; 720*95c635efSGarrett D'Amore 721*95c635efSGarrett D'Amore t = (r->current_string = roff_getstrn(r, mac, maclen)) 722*95c635efSGarrett D'Amore ? ROFF_USERDEF : roffhash_find(mac, maclen); 723*95c635efSGarrett D'Amore 724*95c635efSGarrett D'Amore *pos += (int)maclen; 725*95c635efSGarrett D'Amore 726*95c635efSGarrett D'Amore while (buf[*pos] && ' ' == buf[*pos]) 727*95c635efSGarrett D'Amore (*pos)++; 728*95c635efSGarrett D'Amore 729*95c635efSGarrett D'Amore return(t); 730*95c635efSGarrett D'Amore } 731*95c635efSGarrett D'Amore 732*95c635efSGarrett D'Amore /* ARGSUSED */ 733*95c635efSGarrett D'Amore static enum rofferr 734*95c635efSGarrett D'Amore roff_cblock(ROFF_ARGS) 735*95c635efSGarrett D'Amore { 736*95c635efSGarrett D'Amore 737*95c635efSGarrett D'Amore /* 738*95c635efSGarrett D'Amore * A block-close `..' should only be invoked as a child of an 739*95c635efSGarrett D'Amore * ignore macro, otherwise raise a warning and just ignore it. 740*95c635efSGarrett D'Amore */ 741*95c635efSGarrett D'Amore 742*95c635efSGarrett D'Amore if (NULL == r->last) { 743*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); 744*95c635efSGarrett D'Amore return(ROFF_IGN); 745*95c635efSGarrett D'Amore } 746*95c635efSGarrett D'Amore 747*95c635efSGarrett D'Amore switch (r->last->tok) { 748*95c635efSGarrett D'Amore case (ROFF_am): 749*95c635efSGarrett D'Amore /* FALLTHROUGH */ 750*95c635efSGarrett D'Amore case (ROFF_ami): 751*95c635efSGarrett D'Amore /* FALLTHROUGH */ 752*95c635efSGarrett D'Amore case (ROFF_am1): 753*95c635efSGarrett D'Amore /* FALLTHROUGH */ 754*95c635efSGarrett D'Amore case (ROFF_de): 755*95c635efSGarrett D'Amore /* ROFF_de1 is remapped to ROFF_de in roff_block(). */ 756*95c635efSGarrett D'Amore /* FALLTHROUGH */ 757*95c635efSGarrett D'Amore case (ROFF_dei): 758*95c635efSGarrett D'Amore /* FALLTHROUGH */ 759*95c635efSGarrett D'Amore case (ROFF_ig): 760*95c635efSGarrett D'Amore break; 761*95c635efSGarrett D'Amore default: 762*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); 763*95c635efSGarrett D'Amore return(ROFF_IGN); 764*95c635efSGarrett D'Amore } 765*95c635efSGarrett D'Amore 766*95c635efSGarrett D'Amore if ((*bufp)[pos]) 767*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL); 768*95c635efSGarrett D'Amore 769*95c635efSGarrett D'Amore roffnode_pop(r); 770*95c635efSGarrett D'Amore roffnode_cleanscope(r); 771*95c635efSGarrett D'Amore return(ROFF_IGN); 772*95c635efSGarrett D'Amore 773*95c635efSGarrett D'Amore } 774*95c635efSGarrett D'Amore 775*95c635efSGarrett D'Amore 776*95c635efSGarrett D'Amore static void 777*95c635efSGarrett D'Amore roffnode_cleanscope(struct roff *r) 778*95c635efSGarrett D'Amore { 779*95c635efSGarrett D'Amore 780*95c635efSGarrett D'Amore while (r->last) { 781*95c635efSGarrett D'Amore if (--r->last->endspan < 0) 782*95c635efSGarrett D'Amore break; 783*95c635efSGarrett D'Amore roffnode_pop(r); 784*95c635efSGarrett D'Amore } 785*95c635efSGarrett D'Amore } 786*95c635efSGarrett D'Amore 787*95c635efSGarrett D'Amore 788*95c635efSGarrett D'Amore /* ARGSUSED */ 789*95c635efSGarrett D'Amore static enum rofferr 790*95c635efSGarrett D'Amore roff_ccond(ROFF_ARGS) 791*95c635efSGarrett D'Amore { 792*95c635efSGarrett D'Amore 793*95c635efSGarrett D'Amore if (NULL == r->last) { 794*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); 795*95c635efSGarrett D'Amore return(ROFF_IGN); 796*95c635efSGarrett D'Amore } 797*95c635efSGarrett D'Amore 798*95c635efSGarrett D'Amore switch (r->last->tok) { 799*95c635efSGarrett D'Amore case (ROFF_el): 800*95c635efSGarrett D'Amore /* FALLTHROUGH */ 801*95c635efSGarrett D'Amore case (ROFF_ie): 802*95c635efSGarrett D'Amore /* FALLTHROUGH */ 803*95c635efSGarrett D'Amore case (ROFF_if): 804*95c635efSGarrett D'Amore break; 805*95c635efSGarrett D'Amore default: 806*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); 807*95c635efSGarrett D'Amore return(ROFF_IGN); 808*95c635efSGarrett D'Amore } 809*95c635efSGarrett D'Amore 810*95c635efSGarrett D'Amore if (r->last->endspan > -1) { 811*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); 812*95c635efSGarrett D'Amore return(ROFF_IGN); 813*95c635efSGarrett D'Amore } 814*95c635efSGarrett D'Amore 815*95c635efSGarrett D'Amore if ((*bufp)[pos]) 816*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL); 817*95c635efSGarrett D'Amore 818*95c635efSGarrett D'Amore roffnode_pop(r); 819*95c635efSGarrett D'Amore roffnode_cleanscope(r); 820*95c635efSGarrett D'Amore return(ROFF_IGN); 821*95c635efSGarrett D'Amore } 822*95c635efSGarrett D'Amore 823*95c635efSGarrett D'Amore 824*95c635efSGarrett D'Amore /* ARGSUSED */ 825*95c635efSGarrett D'Amore static enum rofferr 826*95c635efSGarrett D'Amore roff_block(ROFF_ARGS) 827*95c635efSGarrett D'Amore { 828*95c635efSGarrett D'Amore int sv; 829*95c635efSGarrett D'Amore size_t sz; 830*95c635efSGarrett D'Amore char *name; 831*95c635efSGarrett D'Amore 832*95c635efSGarrett D'Amore name = NULL; 833*95c635efSGarrett D'Amore 834*95c635efSGarrett D'Amore if (ROFF_ig != tok) { 835*95c635efSGarrett D'Amore if ('\0' == (*bufp)[pos]) { 836*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL); 837*95c635efSGarrett D'Amore return(ROFF_IGN); 838*95c635efSGarrett D'Amore } 839*95c635efSGarrett D'Amore 840*95c635efSGarrett D'Amore /* 841*95c635efSGarrett D'Amore * Re-write `de1', since we don't really care about 842*95c635efSGarrett D'Amore * groff's strange compatibility mode, into `de'. 843*95c635efSGarrett D'Amore */ 844*95c635efSGarrett D'Amore 845*95c635efSGarrett D'Amore if (ROFF_de1 == tok) 846*95c635efSGarrett D'Amore tok = ROFF_de; 847*95c635efSGarrett D'Amore if (ROFF_de == tok) 848*95c635efSGarrett D'Amore name = *bufp + pos; 849*95c635efSGarrett D'Amore else 850*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos, 851*95c635efSGarrett D'Amore roffs[tok].name); 852*95c635efSGarrett D'Amore 853*95c635efSGarrett D'Amore while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos])) 854*95c635efSGarrett D'Amore pos++; 855*95c635efSGarrett D'Amore 856*95c635efSGarrett D'Amore while (isspace((unsigned char)(*bufp)[pos])) 857*95c635efSGarrett D'Amore (*bufp)[pos++] = '\0'; 858*95c635efSGarrett D'Amore } 859*95c635efSGarrett D'Amore 860*95c635efSGarrett D'Amore roffnode_push(r, tok, name, ln, ppos); 861*95c635efSGarrett D'Amore 862*95c635efSGarrett D'Amore /* 863*95c635efSGarrett D'Amore * At the beginning of a `de' macro, clear the existing string 864*95c635efSGarrett D'Amore * with the same name, if there is one. New content will be 865*95c635efSGarrett D'Amore * added from roff_block_text() in multiline mode. 866*95c635efSGarrett D'Amore */ 867*95c635efSGarrett D'Amore 868*95c635efSGarrett D'Amore if (ROFF_de == tok) 869*95c635efSGarrett D'Amore roff_setstr(r, name, "", 0); 870*95c635efSGarrett D'Amore 871*95c635efSGarrett D'Amore if ('\0' == (*bufp)[pos]) 872*95c635efSGarrett D'Amore return(ROFF_IGN); 873*95c635efSGarrett D'Amore 874*95c635efSGarrett D'Amore /* If present, process the custom end-of-line marker. */ 875*95c635efSGarrett D'Amore 876*95c635efSGarrett D'Amore sv = pos; 877*95c635efSGarrett D'Amore while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos])) 878*95c635efSGarrett D'Amore pos++; 879*95c635efSGarrett D'Amore 880*95c635efSGarrett D'Amore /* 881*95c635efSGarrett D'Amore * Note: groff does NOT like escape characters in the input. 882*95c635efSGarrett D'Amore * Instead of detecting this, we're just going to let it fly and 883*95c635efSGarrett D'Amore * to hell with it. 884*95c635efSGarrett D'Amore */ 885*95c635efSGarrett D'Amore 886*95c635efSGarrett D'Amore assert(pos > sv); 887*95c635efSGarrett D'Amore sz = (size_t)(pos - sv); 888*95c635efSGarrett D'Amore 889*95c635efSGarrett D'Amore if (1 == sz && '.' == (*bufp)[sv]) 890*95c635efSGarrett D'Amore return(ROFF_IGN); 891*95c635efSGarrett D'Amore 892*95c635efSGarrett D'Amore r->last->end = mandoc_malloc(sz + 1); 893*95c635efSGarrett D'Amore 894*95c635efSGarrett D'Amore memcpy(r->last->end, *bufp + sv, sz); 895*95c635efSGarrett D'Amore r->last->end[(int)sz] = '\0'; 896*95c635efSGarrett D'Amore 897*95c635efSGarrett D'Amore if ((*bufp)[pos]) 898*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL); 899*95c635efSGarrett D'Amore 900*95c635efSGarrett D'Amore return(ROFF_IGN); 901*95c635efSGarrett D'Amore } 902*95c635efSGarrett D'Amore 903*95c635efSGarrett D'Amore 904*95c635efSGarrett D'Amore /* ARGSUSED */ 905*95c635efSGarrett D'Amore static enum rofferr 906*95c635efSGarrett D'Amore roff_block_sub(ROFF_ARGS) 907*95c635efSGarrett D'Amore { 908*95c635efSGarrett D'Amore enum rofft t; 909*95c635efSGarrett D'Amore int i, j; 910*95c635efSGarrett D'Amore 911*95c635efSGarrett D'Amore /* 912*95c635efSGarrett D'Amore * First check whether a custom macro exists at this level. If 913*95c635efSGarrett D'Amore * it does, then check against it. This is some of groff's 914*95c635efSGarrett D'Amore * stranger behaviours. If we encountered a custom end-scope 915*95c635efSGarrett D'Amore * tag and that tag also happens to be a "real" macro, then we 916*95c635efSGarrett D'Amore * need to try interpreting it again as a real macro. If it's 917*95c635efSGarrett D'Amore * not, then return ignore. Else continue. 918*95c635efSGarrett D'Amore */ 919*95c635efSGarrett D'Amore 920*95c635efSGarrett D'Amore if (r->last->end) { 921*95c635efSGarrett D'Amore for (i = pos, j = 0; r->last->end[j]; j++, i++) 922*95c635efSGarrett D'Amore if ((*bufp)[i] != r->last->end[j]) 923*95c635efSGarrett D'Amore break; 924*95c635efSGarrett D'Amore 925*95c635efSGarrett D'Amore if ('\0' == r->last->end[j] && 926*95c635efSGarrett D'Amore ('\0' == (*bufp)[i] || 927*95c635efSGarrett D'Amore ' ' == (*bufp)[i] || 928*95c635efSGarrett D'Amore '\t' == (*bufp)[i])) { 929*95c635efSGarrett D'Amore roffnode_pop(r); 930*95c635efSGarrett D'Amore roffnode_cleanscope(r); 931*95c635efSGarrett D'Amore 932*95c635efSGarrett D'Amore while (' ' == (*bufp)[i] || '\t' == (*bufp)[i]) 933*95c635efSGarrett D'Amore i++; 934*95c635efSGarrett D'Amore 935*95c635efSGarrett D'Amore pos = i; 936*95c635efSGarrett D'Amore if (ROFF_MAX != roff_parse(r, *bufp, &pos)) 937*95c635efSGarrett D'Amore return(ROFF_RERUN); 938*95c635efSGarrett D'Amore return(ROFF_IGN); 939*95c635efSGarrett D'Amore } 940*95c635efSGarrett D'Amore } 941*95c635efSGarrett D'Amore 942*95c635efSGarrett D'Amore /* 943*95c635efSGarrett D'Amore * If we have no custom end-query or lookup failed, then try 944*95c635efSGarrett D'Amore * pulling it out of the hashtable. 945*95c635efSGarrett D'Amore */ 946*95c635efSGarrett D'Amore 947*95c635efSGarrett D'Amore t = roff_parse(r, *bufp, &pos); 948*95c635efSGarrett D'Amore 949*95c635efSGarrett D'Amore /* 950*95c635efSGarrett D'Amore * Macros other than block-end are only significant 951*95c635efSGarrett D'Amore * in `de' blocks; elsewhere, simply throw them away. 952*95c635efSGarrett D'Amore */ 953*95c635efSGarrett D'Amore if (ROFF_cblock != t) { 954*95c635efSGarrett D'Amore if (ROFF_de == tok) 955*95c635efSGarrett D'Amore roff_setstr(r, r->last->name, *bufp + ppos, 1); 956*95c635efSGarrett D'Amore return(ROFF_IGN); 957*95c635efSGarrett D'Amore } 958*95c635efSGarrett D'Amore 959*95c635efSGarrett D'Amore assert(roffs[t].proc); 960*95c635efSGarrett D'Amore return((*roffs[t].proc)(r, t, bufp, szp, 961*95c635efSGarrett D'Amore ln, ppos, pos, offs)); 962*95c635efSGarrett D'Amore } 963*95c635efSGarrett D'Amore 964*95c635efSGarrett D'Amore 965*95c635efSGarrett D'Amore /* ARGSUSED */ 966*95c635efSGarrett D'Amore static enum rofferr 967*95c635efSGarrett D'Amore roff_block_text(ROFF_ARGS) 968*95c635efSGarrett D'Amore { 969*95c635efSGarrett D'Amore 970*95c635efSGarrett D'Amore if (ROFF_de == tok) 971*95c635efSGarrett D'Amore roff_setstr(r, r->last->name, *bufp + pos, 1); 972*95c635efSGarrett D'Amore 973*95c635efSGarrett D'Amore return(ROFF_IGN); 974*95c635efSGarrett D'Amore } 975*95c635efSGarrett D'Amore 976*95c635efSGarrett D'Amore 977*95c635efSGarrett D'Amore /* ARGSUSED */ 978*95c635efSGarrett D'Amore static enum rofferr 979*95c635efSGarrett D'Amore roff_cond_sub(ROFF_ARGS) 980*95c635efSGarrett D'Amore { 981*95c635efSGarrett D'Amore enum rofft t; 982*95c635efSGarrett D'Amore enum roffrule rr; 983*95c635efSGarrett D'Amore char *ep; 984*95c635efSGarrett D'Amore 985*95c635efSGarrett D'Amore rr = r->last->rule; 986*95c635efSGarrett D'Amore roffnode_cleanscope(r); 987*95c635efSGarrett D'Amore 988*95c635efSGarrett D'Amore /* 989*95c635efSGarrett D'Amore * If the macro is unknown, first check if it contains a closing 990*95c635efSGarrett D'Amore * delimiter `\}'. If it does, close out our scope and return 991*95c635efSGarrett D'Amore * the currently-scoped rule (ignore or continue). Else, drop 992*95c635efSGarrett D'Amore * into the currently-scoped rule. 993*95c635efSGarrett D'Amore */ 994*95c635efSGarrett D'Amore 995*95c635efSGarrett D'Amore if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos))) { 996*95c635efSGarrett D'Amore ep = &(*bufp)[pos]; 997*95c635efSGarrett D'Amore for ( ; NULL != (ep = strchr(ep, '\\')); ep++) { 998*95c635efSGarrett D'Amore ep++; 999*95c635efSGarrett D'Amore if ('}' != *ep) 1000*95c635efSGarrett D'Amore continue; 1001*95c635efSGarrett D'Amore 1002*95c635efSGarrett D'Amore /* 1003*95c635efSGarrett D'Amore * Make the \} go away. 1004*95c635efSGarrett D'Amore * This is a little haphazard, as it's not quite 1005*95c635efSGarrett D'Amore * clear how nroff does this. 1006*95c635efSGarrett D'Amore * If we're at the end of line, then just chop 1007*95c635efSGarrett D'Amore * off the \} and resize the buffer. 1008*95c635efSGarrett D'Amore * If we aren't, then conver it to spaces. 1009*95c635efSGarrett D'Amore */ 1010*95c635efSGarrett D'Amore 1011*95c635efSGarrett D'Amore if ('\0' == *(ep + 1)) { 1012*95c635efSGarrett D'Amore *--ep = '\0'; 1013*95c635efSGarrett D'Amore *szp -= 2; 1014*95c635efSGarrett D'Amore } else 1015*95c635efSGarrett D'Amore *(ep - 1) = *ep = ' '; 1016*95c635efSGarrett D'Amore 1017*95c635efSGarrett D'Amore roff_ccond(r, ROFF_ccond, bufp, szp, 1018*95c635efSGarrett D'Amore ln, pos, pos + 2, offs); 1019*95c635efSGarrett D'Amore break; 1020*95c635efSGarrett D'Amore } 1021*95c635efSGarrett D'Amore return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); 1022*95c635efSGarrett D'Amore } 1023*95c635efSGarrett D'Amore 1024*95c635efSGarrett D'Amore /* 1025*95c635efSGarrett D'Amore * A denied conditional must evaluate its children if and only 1026*95c635efSGarrett D'Amore * if they're either structurally required (such as loops and 1027*95c635efSGarrett D'Amore * conditionals) or a closing macro. 1028*95c635efSGarrett D'Amore */ 1029*95c635efSGarrett D'Amore 1030*95c635efSGarrett D'Amore if (ROFFRULE_DENY == rr) 1031*95c635efSGarrett D'Amore if ( ! (ROFFMAC_STRUCT & roffs[t].flags)) 1032*95c635efSGarrett D'Amore if (ROFF_ccond != t) 1033*95c635efSGarrett D'Amore return(ROFF_IGN); 1034*95c635efSGarrett D'Amore 1035*95c635efSGarrett D'Amore assert(roffs[t].proc); 1036*95c635efSGarrett D'Amore return((*roffs[t].proc)(r, t, bufp, szp, 1037*95c635efSGarrett D'Amore ln, ppos, pos, offs)); 1038*95c635efSGarrett D'Amore } 1039*95c635efSGarrett D'Amore 1040*95c635efSGarrett D'Amore /* ARGSUSED */ 1041*95c635efSGarrett D'Amore static enum rofferr 1042*95c635efSGarrett D'Amore roff_cond_text(ROFF_ARGS) 1043*95c635efSGarrett D'Amore { 1044*95c635efSGarrett D'Amore char *ep; 1045*95c635efSGarrett D'Amore enum roffrule rr; 1046*95c635efSGarrett D'Amore 1047*95c635efSGarrett D'Amore rr = r->last->rule; 1048*95c635efSGarrett D'Amore roffnode_cleanscope(r); 1049*95c635efSGarrett D'Amore 1050*95c635efSGarrett D'Amore ep = &(*bufp)[pos]; 1051*95c635efSGarrett D'Amore for ( ; NULL != (ep = strchr(ep, '\\')); ep++) { 1052*95c635efSGarrett D'Amore ep++; 1053*95c635efSGarrett D'Amore if ('}' != *ep) 1054*95c635efSGarrett D'Amore continue; 1055*95c635efSGarrett D'Amore *ep = '&'; 1056*95c635efSGarrett D'Amore roff_ccond(r, ROFF_ccond, bufp, szp, 1057*95c635efSGarrett D'Amore ln, pos, pos + 2, offs); 1058*95c635efSGarrett D'Amore } 1059*95c635efSGarrett D'Amore return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); 1060*95c635efSGarrett D'Amore } 1061*95c635efSGarrett D'Amore 1062*95c635efSGarrett D'Amore static enum roffrule 1063*95c635efSGarrett D'Amore roff_evalcond(const char *v, int *pos) 1064*95c635efSGarrett D'Amore { 1065*95c635efSGarrett D'Amore 1066*95c635efSGarrett D'Amore switch (v[*pos]) { 1067*95c635efSGarrett D'Amore case ('n'): 1068*95c635efSGarrett D'Amore (*pos)++; 1069*95c635efSGarrett D'Amore return(ROFFRULE_ALLOW); 1070*95c635efSGarrett D'Amore case ('e'): 1071*95c635efSGarrett D'Amore /* FALLTHROUGH */ 1072*95c635efSGarrett D'Amore case ('o'): 1073*95c635efSGarrett D'Amore /* FALLTHROUGH */ 1074*95c635efSGarrett D'Amore case ('t'): 1075*95c635efSGarrett D'Amore (*pos)++; 1076*95c635efSGarrett D'Amore return(ROFFRULE_DENY); 1077*95c635efSGarrett D'Amore default: 1078*95c635efSGarrett D'Amore break; 1079*95c635efSGarrett D'Amore } 1080*95c635efSGarrett D'Amore 1081*95c635efSGarrett D'Amore while (v[*pos] && ' ' != v[*pos]) 1082*95c635efSGarrett D'Amore (*pos)++; 1083*95c635efSGarrett D'Amore return(ROFFRULE_DENY); 1084*95c635efSGarrett D'Amore } 1085*95c635efSGarrett D'Amore 1086*95c635efSGarrett D'Amore /* ARGSUSED */ 1087*95c635efSGarrett D'Amore static enum rofferr 1088*95c635efSGarrett D'Amore roff_line_ignore(ROFF_ARGS) 1089*95c635efSGarrett D'Amore { 1090*95c635efSGarrett D'Amore 1091*95c635efSGarrett D'Amore if (ROFF_it == tok) 1092*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos, "it"); 1093*95c635efSGarrett D'Amore 1094*95c635efSGarrett D'Amore return(ROFF_IGN); 1095*95c635efSGarrett D'Amore } 1096*95c635efSGarrett D'Amore 1097*95c635efSGarrett D'Amore /* ARGSUSED */ 1098*95c635efSGarrett D'Amore static enum rofferr 1099*95c635efSGarrett D'Amore roff_cond(ROFF_ARGS) 1100*95c635efSGarrett D'Amore { 1101*95c635efSGarrett D'Amore int sv; 1102*95c635efSGarrett D'Amore enum roffrule rule; 1103*95c635efSGarrett D'Amore 1104*95c635efSGarrett D'Amore /* 1105*95c635efSGarrett D'Amore * An `.el' has no conditional body: it will consume the value 1106*95c635efSGarrett D'Amore * of the current rstack entry set in prior `ie' calls or 1107*95c635efSGarrett D'Amore * defaults to DENY. 1108*95c635efSGarrett D'Amore * 1109*95c635efSGarrett D'Amore * If we're not an `el', however, then evaluate the conditional. 1110*95c635efSGarrett D'Amore */ 1111*95c635efSGarrett D'Amore 1112*95c635efSGarrett D'Amore rule = ROFF_el == tok ? 1113*95c635efSGarrett D'Amore (r->rstackpos < 0 ? 1114*95c635efSGarrett D'Amore ROFFRULE_DENY : r->rstack[r->rstackpos--]) : 1115*95c635efSGarrett D'Amore roff_evalcond(*bufp, &pos); 1116*95c635efSGarrett D'Amore 1117*95c635efSGarrett D'Amore sv = pos; 1118*95c635efSGarrett D'Amore while (' ' == (*bufp)[pos]) 1119*95c635efSGarrett D'Amore pos++; 1120*95c635efSGarrett D'Amore 1121*95c635efSGarrett D'Amore /* 1122*95c635efSGarrett D'Amore * Roff is weird. If we have just white-space after the 1123*95c635efSGarrett D'Amore * conditional, it's considered the BODY and we exit without 1124*95c635efSGarrett D'Amore * really doing anything. Warn about this. It's probably 1125*95c635efSGarrett D'Amore * wrong. 1126*95c635efSGarrett D'Amore */ 1127*95c635efSGarrett D'Amore 1128*95c635efSGarrett D'Amore if ('\0' == (*bufp)[pos] && sv != pos) { 1129*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL); 1130*95c635efSGarrett D'Amore return(ROFF_IGN); 1131*95c635efSGarrett D'Amore } 1132*95c635efSGarrett D'Amore 1133*95c635efSGarrett D'Amore roffnode_push(r, tok, NULL, ln, ppos); 1134*95c635efSGarrett D'Amore 1135*95c635efSGarrett D'Amore r->last->rule = rule; 1136*95c635efSGarrett D'Amore 1137*95c635efSGarrett D'Amore /* 1138*95c635efSGarrett D'Amore * An if-else will put the NEGATION of the current evaluated 1139*95c635efSGarrett D'Amore * conditional into the stack of rules. 1140*95c635efSGarrett D'Amore */ 1141*95c635efSGarrett D'Amore 1142*95c635efSGarrett D'Amore if (ROFF_ie == tok) { 1143*95c635efSGarrett D'Amore if (r->rstackpos == RSTACK_MAX - 1) { 1144*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_MEM, 1145*95c635efSGarrett D'Amore r->parse, ln, ppos, NULL); 1146*95c635efSGarrett D'Amore return(ROFF_ERR); 1147*95c635efSGarrett D'Amore } 1148*95c635efSGarrett D'Amore r->rstack[++r->rstackpos] = 1149*95c635efSGarrett D'Amore ROFFRULE_DENY == r->last->rule ? 1150*95c635efSGarrett D'Amore ROFFRULE_ALLOW : ROFFRULE_DENY; 1151*95c635efSGarrett D'Amore } 1152*95c635efSGarrett D'Amore 1153*95c635efSGarrett D'Amore /* If the parent has false as its rule, then so do we. */ 1154*95c635efSGarrett D'Amore 1155*95c635efSGarrett D'Amore if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule) 1156*95c635efSGarrett D'Amore r->last->rule = ROFFRULE_DENY; 1157*95c635efSGarrett D'Amore 1158*95c635efSGarrett D'Amore /* 1159*95c635efSGarrett D'Amore * Determine scope. If we're invoked with "\{" trailing the 1160*95c635efSGarrett D'Amore * conditional, then we're in a multiline scope. Else our scope 1161*95c635efSGarrett D'Amore * expires on the next line. 1162*95c635efSGarrett D'Amore */ 1163*95c635efSGarrett D'Amore 1164*95c635efSGarrett D'Amore r->last->endspan = 1; 1165*95c635efSGarrett D'Amore 1166*95c635efSGarrett D'Amore if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) { 1167*95c635efSGarrett D'Amore r->last->endspan = -1; 1168*95c635efSGarrett D'Amore pos += 2; 1169*95c635efSGarrett D'Amore } 1170*95c635efSGarrett D'Amore 1171*95c635efSGarrett D'Amore /* 1172*95c635efSGarrett D'Amore * If there are no arguments on the line, the next-line scope is 1173*95c635efSGarrett D'Amore * assumed. 1174*95c635efSGarrett D'Amore */ 1175*95c635efSGarrett D'Amore 1176*95c635efSGarrett D'Amore if ('\0' == (*bufp)[pos]) 1177*95c635efSGarrett D'Amore return(ROFF_IGN); 1178*95c635efSGarrett D'Amore 1179*95c635efSGarrett D'Amore /* Otherwise re-run the roff parser after recalculating. */ 1180*95c635efSGarrett D'Amore 1181*95c635efSGarrett D'Amore *offs = pos; 1182*95c635efSGarrett D'Amore return(ROFF_RERUN); 1183*95c635efSGarrett D'Amore } 1184*95c635efSGarrett D'Amore 1185*95c635efSGarrett D'Amore 1186*95c635efSGarrett D'Amore /* ARGSUSED */ 1187*95c635efSGarrett D'Amore static enum rofferr 1188*95c635efSGarrett D'Amore roff_ds(ROFF_ARGS) 1189*95c635efSGarrett D'Amore { 1190*95c635efSGarrett D'Amore char *name, *string; 1191*95c635efSGarrett D'Amore 1192*95c635efSGarrett D'Amore /* 1193*95c635efSGarrett D'Amore * A symbol is named by the first word following the macro 1194*95c635efSGarrett D'Amore * invocation up to a space. Its value is anything after the 1195*95c635efSGarrett D'Amore * name's trailing whitespace and optional double-quote. Thus, 1196*95c635efSGarrett D'Amore * 1197*95c635efSGarrett D'Amore * [.ds foo "bar " ] 1198*95c635efSGarrett D'Amore * 1199*95c635efSGarrett D'Amore * will have `bar " ' as its value. 1200*95c635efSGarrett D'Amore */ 1201*95c635efSGarrett D'Amore 1202*95c635efSGarrett D'Amore string = *bufp + pos; 1203*95c635efSGarrett D'Amore name = roff_getname(r, &string, ln, pos); 1204*95c635efSGarrett D'Amore if ('\0' == *name) 1205*95c635efSGarrett D'Amore return(ROFF_IGN); 1206*95c635efSGarrett D'Amore 1207*95c635efSGarrett D'Amore /* Read past initial double-quote. */ 1208*95c635efSGarrett D'Amore if ('"' == *string) 1209*95c635efSGarrett D'Amore string++; 1210*95c635efSGarrett D'Amore 1211*95c635efSGarrett D'Amore /* The rest is the value. */ 1212*95c635efSGarrett D'Amore roff_setstr(r, name, string, 0); 1213*95c635efSGarrett D'Amore return(ROFF_IGN); 1214*95c635efSGarrett D'Amore } 1215*95c635efSGarrett D'Amore 1216*95c635efSGarrett D'Amore int 1217*95c635efSGarrett D'Amore roff_regisset(const struct roff *r, enum regs reg) 1218*95c635efSGarrett D'Amore { 1219*95c635efSGarrett D'Amore 1220*95c635efSGarrett D'Amore return(r->regs[(int)reg].set); 1221*95c635efSGarrett D'Amore } 1222*95c635efSGarrett D'Amore 1223*95c635efSGarrett D'Amore unsigned int 1224*95c635efSGarrett D'Amore roff_regget(const struct roff *r, enum regs reg) 1225*95c635efSGarrett D'Amore { 1226*95c635efSGarrett D'Amore 1227*95c635efSGarrett D'Amore return(r->regs[(int)reg].u); 1228*95c635efSGarrett D'Amore } 1229*95c635efSGarrett D'Amore 1230*95c635efSGarrett D'Amore void 1231*95c635efSGarrett D'Amore roff_regunset(struct roff *r, enum regs reg) 1232*95c635efSGarrett D'Amore { 1233*95c635efSGarrett D'Amore 1234*95c635efSGarrett D'Amore r->regs[(int)reg].set = 0; 1235*95c635efSGarrett D'Amore } 1236*95c635efSGarrett D'Amore 1237*95c635efSGarrett D'Amore /* ARGSUSED */ 1238*95c635efSGarrett D'Amore static enum rofferr 1239*95c635efSGarrett D'Amore roff_nr(ROFF_ARGS) 1240*95c635efSGarrett D'Amore { 1241*95c635efSGarrett D'Amore const char *key; 1242*95c635efSGarrett D'Amore char *val; 1243*95c635efSGarrett D'Amore int iv; 1244*95c635efSGarrett D'Amore 1245*95c635efSGarrett D'Amore val = *bufp + pos; 1246*95c635efSGarrett D'Amore key = roff_getname(r, &val, ln, pos); 1247*95c635efSGarrett D'Amore 1248*95c635efSGarrett D'Amore if (0 == strcmp(key, "nS")) { 1249*95c635efSGarrett D'Amore r->regs[(int)REG_nS].set = 1; 1250*95c635efSGarrett D'Amore if ((iv = mandoc_strntoi(val, strlen(val), 10)) >= 0) 1251*95c635efSGarrett D'Amore r->regs[(int)REG_nS].u = (unsigned)iv; 1252*95c635efSGarrett D'Amore else 1253*95c635efSGarrett D'Amore r->regs[(int)REG_nS].u = 0u; 1254*95c635efSGarrett D'Amore } 1255*95c635efSGarrett D'Amore 1256*95c635efSGarrett D'Amore return(ROFF_IGN); 1257*95c635efSGarrett D'Amore } 1258*95c635efSGarrett D'Amore 1259*95c635efSGarrett D'Amore /* ARGSUSED */ 1260*95c635efSGarrett D'Amore static enum rofferr 1261*95c635efSGarrett D'Amore roff_rm(ROFF_ARGS) 1262*95c635efSGarrett D'Amore { 1263*95c635efSGarrett D'Amore const char *name; 1264*95c635efSGarrett D'Amore char *cp; 1265*95c635efSGarrett D'Amore 1266*95c635efSGarrett D'Amore cp = *bufp + pos; 1267*95c635efSGarrett D'Amore while ('\0' != *cp) { 1268*95c635efSGarrett D'Amore name = roff_getname(r, &cp, ln, (int)(cp - *bufp)); 1269*95c635efSGarrett D'Amore if ('\0' != *name) 1270*95c635efSGarrett D'Amore roff_setstr(r, name, NULL, 0); 1271*95c635efSGarrett D'Amore } 1272*95c635efSGarrett D'Amore return(ROFF_IGN); 1273*95c635efSGarrett D'Amore } 1274*95c635efSGarrett D'Amore 1275*95c635efSGarrett D'Amore /* ARGSUSED */ 1276*95c635efSGarrett D'Amore static enum rofferr 1277*95c635efSGarrett D'Amore roff_TE(ROFF_ARGS) 1278*95c635efSGarrett D'Amore { 1279*95c635efSGarrett D'Amore 1280*95c635efSGarrett D'Amore if (NULL == r->tbl) 1281*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); 1282*95c635efSGarrett D'Amore else 1283*95c635efSGarrett D'Amore tbl_end(&r->tbl); 1284*95c635efSGarrett D'Amore 1285*95c635efSGarrett D'Amore return(ROFF_IGN); 1286*95c635efSGarrett D'Amore } 1287*95c635efSGarrett D'Amore 1288*95c635efSGarrett D'Amore /* ARGSUSED */ 1289*95c635efSGarrett D'Amore static enum rofferr 1290*95c635efSGarrett D'Amore roff_T_(ROFF_ARGS) 1291*95c635efSGarrett D'Amore { 1292*95c635efSGarrett D'Amore 1293*95c635efSGarrett D'Amore if (NULL == r->tbl) 1294*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); 1295*95c635efSGarrett D'Amore else 1296*95c635efSGarrett D'Amore tbl_restart(ppos, ln, r->tbl); 1297*95c635efSGarrett D'Amore 1298*95c635efSGarrett D'Amore return(ROFF_IGN); 1299*95c635efSGarrett D'Amore } 1300*95c635efSGarrett D'Amore 1301*95c635efSGarrett D'Amore #if 0 1302*95c635efSGarrett D'Amore static int 1303*95c635efSGarrett D'Amore roff_closeeqn(struct roff *r) 1304*95c635efSGarrett D'Amore { 1305*95c635efSGarrett D'Amore 1306*95c635efSGarrett D'Amore return(r->eqn && ROFF_EQN == eqn_end(&r->eqn) ? 1 : 0); 1307*95c635efSGarrett D'Amore } 1308*95c635efSGarrett D'Amore #endif 1309*95c635efSGarrett D'Amore 1310*95c635efSGarrett D'Amore static void 1311*95c635efSGarrett D'Amore roff_openeqn(struct roff *r, const char *name, int line, 1312*95c635efSGarrett D'Amore int offs, const char *buf) 1313*95c635efSGarrett D'Amore { 1314*95c635efSGarrett D'Amore struct eqn_node *e; 1315*95c635efSGarrett D'Amore int poff; 1316*95c635efSGarrett D'Amore 1317*95c635efSGarrett D'Amore assert(NULL == r->eqn); 1318*95c635efSGarrett D'Amore e = eqn_alloc(name, offs, line, r->parse); 1319*95c635efSGarrett D'Amore 1320*95c635efSGarrett D'Amore if (r->last_eqn) 1321*95c635efSGarrett D'Amore r->last_eqn->next = e; 1322*95c635efSGarrett D'Amore else 1323*95c635efSGarrett D'Amore r->first_eqn = r->last_eqn = e; 1324*95c635efSGarrett D'Amore 1325*95c635efSGarrett D'Amore r->eqn = r->last_eqn = e; 1326*95c635efSGarrett D'Amore 1327*95c635efSGarrett D'Amore if (buf) { 1328*95c635efSGarrett D'Amore poff = 0; 1329*95c635efSGarrett D'Amore eqn_read(&r->eqn, line, buf, offs, &poff); 1330*95c635efSGarrett D'Amore } 1331*95c635efSGarrett D'Amore } 1332*95c635efSGarrett D'Amore 1333*95c635efSGarrett D'Amore /* ARGSUSED */ 1334*95c635efSGarrett D'Amore static enum rofferr 1335*95c635efSGarrett D'Amore roff_EQ(ROFF_ARGS) 1336*95c635efSGarrett D'Amore { 1337*95c635efSGarrett D'Amore 1338*95c635efSGarrett D'Amore roff_openeqn(r, *bufp + pos, ln, ppos, NULL); 1339*95c635efSGarrett D'Amore return(ROFF_IGN); 1340*95c635efSGarrett D'Amore } 1341*95c635efSGarrett D'Amore 1342*95c635efSGarrett D'Amore /* ARGSUSED */ 1343*95c635efSGarrett D'Amore static enum rofferr 1344*95c635efSGarrett D'Amore roff_EN(ROFF_ARGS) 1345*95c635efSGarrett D'Amore { 1346*95c635efSGarrett D'Amore 1347*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); 1348*95c635efSGarrett D'Amore return(ROFF_IGN); 1349*95c635efSGarrett D'Amore } 1350*95c635efSGarrett D'Amore 1351*95c635efSGarrett D'Amore /* ARGSUSED */ 1352*95c635efSGarrett D'Amore static enum rofferr 1353*95c635efSGarrett D'Amore roff_TS(ROFF_ARGS) 1354*95c635efSGarrett D'Amore { 1355*95c635efSGarrett D'Amore struct tbl_node *t; 1356*95c635efSGarrett D'Amore 1357*95c635efSGarrett D'Amore if (r->tbl) { 1358*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_SCOPEBROKEN, r->parse, ln, ppos, NULL); 1359*95c635efSGarrett D'Amore tbl_end(&r->tbl); 1360*95c635efSGarrett D'Amore } 1361*95c635efSGarrett D'Amore 1362*95c635efSGarrett D'Amore t = tbl_alloc(ppos, ln, r->parse); 1363*95c635efSGarrett D'Amore 1364*95c635efSGarrett D'Amore if (r->last_tbl) 1365*95c635efSGarrett D'Amore r->last_tbl->next = t; 1366*95c635efSGarrett D'Amore else 1367*95c635efSGarrett D'Amore r->first_tbl = r->last_tbl = t; 1368*95c635efSGarrett D'Amore 1369*95c635efSGarrett D'Amore r->tbl = r->last_tbl = t; 1370*95c635efSGarrett D'Amore return(ROFF_IGN); 1371*95c635efSGarrett D'Amore } 1372*95c635efSGarrett D'Amore 1373*95c635efSGarrett D'Amore /* ARGSUSED */ 1374*95c635efSGarrett D'Amore static enum rofferr 1375*95c635efSGarrett D'Amore roff_tr(ROFF_ARGS) 1376*95c635efSGarrett D'Amore { 1377*95c635efSGarrett D'Amore const char *p, *first, *second; 1378*95c635efSGarrett D'Amore size_t fsz, ssz; 1379*95c635efSGarrett D'Amore enum mandoc_esc esc; 1380*95c635efSGarrett D'Amore 1381*95c635efSGarrett D'Amore p = *bufp + pos; 1382*95c635efSGarrett D'Amore 1383*95c635efSGarrett D'Amore if ('\0' == *p) { 1384*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, ln, ppos, NULL); 1385*95c635efSGarrett D'Amore return(ROFF_IGN); 1386*95c635efSGarrett D'Amore } 1387*95c635efSGarrett D'Amore 1388*95c635efSGarrett D'Amore while ('\0' != *p) { 1389*95c635efSGarrett D'Amore fsz = ssz = 1; 1390*95c635efSGarrett D'Amore 1391*95c635efSGarrett D'Amore first = p++; 1392*95c635efSGarrett D'Amore if ('\\' == *first) { 1393*95c635efSGarrett D'Amore esc = mandoc_escape(&p, NULL, NULL); 1394*95c635efSGarrett D'Amore if (ESCAPE_ERROR == esc) { 1395*95c635efSGarrett D'Amore mandoc_msg 1396*95c635efSGarrett D'Amore (MANDOCERR_BADESCAPE, r->parse, 1397*95c635efSGarrett D'Amore ln, (int)(p - *bufp), NULL); 1398*95c635efSGarrett D'Amore return(ROFF_IGN); 1399*95c635efSGarrett D'Amore } 1400*95c635efSGarrett D'Amore fsz = (size_t)(p - first); 1401*95c635efSGarrett D'Amore } 1402*95c635efSGarrett D'Amore 1403*95c635efSGarrett D'Amore second = p++; 1404*95c635efSGarrett D'Amore if ('\\' == *second) { 1405*95c635efSGarrett D'Amore esc = mandoc_escape(&p, NULL, NULL); 1406*95c635efSGarrett D'Amore if (ESCAPE_ERROR == esc) { 1407*95c635efSGarrett D'Amore mandoc_msg 1408*95c635efSGarrett D'Amore (MANDOCERR_BADESCAPE, r->parse, 1409*95c635efSGarrett D'Amore ln, (int)(p - *bufp), NULL); 1410*95c635efSGarrett D'Amore return(ROFF_IGN); 1411*95c635efSGarrett D'Amore } 1412*95c635efSGarrett D'Amore ssz = (size_t)(p - second); 1413*95c635efSGarrett D'Amore } else if ('\0' == *second) { 1414*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, 1415*95c635efSGarrett D'Amore ln, (int)(p - *bufp), NULL); 1416*95c635efSGarrett D'Amore second = " "; 1417*95c635efSGarrett D'Amore p--; 1418*95c635efSGarrett D'Amore } 1419*95c635efSGarrett D'Amore 1420*95c635efSGarrett D'Amore if (fsz > 1) { 1421*95c635efSGarrett D'Amore roff_setstrn(&r->xmbtab, first, 1422*95c635efSGarrett D'Amore fsz, second, ssz, 0); 1423*95c635efSGarrett D'Amore continue; 1424*95c635efSGarrett D'Amore } 1425*95c635efSGarrett D'Amore 1426*95c635efSGarrett D'Amore if (NULL == r->xtab) 1427*95c635efSGarrett D'Amore r->xtab = mandoc_calloc 1428*95c635efSGarrett D'Amore (128, sizeof(struct roffstr)); 1429*95c635efSGarrett D'Amore 1430*95c635efSGarrett D'Amore free(r->xtab[(int)*first].p); 1431*95c635efSGarrett D'Amore r->xtab[(int)*first].p = mandoc_strndup(second, ssz); 1432*95c635efSGarrett D'Amore r->xtab[(int)*first].sz = ssz; 1433*95c635efSGarrett D'Amore } 1434*95c635efSGarrett D'Amore 1435*95c635efSGarrett D'Amore return(ROFF_IGN); 1436*95c635efSGarrett D'Amore } 1437*95c635efSGarrett D'Amore 1438*95c635efSGarrett D'Amore /* ARGSUSED */ 1439*95c635efSGarrett D'Amore static enum rofferr 1440*95c635efSGarrett D'Amore roff_so(ROFF_ARGS) 1441*95c635efSGarrett D'Amore { 1442*95c635efSGarrett D'Amore char *name; 1443*95c635efSGarrett D'Amore 1444*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_SO, r->parse, ln, ppos, NULL); 1445*95c635efSGarrett D'Amore 1446*95c635efSGarrett D'Amore /* 1447*95c635efSGarrett D'Amore * Handle `so'. Be EXTREMELY careful, as we shouldn't be 1448*95c635efSGarrett D'Amore * opening anything that's not in our cwd or anything beneath 1449*95c635efSGarrett D'Amore * it. Thus, explicitly disallow traversing up the file-system 1450*95c635efSGarrett D'Amore * or using absolute paths. 1451*95c635efSGarrett D'Amore */ 1452*95c635efSGarrett D'Amore 1453*95c635efSGarrett D'Amore name = *bufp + pos; 1454*95c635efSGarrett D'Amore if ('/' == *name || strstr(name, "../") || strstr(name, "/..")) { 1455*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_SOPATH, r->parse, ln, pos, NULL); 1456*95c635efSGarrett D'Amore return(ROFF_ERR); 1457*95c635efSGarrett D'Amore } 1458*95c635efSGarrett D'Amore 1459*95c635efSGarrett D'Amore *offs = pos; 1460*95c635efSGarrett D'Amore return(ROFF_SO); 1461*95c635efSGarrett D'Amore } 1462*95c635efSGarrett D'Amore 1463*95c635efSGarrett D'Amore /* ARGSUSED */ 1464*95c635efSGarrett D'Amore static enum rofferr 1465*95c635efSGarrett D'Amore roff_userdef(ROFF_ARGS) 1466*95c635efSGarrett D'Amore { 1467*95c635efSGarrett D'Amore const char *arg[9]; 1468*95c635efSGarrett D'Amore char *cp, *n1, *n2; 1469*95c635efSGarrett D'Amore int i; 1470*95c635efSGarrett D'Amore 1471*95c635efSGarrett D'Amore /* 1472*95c635efSGarrett D'Amore * Collect pointers to macro argument strings 1473*95c635efSGarrett D'Amore * and null-terminate them. 1474*95c635efSGarrett D'Amore */ 1475*95c635efSGarrett D'Amore cp = *bufp + pos; 1476*95c635efSGarrett D'Amore for (i = 0; i < 9; i++) 1477*95c635efSGarrett D'Amore arg[i] = '\0' == *cp ? "" : 1478*95c635efSGarrett D'Amore mandoc_getarg(r->parse, &cp, ln, &pos); 1479*95c635efSGarrett D'Amore 1480*95c635efSGarrett D'Amore /* 1481*95c635efSGarrett D'Amore * Expand macro arguments. 1482*95c635efSGarrett D'Amore */ 1483*95c635efSGarrett D'Amore *szp = 0; 1484*95c635efSGarrett D'Amore n1 = cp = mandoc_strdup(r->current_string); 1485*95c635efSGarrett D'Amore while (NULL != (cp = strstr(cp, "\\$"))) { 1486*95c635efSGarrett D'Amore i = cp[2] - '1'; 1487*95c635efSGarrett D'Amore if (0 > i || 8 < i) { 1488*95c635efSGarrett D'Amore /* Not an argument invocation. */ 1489*95c635efSGarrett D'Amore cp += 2; 1490*95c635efSGarrett D'Amore continue; 1491*95c635efSGarrett D'Amore } 1492*95c635efSGarrett D'Amore 1493*95c635efSGarrett D'Amore *szp = strlen(n1) - 3 + strlen(arg[i]) + 1; 1494*95c635efSGarrett D'Amore n2 = mandoc_malloc(*szp); 1495*95c635efSGarrett D'Amore 1496*95c635efSGarrett D'Amore strlcpy(n2, n1, (size_t)(cp - n1 + 1)); 1497*95c635efSGarrett D'Amore strlcat(n2, arg[i], *szp); 1498*95c635efSGarrett D'Amore strlcat(n2, cp + 3, *szp); 1499*95c635efSGarrett D'Amore 1500*95c635efSGarrett D'Amore cp = n2 + (cp - n1); 1501*95c635efSGarrett D'Amore free(n1); 1502*95c635efSGarrett D'Amore n1 = n2; 1503*95c635efSGarrett D'Amore } 1504*95c635efSGarrett D'Amore 1505*95c635efSGarrett D'Amore /* 1506*95c635efSGarrett D'Amore * Replace the macro invocation 1507*95c635efSGarrett D'Amore * by the expanded macro. 1508*95c635efSGarrett D'Amore */ 1509*95c635efSGarrett D'Amore free(*bufp); 1510*95c635efSGarrett D'Amore *bufp = n1; 1511*95c635efSGarrett D'Amore if (0 == *szp) 1512*95c635efSGarrett D'Amore *szp = strlen(*bufp) + 1; 1513*95c635efSGarrett D'Amore 1514*95c635efSGarrett D'Amore return(*szp > 1 && '\n' == (*bufp)[(int)*szp - 2] ? 1515*95c635efSGarrett D'Amore ROFF_REPARSE : ROFF_APPEND); 1516*95c635efSGarrett D'Amore } 1517*95c635efSGarrett D'Amore 1518*95c635efSGarrett D'Amore static char * 1519*95c635efSGarrett D'Amore roff_getname(struct roff *r, char **cpp, int ln, int pos) 1520*95c635efSGarrett D'Amore { 1521*95c635efSGarrett D'Amore char *name, *cp; 1522*95c635efSGarrett D'Amore 1523*95c635efSGarrett D'Amore name = *cpp; 1524*95c635efSGarrett D'Amore if ('\0' == *name) 1525*95c635efSGarrett D'Amore return(name); 1526*95c635efSGarrett D'Amore 1527*95c635efSGarrett D'Amore /* Read until end of name. */ 1528*95c635efSGarrett D'Amore for (cp = name; '\0' != *cp && ' ' != *cp; cp++) { 1529*95c635efSGarrett D'Amore if ('\\' != *cp) 1530*95c635efSGarrett D'Amore continue; 1531*95c635efSGarrett D'Amore cp++; 1532*95c635efSGarrett D'Amore if ('\\' == *cp) 1533*95c635efSGarrett D'Amore continue; 1534*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_NAMESC, r->parse, ln, pos, NULL); 1535*95c635efSGarrett D'Amore *cp = '\0'; 1536*95c635efSGarrett D'Amore name = cp; 1537*95c635efSGarrett D'Amore } 1538*95c635efSGarrett D'Amore 1539*95c635efSGarrett D'Amore /* Nil-terminate name. */ 1540*95c635efSGarrett D'Amore if ('\0' != *cp) 1541*95c635efSGarrett D'Amore *(cp++) = '\0'; 1542*95c635efSGarrett D'Amore 1543*95c635efSGarrett D'Amore /* Read past spaces. */ 1544*95c635efSGarrett D'Amore while (' ' == *cp) 1545*95c635efSGarrett D'Amore cp++; 1546*95c635efSGarrett D'Amore 1547*95c635efSGarrett D'Amore *cpp = cp; 1548*95c635efSGarrett D'Amore return(name); 1549*95c635efSGarrett D'Amore } 1550*95c635efSGarrett D'Amore 1551*95c635efSGarrett D'Amore /* 1552*95c635efSGarrett D'Amore * Store *string into the user-defined string called *name. 1553*95c635efSGarrett D'Amore * In multiline mode, append to an existing entry and append '\n'; 1554*95c635efSGarrett D'Amore * else replace the existing entry, if there is one. 1555*95c635efSGarrett D'Amore * To clear an existing entry, call with (*r, *name, NULL, 0). 1556*95c635efSGarrett D'Amore */ 1557*95c635efSGarrett D'Amore static void 1558*95c635efSGarrett D'Amore roff_setstr(struct roff *r, const char *name, const char *string, 1559*95c635efSGarrett D'Amore int multiline) 1560*95c635efSGarrett D'Amore { 1561*95c635efSGarrett D'Amore 1562*95c635efSGarrett D'Amore roff_setstrn(&r->strtab, name, strlen(name), string, 1563*95c635efSGarrett D'Amore string ? strlen(string) : 0, multiline); 1564*95c635efSGarrett D'Amore } 1565*95c635efSGarrett D'Amore 1566*95c635efSGarrett D'Amore static void 1567*95c635efSGarrett D'Amore roff_setstrn(struct roffkv **r, const char *name, size_t namesz, 1568*95c635efSGarrett D'Amore const char *string, size_t stringsz, int multiline) 1569*95c635efSGarrett D'Amore { 1570*95c635efSGarrett D'Amore struct roffkv *n; 1571*95c635efSGarrett D'Amore char *c; 1572*95c635efSGarrett D'Amore int i; 1573*95c635efSGarrett D'Amore size_t oldch, newch; 1574*95c635efSGarrett D'Amore 1575*95c635efSGarrett D'Amore /* Search for an existing string with the same name. */ 1576*95c635efSGarrett D'Amore n = *r; 1577*95c635efSGarrett D'Amore 1578*95c635efSGarrett D'Amore while (n && strcmp(name, n->key.p)) 1579*95c635efSGarrett D'Amore n = n->next; 1580*95c635efSGarrett D'Amore 1581*95c635efSGarrett D'Amore if (NULL == n) { 1582*95c635efSGarrett D'Amore /* Create a new string table entry. */ 1583*95c635efSGarrett D'Amore n = mandoc_malloc(sizeof(struct roffkv)); 1584*95c635efSGarrett D'Amore n->key.p = mandoc_strndup(name, namesz); 1585*95c635efSGarrett D'Amore n->key.sz = namesz; 1586*95c635efSGarrett D'Amore n->val.p = NULL; 1587*95c635efSGarrett D'Amore n->val.sz = 0; 1588*95c635efSGarrett D'Amore n->next = *r; 1589*95c635efSGarrett D'Amore *r = n; 1590*95c635efSGarrett D'Amore } else if (0 == multiline) { 1591*95c635efSGarrett D'Amore /* In multiline mode, append; else replace. */ 1592*95c635efSGarrett D'Amore free(n->val.p); 1593*95c635efSGarrett D'Amore n->val.p = NULL; 1594*95c635efSGarrett D'Amore n->val.sz = 0; 1595*95c635efSGarrett D'Amore } 1596*95c635efSGarrett D'Amore 1597*95c635efSGarrett D'Amore if (NULL == string) 1598*95c635efSGarrett D'Amore return; 1599*95c635efSGarrett D'Amore 1600*95c635efSGarrett D'Amore /* 1601*95c635efSGarrett D'Amore * One additional byte for the '\n' in multiline mode, 1602*95c635efSGarrett D'Amore * and one for the terminating '\0'. 1603*95c635efSGarrett D'Amore */ 1604*95c635efSGarrett D'Amore newch = stringsz + (multiline ? 2u : 1u); 1605*95c635efSGarrett D'Amore 1606*95c635efSGarrett D'Amore if (NULL == n->val.p) { 1607*95c635efSGarrett D'Amore n->val.p = mandoc_malloc(newch); 1608*95c635efSGarrett D'Amore *n->val.p = '\0'; 1609*95c635efSGarrett D'Amore oldch = 0; 1610*95c635efSGarrett D'Amore } else { 1611*95c635efSGarrett D'Amore oldch = n->val.sz; 1612*95c635efSGarrett D'Amore n->val.p = mandoc_realloc(n->val.p, oldch + newch); 1613*95c635efSGarrett D'Amore } 1614*95c635efSGarrett D'Amore 1615*95c635efSGarrett D'Amore /* Skip existing content in the destination buffer. */ 1616*95c635efSGarrett D'Amore c = n->val.p + (int)oldch; 1617*95c635efSGarrett D'Amore 1618*95c635efSGarrett D'Amore /* Append new content to the destination buffer. */ 1619*95c635efSGarrett D'Amore i = 0; 1620*95c635efSGarrett D'Amore while (i < (int)stringsz) { 1621*95c635efSGarrett D'Amore /* 1622*95c635efSGarrett D'Amore * Rudimentary roff copy mode: 1623*95c635efSGarrett D'Amore * Handle escaped backslashes. 1624*95c635efSGarrett D'Amore */ 1625*95c635efSGarrett D'Amore if ('\\' == string[i] && '\\' == string[i + 1]) 1626*95c635efSGarrett D'Amore i++; 1627*95c635efSGarrett D'Amore *c++ = string[i++]; 1628*95c635efSGarrett D'Amore } 1629*95c635efSGarrett D'Amore 1630*95c635efSGarrett D'Amore /* Append terminating bytes. */ 1631*95c635efSGarrett D'Amore if (multiline) 1632*95c635efSGarrett D'Amore *c++ = '\n'; 1633*95c635efSGarrett D'Amore 1634*95c635efSGarrett D'Amore *c = '\0'; 1635*95c635efSGarrett D'Amore n->val.sz = (int)(c - n->val.p); 1636*95c635efSGarrett D'Amore } 1637*95c635efSGarrett D'Amore 1638*95c635efSGarrett D'Amore static const char * 1639*95c635efSGarrett D'Amore roff_getstrn(const struct roff *r, const char *name, size_t len) 1640*95c635efSGarrett D'Amore { 1641*95c635efSGarrett D'Amore const struct roffkv *n; 1642*95c635efSGarrett D'Amore 1643*95c635efSGarrett D'Amore for (n = r->strtab; n; n = n->next) 1644*95c635efSGarrett D'Amore if (0 == strncmp(name, n->key.p, len) && 1645*95c635efSGarrett D'Amore '\0' == n->key.p[(int)len]) 1646*95c635efSGarrett D'Amore return(n->val.p); 1647*95c635efSGarrett D'Amore 1648*95c635efSGarrett D'Amore return(NULL); 1649*95c635efSGarrett D'Amore } 1650*95c635efSGarrett D'Amore 1651*95c635efSGarrett D'Amore static void 1652*95c635efSGarrett D'Amore roff_freestr(struct roffkv *r) 1653*95c635efSGarrett D'Amore { 1654*95c635efSGarrett D'Amore struct roffkv *n, *nn; 1655*95c635efSGarrett D'Amore 1656*95c635efSGarrett D'Amore for (n = r; n; n = nn) { 1657*95c635efSGarrett D'Amore free(n->key.p); 1658*95c635efSGarrett D'Amore free(n->val.p); 1659*95c635efSGarrett D'Amore nn = n->next; 1660*95c635efSGarrett D'Amore free(n); 1661*95c635efSGarrett D'Amore } 1662*95c635efSGarrett D'Amore } 1663*95c635efSGarrett D'Amore 1664*95c635efSGarrett D'Amore const struct tbl_span * 1665*95c635efSGarrett D'Amore roff_span(const struct roff *r) 1666*95c635efSGarrett D'Amore { 1667*95c635efSGarrett D'Amore 1668*95c635efSGarrett D'Amore return(r->tbl ? tbl_span(r->tbl) : NULL); 1669*95c635efSGarrett D'Amore } 1670*95c635efSGarrett D'Amore 1671*95c635efSGarrett D'Amore const struct eqn * 1672*95c635efSGarrett D'Amore roff_eqn(const struct roff *r) 1673*95c635efSGarrett D'Amore { 1674*95c635efSGarrett D'Amore 1675*95c635efSGarrett D'Amore return(r->last_eqn ? &r->last_eqn->eqn : NULL); 1676*95c635efSGarrett D'Amore } 1677*95c635efSGarrett D'Amore 1678*95c635efSGarrett D'Amore /* 1679*95c635efSGarrett D'Amore * Duplicate an input string, making the appropriate character 1680*95c635efSGarrett D'Amore * conversations (as stipulated by `tr') along the way. 1681*95c635efSGarrett D'Amore * Returns a heap-allocated string with all the replacements made. 1682*95c635efSGarrett D'Amore */ 1683*95c635efSGarrett D'Amore char * 1684*95c635efSGarrett D'Amore roff_strdup(const struct roff *r, const char *p) 1685*95c635efSGarrett D'Amore { 1686*95c635efSGarrett D'Amore const struct roffkv *cp; 1687*95c635efSGarrett D'Amore char *res; 1688*95c635efSGarrett D'Amore const char *pp; 1689*95c635efSGarrett D'Amore size_t ssz, sz; 1690*95c635efSGarrett D'Amore enum mandoc_esc esc; 1691*95c635efSGarrett D'Amore 1692*95c635efSGarrett D'Amore if (NULL == r->xmbtab && NULL == r->xtab) 1693*95c635efSGarrett D'Amore return(mandoc_strdup(p)); 1694*95c635efSGarrett D'Amore else if ('\0' == *p) 1695*95c635efSGarrett D'Amore return(mandoc_strdup("")); 1696*95c635efSGarrett D'Amore 1697*95c635efSGarrett D'Amore /* 1698*95c635efSGarrett D'Amore * Step through each character looking for term matches 1699*95c635efSGarrett D'Amore * (remember that a `tr' can be invoked with an escape, which is 1700*95c635efSGarrett D'Amore * a glyph but the escape is multi-character). 1701*95c635efSGarrett D'Amore * We only do this if the character hash has been initialised 1702*95c635efSGarrett D'Amore * and the string is >0 length. 1703*95c635efSGarrett D'Amore */ 1704*95c635efSGarrett D'Amore 1705*95c635efSGarrett D'Amore res = NULL; 1706*95c635efSGarrett D'Amore ssz = 0; 1707*95c635efSGarrett D'Amore 1708*95c635efSGarrett D'Amore while ('\0' != *p) { 1709*95c635efSGarrett D'Amore if ('\\' != *p && r->xtab && r->xtab[(int)*p].p) { 1710*95c635efSGarrett D'Amore sz = r->xtab[(int)*p].sz; 1711*95c635efSGarrett D'Amore res = mandoc_realloc(res, ssz + sz + 1); 1712*95c635efSGarrett D'Amore memcpy(res + ssz, r->xtab[(int)*p].p, sz); 1713*95c635efSGarrett D'Amore ssz += sz; 1714*95c635efSGarrett D'Amore p++; 1715*95c635efSGarrett D'Amore continue; 1716*95c635efSGarrett D'Amore } else if ('\\' != *p) { 1717*95c635efSGarrett D'Amore res = mandoc_realloc(res, ssz + 2); 1718*95c635efSGarrett D'Amore res[ssz++] = *p++; 1719*95c635efSGarrett D'Amore continue; 1720*95c635efSGarrett D'Amore } 1721*95c635efSGarrett D'Amore 1722*95c635efSGarrett D'Amore /* Search for term matches. */ 1723*95c635efSGarrett D'Amore for (cp = r->xmbtab; cp; cp = cp->next) 1724*95c635efSGarrett D'Amore if (0 == strncmp(p, cp->key.p, cp->key.sz)) 1725*95c635efSGarrett D'Amore break; 1726*95c635efSGarrett D'Amore 1727*95c635efSGarrett D'Amore if (NULL != cp) { 1728*95c635efSGarrett D'Amore /* 1729*95c635efSGarrett D'Amore * A match has been found. 1730*95c635efSGarrett D'Amore * Append the match to the array and move 1731*95c635efSGarrett D'Amore * forward by its keysize. 1732*95c635efSGarrett D'Amore */ 1733*95c635efSGarrett D'Amore res = mandoc_realloc 1734*95c635efSGarrett D'Amore (res, ssz + cp->val.sz + 1); 1735*95c635efSGarrett D'Amore memcpy(res + ssz, cp->val.p, cp->val.sz); 1736*95c635efSGarrett D'Amore ssz += cp->val.sz; 1737*95c635efSGarrett D'Amore p += (int)cp->key.sz; 1738*95c635efSGarrett D'Amore continue; 1739*95c635efSGarrett D'Amore } 1740*95c635efSGarrett D'Amore 1741*95c635efSGarrett D'Amore /* 1742*95c635efSGarrett D'Amore * Handle escapes carefully: we need to copy 1743*95c635efSGarrett D'Amore * over just the escape itself, or else we might 1744*95c635efSGarrett D'Amore * do replacements within the escape itself. 1745*95c635efSGarrett D'Amore * Make sure to pass along the bogus string. 1746*95c635efSGarrett D'Amore */ 1747*95c635efSGarrett D'Amore pp = p++; 1748*95c635efSGarrett D'Amore esc = mandoc_escape(&p, NULL, NULL); 1749*95c635efSGarrett D'Amore if (ESCAPE_ERROR == esc) { 1750*95c635efSGarrett D'Amore sz = strlen(pp); 1751*95c635efSGarrett D'Amore res = mandoc_realloc(res, ssz + sz + 1); 1752*95c635efSGarrett D'Amore memcpy(res + ssz, pp, sz); 1753*95c635efSGarrett D'Amore break; 1754*95c635efSGarrett D'Amore } 1755*95c635efSGarrett D'Amore /* 1756*95c635efSGarrett D'Amore * We bail out on bad escapes. 1757*95c635efSGarrett D'Amore * No need to warn: we already did so when 1758*95c635efSGarrett D'Amore * roff_res() was called. 1759*95c635efSGarrett D'Amore */ 1760*95c635efSGarrett D'Amore sz = (int)(p - pp); 1761*95c635efSGarrett D'Amore res = mandoc_realloc(res, ssz + sz + 1); 1762*95c635efSGarrett D'Amore memcpy(res + ssz, pp, sz); 1763*95c635efSGarrett D'Amore ssz += sz; 1764*95c635efSGarrett D'Amore } 1765*95c635efSGarrett D'Amore 1766*95c635efSGarrett D'Amore res[(int)ssz] = '\0'; 1767*95c635efSGarrett D'Amore return(res); 1768*95c635efSGarrett D'Amore } 1769