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