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