371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov/* $Id: roff.c,v 1.284 2016/01/08 17:48:10 schwarze Exp $ */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore/*
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore *
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * copyright notice and this permission notice appear in all copies.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore *
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include "config.h"
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#include <sys/types.h>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include <assert.h>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include <ctype.h>
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#include <limits.h>
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore#include <stdio.h>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include <stdlib.h>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include <string.h>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include "mandoc.h"
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#include "mandoc_aux.h"
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#include "roff.h"
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include "libmandoc.h"
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#include "roff_int.h"
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#include "libroff.h"
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore/* Maximum number of string expansions per line, to break infinite loops. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#define EXPAND_LIMIT 1000
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov/* --- data types --------------------------------------------------------- */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreenum rofft {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_ab,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_ad,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_af,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_aln,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_als,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_am,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_am1,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_ami,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_ami1,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_as,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_as1,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_asciify,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_backtrace,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_bd,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_bleedat,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_blm,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_box,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_boxa,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_bp,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_BP,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* MAN_br, MDOC_br */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_break,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_breakchar,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_brnl,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_brp,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_brpnl,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_c2,
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore ROFF_cc,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_ce,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_cf,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_cflags,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_ch,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_char,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_chop,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_class,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_close,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_CL,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_color,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_composite,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_continue,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_cp,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_cropat,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_cs,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_cu,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_da,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_dch,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_Dd,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_de,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_de1,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_defcolor,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_dei,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_dei1,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_device,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_devicem,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_di,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_do,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_ds,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_ds1,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_dwh,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_dt,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_ec,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_ecr,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_ecs,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_el,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_em,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_EN,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_eo,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_EP,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_EQ,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_errprint,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_ev,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_evc,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_ex,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_fallback,
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore ROFF_fam,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_fc,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_fchar,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_fcolor,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_fdeferlig,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_feature,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* MAN_fi; ignored in mdoc(7) */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_fkern,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_fl,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_flig,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_fp,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_fps,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_fschar,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_fspacewidth,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_fspecial,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* MAN_ft; ignored in mdoc(7) */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_ftr,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_fzoom,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_gcolor,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_hc,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_hcode,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_hidechar,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_hla,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_hlm,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_hpf,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_hpfa,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_hpfcode,
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore ROFF_hw,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_hy,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_hylang,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_hylen,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_hym,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_hypp,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_hys,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_ie,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_if,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_ig,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* MAN_in; ignored in mdoc(7) */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_index,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_it,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_itc,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_IX,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_kern,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_kernafter,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_kernbefore,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_kernpair,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_lc,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_lc_ctype,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_lds,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_length,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_letadj,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_lf,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_lg,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_lhang,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_linetabs,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* MAN_ll, MDOC_ll */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_lnr,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_lnrf,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_lpfx,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_ls,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_lsm,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_lt,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_mc,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_mediasize,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_minss,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_mk,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_mso,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_na,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_ne,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* MAN_nf; ignored in mdoc(7) */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_nh,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_nhychar,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_nm,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_nn,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_nop,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_nr,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_nrf,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_nroff,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_ns,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_nx,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_open,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_opena,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_os,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_output,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_padj,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_papersize,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_pc,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_pev,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_pi,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_PI,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_pl,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_pm,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_pn,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_pnr,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_po,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_ps,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_psbb,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_pshape,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_pso,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_ptr,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_pvs,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_rchar,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_rd,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_recursionlimit,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_return,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_rfschar,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_rhang,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_rj,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_rm,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_rn,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_rnn,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_rr,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_rs,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_rt,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_schar,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_sentchar,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_shc,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_shift,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_sizes,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_so,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* MAN_sp, MDOC_sp */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_spacewidth,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_special,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_spreadwarn,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_ss,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_sty,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_substring,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_sv,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_sy,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_T_,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_ta,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_tc,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_TE,
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore ROFF_TH,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_ti,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_tkf,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_tl,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_tm,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_tm1,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_tmc,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_tr,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_track,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_transchar,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_trf,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_trimat,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_trin,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_trnt,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_troff,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_TS,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_uf,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_ul,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_unformat,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_unwatch,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_unwatchn,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_vpt,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_vs,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_warn,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_warnscale,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_watch,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_watchlength,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_watchn,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_wh,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_while,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_write,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_writec,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_writem,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_xflag,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_cblock,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_USERDEF,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ROFF_MAX
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore};
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore/*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * An incredibly-simple string buffer.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestruct roffstr {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore char *p; /* nil-terminated buffer */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore size_t sz; /* saved strlen(p) */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore};
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore/*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * A key-value roffstr pair as part of a singly-linked list.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestruct roffkv {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct roffstr key;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct roffstr val;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct roffkv *next; /* next in list */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore};
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore/*
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * A single number register as part of a singly-linked list.
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amorestruct roffreg {
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore struct roffstr key;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore int val;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore struct roffreg *next;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore};
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestruct roff {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct mparse *parse; /* parse point */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct roffnode *last; /* leaf of stack */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int *rstack; /* stack of inverted `ie' values */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore struct roffreg *regtab; /* number registers */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct roffkv *strtab; /* user-defined strings & macros */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct roffkv *xmbtab; /* multi-byte trans table (`tr') */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct roffstr *xtab; /* single-byte trans table (`tr') */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const char *current_string; /* value of last called user macro */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct tbl_node *first_tbl; /* first table parsed */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct tbl_node *last_tbl; /* last table parsed */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct tbl_node *tbl; /* current table being parsed */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct eqn_node *last_eqn; /* last equation parsed */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct eqn_node *first_eqn; /* first equation parsed */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct eqn_node *eqn; /* current equation being parsed */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int eqn_inline; /* current equation is inline */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int options; /* parse options */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int rstacksz; /* current size limit of rstack */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int rstackpos; /* position in rstack */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int format; /* current file in mdoc or man format */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov int argc; /* number of args of the last macro */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov char control; /* control character */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore};
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestruct roffnode {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore enum rofft tok; /* type of node */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct roffnode *parent; /* up one in stack */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore int line; /* parse line */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore int col; /* parse col */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore char *name; /* node name, e.g. macro name */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore char *end; /* end-rules: custom token */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore int endspan; /* end-rules: next-line or infty */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int rule; /* current evaluation rule */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore};
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#define ROFF_ARGS struct roff *r, /* parse ctx */ \
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore enum rofft tok, /* tok of macro */ \
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov struct buf *buf, /* input buffer */ \
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore int ln, /* parse line */ \
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore int ppos, /* original pos in buffer */ \
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore int pos, /* current pos in buffer */ \
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore int *offs /* reset offset of buffer data */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoretypedef enum rofferr (*roffproc)(ROFF_ARGS);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestruct roffmac {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const char *name; /* macro name */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore roffproc proc; /* process new macro */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore roffproc text; /* process as child text of macro */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore roffproc sub; /* process as child of macro */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore int flags;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#define ROFFMAC_STRUCT (1 << 0) /* always interpret */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct roffmac *next;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore};
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestruct predef {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const char *name; /* predefined input name */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const char *str; /* replacement symbol */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore};
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#define PREDEF(__name, __str) \
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { (__name), (__str) },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov/* --- function prototypes ------------------------------------------------ */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofft roffhash_find(const char *, size_t);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void roffhash_init(void);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void roffnode_cleanscope(struct roff *);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void roffnode_pop(struct roff *);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void roffnode_push(struct roff *, enum rofft,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const char *, int, int);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr roff_block(ROFF_ARGS);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr roff_block_text(ROFF_ARGS);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr roff_block_sub(ROFF_ARGS);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic enum rofferr roff_brp(ROFF_ARGS);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr roff_cblock(ROFF_ARGS);
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amorestatic enum rofferr roff_cc(ROFF_ARGS);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic void roff_ccond(struct roff *, int, int);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr roff_cond(ROFF_ARGS);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr roff_cond_text(ROFF_ARGS);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr roff_cond_sub(ROFF_ARGS);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr roff_ds(ROFF_ARGS);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic enum rofferr roff_eqndelim(struct roff *, struct buf *, int);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic int roff_evalcond(struct roff *r, int, char *, int *);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic int roff_evalnum(struct roff *, int,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char *, int *, int *, int);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic int roff_evalpar(struct roff *, int,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char *, int *, int *, int);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic int roff_evalstrcond(const char *, int *);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void roff_free1(struct roff *);
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amorestatic void roff_freereg(struct roffreg *);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void roff_freestr(struct roffkv *);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic size_t roff_getname(struct roff *, char **, int, int);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic int roff_getnum(const char *, int *, int *, int);
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amorestatic int roff_getop(const char *, int *, char *);
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amorestatic int roff_getregn(const struct roff *,
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore const char *, size_t);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic int roff_getregro(const struct roff *,
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov const char *name);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic const char *roff_getstrn(const struct roff *,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const char *, size_t);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic int roff_hasregn(const struct roff *,
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov const char *, size_t);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic enum rofferr roff_insec(ROFF_ARGS);
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amorestatic enum rofferr roff_it(ROFF_ARGS);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr roff_line_ignore(ROFF_ARGS);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic void roff_man_alloc1(struct roff_man *);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic void roff_man_free1(struct roff_man *);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr roff_nr(ROFF_ARGS);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic enum rofft roff_parse(struct roff *, char *, int *,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int, int);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic enum rofferr roff_parsetext(struct buf *, int, int *);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic enum rofferr roff_res(struct roff *, struct buf *, int, int);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr roff_rm(ROFF_ARGS);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic enum rofferr roff_rr(ROFF_ARGS);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void roff_setstr(struct roff *,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const char *, const char *, int);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic void roff_setstrn(struct roffkv **, const char *,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore size_t, const char *, size_t, int);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr roff_so(ROFF_ARGS);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr roff_tr(ROFF_ARGS);
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amorestatic enum rofferr roff_Dd(ROFF_ARGS);
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amorestatic enum rofferr roff_TH(ROFF_ARGS);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr roff_TE(ROFF_ARGS);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr roff_TS(ROFF_ARGS);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr roff_EQ(ROFF_ARGS);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr roff_EN(ROFF_ARGS);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr roff_T_(ROFF_ARGS);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic enum rofferr roff_unsupp(ROFF_ARGS);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr roff_userdef(ROFF_ARGS);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov/* --- constant data ------------------------------------------------------ */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore/* See roffhash_find() */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#define ASCII_HI 126
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#define ASCII_LO 33
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#define HASHWIDTH (ASCII_HI - ASCII_LO + 1)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#define ROFFNUM_SCALE (1 << 0) /* Honour scaling in roff_getnum(). */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#define ROFFNUM_WHITE (1 << 1) /* Skip whitespace in roff_evalnum(). */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic struct roffmac *hash[HASHWIDTH];
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic struct roffmac roffs[ROFF_MAX] = {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "ab", roff_unsupp, NULL, NULL, 0, NULL },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { "ad", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "af", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "aln", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "als", roff_unsupp, NULL, NULL, 0, NULL },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { "am", roff_block, roff_block_text, roff_block_sub, 0, NULL },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "ami1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "as", roff_ds, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "as1", roff_ds, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "asciify", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "backtrace", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "bd", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "bleedat", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "blm", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "box", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "boxa", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "bp", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "BP", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "break", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "breakchar", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "brnl", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "brp", roff_brp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "brpnl", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "c2", roff_unsupp, NULL, NULL, 0, NULL },
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { "cc", roff_cc, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "ce", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "cf", roff_insec, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "cflags", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "ch", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "char", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "chop", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "class", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "close", roff_insec, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "CL", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "color", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "composite", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "continue", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "cp", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "cropat", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "cs", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "cu", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "da", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "dch", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "Dd", roff_Dd, NULL, NULL, 0, NULL },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { "de", roff_block, roff_block_text, roff_block_sub, 0, NULL },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "defcolor", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "dei1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "device", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "devicem", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "di", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "do", roff_unsupp, NULL, NULL, 0, NULL },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { "ds", roff_ds, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "ds1", roff_ds, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "dwh", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "dt", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "ec", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "ecr", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "ecs", roff_unsupp, NULL, NULL, 0, NULL },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "em", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "EN", roff_EN, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "eo", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "EP", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "EQ", roff_EQ, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "errprint", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "ev", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "evc", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "ex", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "fallback", roff_line_ignore, NULL, NULL, 0, NULL },
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { "fam", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "fc", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "fchar", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "fcolor", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "fdeferlig", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "feature", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "fkern", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "fl", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "flig", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "fp", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "fps", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "fschar", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "fspacewidth", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "fspecial", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "ftr", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "fzoom", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "gcolor", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "hc", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "hcode", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "hidechar", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "hla", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "hlm", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "hpf", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "hpfa", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "hpfcode", roff_line_ignore, NULL, NULL, 0, NULL },
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { "hw", roff_line_ignore, NULL, NULL, 0, NULL },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { "hy", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "hylang", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "hylen", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "hym", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "hypp", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "hys", roff_line_ignore, NULL, NULL, 0, NULL },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "index", roff_unsupp, NULL, NULL, 0, NULL },
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { "it", roff_it, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "itc", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "IX", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "kern", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "kernafter", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "kernbefore", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "kernpair", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "lc", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "lc_ctype", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "lds", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "length", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "letadj", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "lf", roff_insec, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "lg", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "lhang", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "linetabs", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "lnr", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "lnrf", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "lpfx", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "ls", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "lsm", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "lt", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "mc", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "mediasize", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "minss", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "mk", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "mso", roff_insec, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "na", roff_line_ignore, NULL, NULL, 0, NULL },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { "ne", roff_line_ignore, NULL, NULL, 0, NULL },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { "nh", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "nhychar", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "nm", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "nn", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "nop", roff_unsupp, NULL, NULL, 0, NULL },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { "nr", roff_nr, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "nrf", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "nroff", roff_line_ignore, NULL, NULL, 0, NULL },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { "ns", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "nx", roff_insec, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "open", roff_insec, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "opena", roff_insec, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "os", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "output", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "padj", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "papersize", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "pc", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "pev", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "pi", roff_insec, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "PI", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "pl", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "pm", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "pn", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "pnr", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "po", roff_line_ignore, NULL, NULL, 0, NULL },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { "ps", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "psbb", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "pshape", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "pso", roff_insec, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "ptr", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "pvs", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "rchar", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "rd", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "recursionlimit", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "return", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "rfschar", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "rhang", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "rj", roff_line_ignore, NULL, NULL, 0, NULL },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { "rm", roff_rm, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "rn", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "rnn", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "rr", roff_rr, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "rs", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "rt", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "schar", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "sentchar", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "shc", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "shift", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "sizes", roff_line_ignore, NULL, NULL, 0, NULL },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { "so", roff_so, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "spacewidth", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "special", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "spreadwarn", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "ss", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "sty", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "substring", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "sv", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "sy", roff_insec, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "T&", roff_T_, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "ta", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "tc", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "TE", roff_TE, NULL, NULL, 0, NULL },
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { "TH", roff_TH, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "ti", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "tkf", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "tl", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "tm", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "tm1", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "tmc", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "tr", roff_tr, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "track", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "transchar", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "trf", roff_insec, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "trimat", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "trin", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "trnt", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "troff", roff_line_ignore, NULL, NULL, 0, NULL },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { "TS", roff_TS, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "uf", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "ul", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "unformat", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "unwatch", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "unwatchn", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "vpt", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "vs", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "warn", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "warnscale", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "watch", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "watchlength", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "watchn", roff_line_ignore, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "wh", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "while", roff_unsupp, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "write", roff_insec, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "writec", roff_insec, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "writem", roff_insec, NULL, NULL, 0, NULL },
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { "xflag", roff_line_ignore, NULL, NULL, 0, NULL },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { ".", roff_cblock, NULL, NULL, 0, NULL },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { NULL, roff_userdef, NULL, NULL, 0, NULL },
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore};
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov/* not currently implemented: Ds em Eq LP Me PP pp Or Rd Sf SH */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amoreconst char *const __mdoc_reserved[] = {
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore "Ac", "Ad", "An", "Ao", "Ap", "Aq", "Ar", "At",
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore "Bc", "Bd", "Bf", "Bk", "Bl", "Bo", "Bq",
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore "Brc", "Bro", "Brq", "Bsx", "Bt", "Bx",
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore "Cd", "Cm", "Db", "Dc", "Dd", "Dl", "Do", "Dq",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "Dt", "Dv", "Dx", "D1",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "Ec", "Ed", "Ef", "Ek", "El", "Em",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "En", "Eo", "Er", "Es", "Ev", "Ex",
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore "Fa", "Fc", "Fd", "Fl", "Fn", "Fo", "Fr", "Ft", "Fx",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "Hf", "Ic", "In", "It", "Lb", "Li", "Lk", "Lp",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "Ms", "Mt", "Nd", "Nm", "No", "Ns", "Nx",
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore "Oc", "Oo", "Op", "Os", "Ot", "Ox",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "Pa", "Pc", "Pf", "Po", "Pp", "Pq",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "Qc", "Ql", "Qo", "Qq", "Re", "Rs", "Rv",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "Sc", "Sh", "Sm", "So", "Sq",
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore "Ss", "St", "Sx", "Sy",
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore "Ta", "Tn", "Ud", "Ux", "Va", "Vt", "Xc", "Xo", "Xr",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "%A", "%B", "%C", "%D", "%I", "%J", "%N", "%O",
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore "%P", "%Q", "%R", "%T", "%U", "%V",
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore NULL
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore};
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov/* not currently implemented: BT DE DS ME MT PT SY TQ YS */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amoreconst char *const __man_reserved[] = {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "AT", "B", "BI", "BR", "DT",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "EE", "EN", "EQ", "EX", "HP", "I", "IB", "IP", "IR",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "LP", "OP", "P", "PD", "PP",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "R", "RB", "RE", "RI", "RS", "SB", "SH", "SM", "SS",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "TE", "TH", "TP", "TS", "T&", "UC", "UE", "UR",
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore NULL
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore};
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore/* Array of injected predefined strings. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#define PREDEFS_MAX 38
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic const struct predef predefs[PREDEFS_MAX] = {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include "predefs.in"
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore};
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore/* See roffhash_find() */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#define ROFF_HASH(p) (p[0] - ASCII_LO)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amorestatic int roffit_lines; /* number of lines to delay */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amorestatic char *roffit_macro; /* nil-terminated macro line */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov/* --- request table ------------------------------------------------------ */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroffhash_init(void)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct roffmac *n;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore int buc, i;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore for (i = 0; i < (int)ROFF_USERDEF; i++) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore assert(roffs[i].name[0] >= ASCII_LO);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore assert(roffs[i].name[0] <= ASCII_HI);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore buc = ROFF_HASH(roffs[i].name);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (NULL != (n = hash[buc])) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore for ( ; n->next; n = n->next)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Do nothing. */ ;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore n->next = &roffs[i];
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore } else
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore hash[buc] = &roffs[i];
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore/*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Look up a roff token by its name. Returns ROFF_MAX if no macro by
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * the nil-terminated string name could be found.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofft
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroffhash_find(const char *p, size_t s)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore int buc;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct roffmac *n;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * libroff has an extremely simple hashtable, for the time
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * being, which simply keys on the first character, which must
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * be printable, then walks a chain. It works well enough until
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * optimised.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (p[0] < ASCII_LO || p[0] > ASCII_HI)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_MAX;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore buc = ROFF_HASH(p);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (NULL == (n = hash[buc]))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_MAX;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore for ( ; n; n = n->next)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (0 == strncmp(n->name, p, s) && '\0' == n->name[(int)s])
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return (enum rofft)(n - roffs);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_MAX;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov/* --- stack of request blocks -------------------------------------------- */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore/*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Pop the current node off of the stack of roff instructions currently
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * pending.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroffnode_pop(struct roff *r)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct roffnode *p;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore assert(r->last);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov p = r->last;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore r->last = r->last->parent;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore free(p->name);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore free(p->end);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore free(p);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore/*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Push a roff node onto the instruction stack. This must later be
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * removed with roffnode_pop().
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroffnode_push(struct roff *r, enum rofft tok, const char *name,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore int line, int col)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct roffnode *p;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore p = mandoc_calloc(1, sizeof(struct roffnode));
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore p->tok = tok;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (name)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore p->name = mandoc_strdup(name);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore p->parent = r->last;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore p->line = line;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore p->col = col;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov p->rule = p->parent ? p->parent->rule : 0;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore r->last = p;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov/* --- roff parser state data management ---------------------------------- */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_free1(struct roff *r)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore struct tbl_node *tbl;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct eqn_node *e;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore int i;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore while (NULL != (tbl = r->first_tbl)) {
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore r->first_tbl = tbl->next;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore tbl_free(tbl);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore r->first_tbl = r->last_tbl = r->tbl = NULL;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore while (NULL != (e = r->first_eqn)) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore r->first_eqn = e->next;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore eqn_free(e);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore r->first_eqn = r->last_eqn = r->eqn = NULL;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore while (r->last)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore roffnode_pop(r);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov free (r->rstack);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->rstack = NULL;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->rstacksz = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->rstackpos = -1;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore roff_freereg(r->regtab);
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore r->regtab = NULL;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov roff_freestr(r->strtab);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov roff_freestr(r->xmbtab);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->strtab = r->xmbtab = NULL;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (r->xtab)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore for (i = 0; i < 128; i++)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore free(r->xtab[i].p);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore free(r->xtab);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore r->xtab = NULL;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorevoid
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_reset(struct roff *r)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore roff_free1(r);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->format = r->options & (MPARSE_MDOC | MPARSE_MAN);
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore r->control = 0;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorevoid
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_free(struct roff *r)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore roff_free1(r);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore free(r);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestruct roff *
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovroff_alloc(struct mparse *parse, int options)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct roff *r;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore r = mandoc_calloc(1, sizeof(struct roff));
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore r->parse = parse;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->options = options;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->format = options & (MPARSE_MDOC | MPARSE_MAN);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore r->rstackpos = -1;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov roffhash_init();
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return r;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov}
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov/* --- syntax tree state data management ---------------------------------- */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic void
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovroff_man_free1(struct roff_man *man)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (man->first != NULL)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_node_delete(man, man->first);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov free(man->meta.msec);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov free(man->meta.vol);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov free(man->meta.os);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov free(man->meta.arch);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov free(man->meta.title);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov free(man->meta.name);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov free(man->meta.date);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov}
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic void
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovroff_man_alloc1(struct roff_man *man)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov memset(&man->meta, 0, sizeof(man->meta));
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->first = mandoc_calloc(1, sizeof(*man->first));
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->first->type = ROFFT_ROOT;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->last = man->first;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->last_es = NULL;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->flags = 0;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->macroset = MACROSET_NONE;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->lastsec = man->lastnamed = SEC_NONE;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->next = ROFF_NEXT_CHILD;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov}
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovvoid
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovroff_man_reset(struct roff_man *man)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_man_free1(man);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_man_alloc1(man);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov}
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovvoid
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovroff_man_free(struct roff_man *man)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_man_free1(man);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov free(man);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov}
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstruct roff_man *
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovroff_man_alloc(struct roff *roff, struct mparse *parse,
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov const char *defos, int quick)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_man *man;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man = mandoc_calloc(1, sizeof(*man));
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->parse = parse;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->roff = roff;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->defos = defos;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->quick = quick;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_man_alloc1(man);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return man;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov}
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov/* --- syntax tree handling ----------------------------------------------- */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstruct roff_node *
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovroff_node_alloc(struct roff_man *man, int line, int pos,
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov enum roff_type type, int tok)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n = mandoc_calloc(1, sizeof(*n));
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->line = line;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->pos = pos;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->tok = tok;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->type = type;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->sec = man->lastsec;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (man->flags & MDOC_SYNOPSIS)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->flags |= MDOC_SYNPRETTY;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov else
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->flags &= ~MDOC_SYNPRETTY;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (man->flags & MDOC_NEWLINE)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->flags |= MDOC_LINE;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->flags &= ~MDOC_NEWLINE;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov}
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovvoid
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovroff_node_append(struct roff_man *man, struct roff_node *n)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov switch (man->next) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case ROFF_NEXT_SIBLING:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (man->last->next != NULL) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->next = man->last->next;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->last->next->prev = n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov } else
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->last->parent->last = n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->last->next = n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->prev = man->last;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->parent = man->last->parent;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov break;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case ROFF_NEXT_CHILD:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->last->child = n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->parent = man->last;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->parent->last = n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov break;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov default:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov abort();
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->last = n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov switch (n->type) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case ROFFT_HEAD:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->parent->head = n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov break;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case ROFFT_BODY:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (n->end != ENDBODY_NOT)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->parent->body = n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov break;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case ROFFT_TAIL:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->parent->tail = n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov break;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov default:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov /*
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * Copy over the normalised-data pointer of our parent. Not
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * everybody has one, but copying a null pointer is fine.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->norm = n->parent->norm;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov assert(n->parent->type == ROFFT_BLOCK);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov}
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovvoid
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovroff_word_alloc(struct roff_man *man, int line, int pos, const char *word)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n = roff_node_alloc(man, line, pos, ROFFT_TEXT, TOKEN_NONE);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->string = roff_strdup(man->roff, word);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_node_append(man, n);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (man->macroset == MACROSET_MDOC)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->flags |= MDOC_VALID | MDOC_ENDED;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov else
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->flags |= MAN_VALID;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->next = ROFF_NEXT_SIBLING;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov}
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovvoid
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovroff_word_append(struct roff_man *man, const char *word)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov char *addstr, *newstr;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n = man->last;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov addstr = roff_strdup(man->roff, word);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov mandoc_asprintf(&newstr, "%s %s", n->string, addstr);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov free(addstr);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov free(n->string);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->string = newstr;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->next = ROFF_NEXT_SIBLING;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov}
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovvoid
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovroff_elem_alloc(struct roff_man *man, int line, int pos, int tok)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n = roff_node_alloc(man, line, pos, ROFFT_ELEM, tok);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_node_append(man, n);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->next = ROFF_NEXT_CHILD;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov}
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstruct roff_node *
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovroff_block_alloc(struct roff_man *man, int line, int pos, int tok)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n = roff_node_alloc(man, line, pos, ROFFT_BLOCK, tok);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_node_append(man, n);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->next = ROFF_NEXT_CHILD;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov}
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstruct roff_node *
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovroff_head_alloc(struct roff_man *man, int line, int pos, int tok)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n = roff_node_alloc(man, line, pos, ROFFT_HEAD, tok);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_node_append(man, n);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->next = ROFF_NEXT_CHILD;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov}
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstruct roff_node *
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovroff_body_alloc(struct roff_man *man, int line, int pos, int tok)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n = roff_node_alloc(man, line, pos, ROFFT_BODY, tok);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_node_append(man, n);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->next = ROFF_NEXT_CHILD;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov}
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovvoid
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovroff_addeqn(struct roff_man *man, const struct eqn *eqn)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n = roff_node_alloc(man, eqn->ln, eqn->pos, ROFFT_EQN, TOKEN_NONE);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->eqn = eqn;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (eqn->ln > man->last->line)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->flags |= MDOC_LINE;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_node_append(man, n);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->next = ROFF_NEXT_SIBLING;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov}
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovvoid
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovroff_addtbl(struct roff_man *man, const struct tbl_span *tbl)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (man->macroset == MACROSET_MAN)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man_breakscope(man, TOKEN_NONE);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n = roff_node_alloc(man, tbl->line, 0, ROFFT_TBL, TOKEN_NONE);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->span = tbl;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_node_append(man, n);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (man->macroset == MACROSET_MDOC)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->flags |= MDOC_VALID | MDOC_ENDED;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov else
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->flags |= MAN_VALID;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->next = ROFF_NEXT_SIBLING;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov}
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovvoid
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovroff_node_unlink(struct roff_man *man, struct roff_node *n)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov /* Adjust siblings. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (n->prev)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->prev->next = n->next;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (n->next)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->next->prev = n->prev;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov /* Adjust parent. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (n->parent != NULL) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (n->parent->child == n)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->parent->child = n->next;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (n->parent->last == n)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->parent->last = n->prev;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov /* Adjust parse point. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (man == NULL)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (man->last == n) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (n->prev == NULL) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->last = n->parent;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->next = ROFF_NEXT_CHILD;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov } else {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->last = n->prev;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->next = ROFF_NEXT_SIBLING;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (man->first == n)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->first = NULL;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov}
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovvoid
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovroff_node_free(struct roff_node *n)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (n->args != NULL)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov mdoc_argv_free(n->args);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (n->type == ROFFT_BLOCK || n->type == ROFFT_ELEM)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov free(n->norm);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov free(n->string);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov free(n);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov}
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovvoid
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovroff_node_delete(struct roff_man *man, struct roff_node *n)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov while (n->child != NULL)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_node_delete(man, n->child);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_node_unlink(man, n);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_node_free(n);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovvoid
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovderoff(char **dest, const struct roff_node *n)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov char *cp;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov size_t sz;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (n->type != ROFFT_TEXT) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov for (n = n->child; n != NULL; n = n->next)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov deroff(dest, n);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov /* Skip leading whitespace and escape sequences. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov cp = n->string;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov while (*cp != '\0') {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if ('\\' == *cp) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov cp++;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov mandoc_escape((const char **)&cp, NULL, NULL);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov } else if (isspace((unsigned char)*cp))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov cp++;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov else
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov break;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov /* Skip trailing whitespace. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov for (sz = strlen(cp); sz; sz--)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if ( ! isspace((unsigned char)cp[sz-1]))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov break;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov /* Skip empty strings. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (sz == 0)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (*dest == NULL) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov *dest = mandoc_strndup(cp, sz);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov free(*dest);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov *dest = cp;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov}
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov/* --- main functions of the roff parser ---------------------------------- */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore/*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * In the current line, expand escape sequences that tend to get
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * used in numerical expressions and conditional requests.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Also check the syntax of the remaining escape sequences.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovroff_res(struct roff *r, struct buf *buf, int ln, int pos)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov char ubuf[24]; /* buffer to print the number */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char *start; /* start of the string to process */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov char *stesc; /* start of an escape sequence ('\\') */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const char *stnam; /* start of the name, after "[(*" */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const char *cp; /* end of the name, e.g. before ']' */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const char *res; /* the string to be substituted */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov char *nbuf; /* new buffer to copy buf->buf to */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore size_t maxl; /* expected length of the escape name */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore size_t naml; /* actual length of the escape name */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov enum mandoc_esc esc; /* type of the escape sequence */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int inaml; /* length returned from mandoc_escape() */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore int expand_count; /* to avoid infinite loops */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int npos; /* position in numeric expression */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int arg_complete; /* argument not interrupted by eol */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov char term; /* character terminating the escape */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore expand_count = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov start = buf->buf + pos;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov stesc = strchr(start, '\0') - 1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (stesc-- > start) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Search backwards for the next backslash. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*stesc != '\\')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov continue;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* If it is escaped, skip it. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov for (cp = stesc - 1; cp >= start; cp--)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*cp != '\\')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ((stesc - cp) % 2 == 0) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov stesc = (char *)cp;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov continue;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Decide whether to expand or to check only. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov term = '\0';
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov cp = stesc + 1;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore switch (*cp) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '*':
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore res = NULL;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'B':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'w':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov term = cp[1];
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* FALLTHROUGH */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'n':
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore res = ubuf;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore break;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore default:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov esc = mandoc_escape(&cp, &stnam, &inaml);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (esc == ESCAPE_ERROR ||
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (esc == ESCAPE_SPECIAL &&
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov mchars_spec2cp(stnam, inaml) < 0))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_vmsg(MANDOCERR_ESC_BAD,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->parse, ln, (int)(stesc - buf->buf),
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "%.*s", (int)(cp - stesc), stesc);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov continue;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (EXPAND_LIMIT < ++expand_count) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, (int)(stesc - buf->buf), NULL);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * The third character decides the length
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * of the name of the string or register.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Save a pointer to the name.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (term == '\0') {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov switch (*++cp) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '\0':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov maxl = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '(':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov cp++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov maxl = 2;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '[':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov cp++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov term = ']';
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov maxl = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov default:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov maxl = 1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov cp += 2;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore maxl = 0;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore stnam = cp;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Advance to the end of the name. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov naml = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov arg_complete = 1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (maxl == 0 || naml < maxl) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*cp == '\0') {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_ESC_BAD, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, (int)(stesc - buf->buf), stesc);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov arg_complete = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (maxl == 0 && *cp == term) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov cp++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*cp++ != '\\' || stesc[1] != 'w') {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov naml++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov continue;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov switch (mandoc_escape(&cp, NULL, NULL)) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case ESCAPE_SPECIAL:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case ESCAPE_UNICODE:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case ESCAPE_NUMBERED:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case ESCAPE_OVERSTRIKE:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov naml++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov default:
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Retrieve the replacement string; if it is
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * undefined, resume searching for escapes.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov switch (stesc[1]) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '*':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (arg_complete)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov res = roff_getstrn(r, stnam, naml);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'B':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov npos = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ubuf[0] = arg_complete &&
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov roff_evalnum(r, ln, stnam, &npos,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov NULL, ROFFNUM_SCALE) &&
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov stnam + npos + 1 == cp ? '1' : '0';
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ubuf[1] = '\0';
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'n':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (arg_complete)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (void)snprintf(ubuf, sizeof(ubuf), "%d",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov roff_getregn(r, stnam, naml));
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ubuf[0] = '\0';
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'w':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* use even incomplete args */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (void)snprintf(ubuf, sizeof(ubuf), "%d",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov 24 * (int)naml);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (res == NULL) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_vmsg(MANDOCERR_STR_UNDEF,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->parse, ln, (int)(stesc - buf->buf),
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "%.*s", (int)naml, stnam);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore res = "";
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else if (buf->sz + strlen(res) > SHRT_MAX) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, (int)(stesc - buf->buf), NULL);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Replace the escape sequence by the string. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *stesc = '\0';
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov buf->sz = mandoc_asprintf(&nbuf, "%s%s%s",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov buf->buf, res, cp) + 1;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Prepare for the next replacement. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov start = nbuf + pos;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov stesc = nbuf + (stesc - buf->buf) + strlen(res);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov free(buf->buf);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov buf->buf = nbuf;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_CONT;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore/*
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * Process text streams.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovroff_parsetext(struct buf *buf, int pos, int *offs)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore size_t sz;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const char *start;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore char *p;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore int isz;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore enum mandoc_esc esc;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov /* Spring the input line trap. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (roffit_lines == 1) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov isz = mandoc_asprintf(&p, "%s\n.%s", buf->buf, roffit_macro);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov free(buf->buf);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov buf->buf = p;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov buf->sz = isz + 1;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov *offs = 0;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov free(roffit_macro);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roffit_lines = 0;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_REPARSE;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov } else if (roffit_lines > 1)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov --roffit_lines;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov /* Convert all breakable hyphens into ASCII_HYPH. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov start = p = buf->buf + pos;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (*p != '\0') {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore sz = strcspn(p, "-\\");
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore p += sz;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*p == '\0')
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*p == '\\') {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Skip over escapes. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore p++;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore esc = mandoc_escape((const char **)&p, NULL, NULL);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (esc == ESCAPE_ERROR)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov while (*p == '-')
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov p++;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore continue;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore } else if (p == start) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore p++;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore continue;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (isalpha((unsigned char)p[-1]) &&
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore isalpha((unsigned char)p[1]))
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore *p = ASCII_HYPH;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore p++;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_CONT;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreenum rofferr
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovroff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore enum rofft t;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore enum rofferr e;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int pos; /* parse point */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int spos; /* saved parse point for messages */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int ppos; /* original offset in buf->buf */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int ctl; /* macro line (boolean) */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ppos = pos = *offs;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Handle in-line equation delimiters. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (r->tbl == NULL &&
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->last_eqn != NULL && r->last_eqn->delim &&
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (r->eqn == NULL || r->eqn_inline)) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov e = roff_eqndelim(r, buf, pos);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (e == ROFF_REPARSE)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return e;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov assert(e == ROFF_CONT);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Expand some escape sequences. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov e = roff_res(r, buf, ln, pos);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (e == ROFF_IGN)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return e;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov assert(e == ROFF_CONT);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ctl = roff_getcontrol(r, buf->buf, &pos);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * First, if a scope is open and we're not a macro, pass the
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * text through the macro's filter.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Equations process all content themselves.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Tables process almost all content themselves, but we want
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * to warn about macros before passing it there.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (r->last != NULL && ! ctl) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore t = r->last->tok;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore assert(roffs[t].text);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov e = (*roffs[t].text)(r, t, buf, ln, pos, pos, offs);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov assert(e == ROFF_IGN || e == ROFF_CONT);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (e != ROFF_CONT)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return e;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (r->eqn != NULL)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return eqn_read(&r->eqn, ln, buf->buf, ppos, offs);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (r->tbl != NULL && ( ! ctl || buf->buf[pos] == '\0'))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return tbl_read(r->tbl, ln, buf->buf, ppos);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ( ! ctl)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return roff_parsetext(buf, pos, offs);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Skip empty request lines. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (buf->buf[pos] == '"') {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_COMMENT_BAD, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, pos, NULL);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else if (buf->buf[pos] == '\0')
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If a scope is open, go to the child handler for that macro,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * as it may want to preprocess before doing anything with it.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Don't do so if an equation is open.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (r->last) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore t = r->last->tok;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore assert(roffs[t].sub);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return (*roffs[t].sub)(r, t, buf, ln, ppos, pos, offs);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* No scope is open. This is a new request or macro. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov spos = pos;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov t = roff_parse(r, buf->buf, &pos, ln, ppos);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Tables ignore most macros. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (r->tbl != NULL && (t == ROFF_MAX || t == ROFF_TS)) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_TBLMACRO, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, pos, buf->buf + spos);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (t == ROFF_TS)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (buf->buf[pos] != '\0' && buf->buf[pos] != ' ')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov pos++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (buf->buf[pos] != '\0' && buf->buf[pos] == ' ')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov pos++;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return tbl_read(r->tbl, ln, buf->buf, pos);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * This is neither a roff request nor a user-defined macro.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Let the standard macro set parsers handle it.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (t == ROFF_MAX)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_CONT;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Execute a roff request or a user defined macro. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore assert(roffs[t].proc);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorevoid
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_endparse(struct roff *r)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (r->last)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_BLK_NOEND, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->last->line, r->last->col,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov roffs[r->last->tok].name);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (r->eqn) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_BLK_NOEND, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->eqn->eqn.ln, r->eqn->eqn.pos, "EQ");
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore eqn_end(&r->eqn);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (r->tbl) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_BLK_NOEND, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->tbl->line, r->tbl->pos, "TS");
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore tbl_end(&r->tbl);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore/*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Parse a roff node's type from the input buffer. This must be in the
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * form of ".foo xxx" in the usual way.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofft
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovroff_parse(struct roff *r, char *buf, int *pos, int ln, int ppos)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov char *cp;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const char *mac;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore size_t maclen;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore enum rofft t;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov cp = buf + *pos;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ('\0' == *cp || '"' == *cp || '\t' == *cp || ' ' == *cp)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_MAX;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mac = cp;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov maclen = roff_getname(r, &cp, ln, ppos);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore t = (r->current_string = roff_getstrn(r, mac, maclen))
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ? ROFF_USERDEF : roffhash_find(mac, maclen);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (ROFF_MAX != t)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *pos = cp - buf;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return t;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov/* --- handling of request blocks ----------------------------------------- */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_cblock(ROFF_ARGS)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * A block-close `..' should only be invoked as a child of an
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * ignore macro, otherwise raise a warning and just ignore it.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (r->last == NULL) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, ppos, "..");
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore switch (r->last->tok) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case ROFF_am:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* ROFF_am1 is remapped to ROFF_am in roff_block(). */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case ROFF_ami:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case ROFF_de:
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* ROFF_de1 is remapped to ROFF_de in roff_block(). */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case ROFF_dei:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case ROFF_ig:
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore default:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, ppos, "..");
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (buf->buf[pos] != '\0')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ".. %s", buf->buf + pos);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore roffnode_pop(r);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore roffnode_cleanscope(r);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroffnode_cleanscope(struct roff *r)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore while (r->last) {
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore if (--r->last->endspan != 0)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore roffnode_pop(r);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic void
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovroff_ccond(struct roff *r, int ln, int ppos)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (NULL == r->last) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, ppos, "\\}");
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov return;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore switch (r->last->tok) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case ROFF_el:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case ROFF_ie:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case ROFF_if:
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore default:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, ppos, "\\}");
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov return;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (r->last->endspan > -1) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, ppos, "\\}");
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov return;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore roffnode_pop(r);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore roffnode_cleanscope(r);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov return;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_block(ROFF_ARGS)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char *name;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov char *iname, *cp;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov size_t namesz;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Ignore groff compatibility mode for now. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (tok == ROFF_de1)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov tok = ROFF_de;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if (tok == ROFF_dei1)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov tok = ROFF_dei;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if (tok == ROFF_am1)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov tok = ROFF_am;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if (tok == ROFF_ami1)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov tok = ROFF_ami;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Parse the macro name argument. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov cp = buf->buf + pos;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (tok == ROFF_ig) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov iname = NULL;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov namesz = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov iname = cp;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov namesz = roff_getname(r, &cp, ln, ppos);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov iname[namesz] = '\0';
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Resolve the macro name argument if it is indirect. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (namesz && (tok == ROFF_dei || tok == ROFF_ami)) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ((name = roff_getstrn(r, iname, namesz)) == NULL) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_vmsg(MANDOCERR_STR_UNDEF,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->parse, ln, (int)(iname - buf->buf),
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "%.*s", (int)namesz, iname);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov namesz = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov namesz = strlen(name);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov name = iname;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (namesz == 0 && tok != ROFF_ig) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_REQ_EMPTY, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, ppos, roffs[tok].name);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore roffnode_push(r, tok, name, ln, ppos);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * At the beginning of a `de' macro, clear the existing string
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * with the same name, if there is one. New content will be
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * appended from roff_block_text() in multiline mode.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (tok == ROFF_de || tok == ROFF_dei)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov roff_setstrn(&r->strtab, name, namesz, "", 0, 0);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*cp == '\0')
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Get the custom end marker. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov iname = cp;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov namesz = roff_getname(r, &cp, ln, ppos);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Resolve the end marker if it is indirect. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (namesz && (tok == ROFF_dei || tok == ROFF_ami)) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ((name = roff_getstrn(r, iname, namesz)) == NULL) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_vmsg(MANDOCERR_STR_UNDEF,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->parse, ln, (int)(iname - buf->buf),
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "%.*s", (int)namesz, iname);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov namesz = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov namesz = strlen(name);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov name = iname;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (namesz)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->last->end = mandoc_strndup(name, namesz);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*cp != '\0')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, pos, ".%s ... %s", roffs[tok].name, cp);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_block_sub(ROFF_ARGS)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore enum rofft t;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore int i, j;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * First check whether a custom macro exists at this level. If
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * it does, then check against it. This is some of groff's
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * stranger behaviours. If we encountered a custom end-scope
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * tag and that tag also happens to be a "real" macro, then we
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * need to try interpreting it again as a real macro. If it's
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * not, then return ignore. Else continue.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (r->last->end) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore for (i = pos, j = 0; r->last->end[j]; j++, i++)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (buf->buf[i] != r->last->end[j])
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (r->last->end[j] == '\0' &&
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (buf->buf[i] == '\0' ||
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov buf->buf[i] == ' ' ||
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov buf->buf[i] == '\t')) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore roffnode_pop(r);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore roffnode_cleanscope(r);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (buf->buf[i] == ' ' || buf->buf[i] == '\t')
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore i++;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore pos = i;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (roff_parse(r, buf->buf, &pos, ln, ppos) !=
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_MAX)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_RERUN;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If we have no custom end-query or lookup failed, then try
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * pulling it out of the hashtable.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov t = roff_parse(r, buf->buf, &pos, ln, ppos);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (t != ROFF_cblock) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (tok != ROFF_ig)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov roff_setstr(r, r->last->name, buf->buf + ppos, 2);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore assert(roffs[t].proc);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_block_text(ROFF_ARGS)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (tok != ROFF_ig)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov roff_setstr(r, r->last->name, buf->buf + pos, 2);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_cond_sub(ROFF_ARGS)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore enum rofft t;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore char *ep;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int rr;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore rr = r->last->rule;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore roffnode_cleanscope(r);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov t = roff_parse(r, buf->buf, &pos, ln, ppos);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * Fully handle known macros when they are structurally
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * required or when the conditional evaluated to true.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ((t != ROFF_MAX) &&
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (rr || roffs[t].flags & ROFFMAC_STRUCT)) {
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore assert(roffs[t].proc);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs);
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * If `\}' occurs on a macro line without a preceding macro,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * drop the line completely.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ep = buf->buf + pos;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (ep[0] == '\\' && ep[1] == '}')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov rr = 0;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Always check for the closing delimiter `\}'. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while ((ep = strchr(ep, '\\')) != NULL) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*(++ep) == '}') {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *ep = '&';
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov roff_ccond(r, ln, ep - buf->buf - 1);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*ep != '\0')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ++ep;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return rr ? ROFF_CONT : ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_cond_text(ROFF_ARGS)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore char *ep;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int rr;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore rr = r->last->rule;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore roffnode_cleanscope(r);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ep = buf->buf + pos;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while ((ep = strchr(ep, '\\')) != NULL) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*(++ep) == '}') {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *ep = '&';
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov roff_ccond(r, ln, ep - buf->buf - 1);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*ep != '\0')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ++ep;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return rr ? ROFF_CONT : ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov/* --- handling of numeric and conditional expressions -------------------- */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov/*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Parse a single signed integer number. Stop at the first non-digit.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * If there is at least one digit, return success and advance the
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * parse point, else return failure and let the parse point unchanged.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Ignore overflows, treat them just like the C language.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amorestatic int
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovroff_getnum(const char *v, int *pos, int *res, int flags)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int myres, scaled, n, p;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (NULL == res)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov res = &myres;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore p = *pos;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore n = v[p] == '-';
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (n || v[p] == '+')
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore p++;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (flags & ROFFNUM_WHITE)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (isspace((unsigned char)v[p]))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov p++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore for (*res = 0; isdigit((unsigned char)v[p]); p++)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res = 10 * *res + v[p] - '0';
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore if (p == *pos + n)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore return 0;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore if (n)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore *res = -*res;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Each number may be followed by one optional scaling unit. */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov switch (v[p]) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'f':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov scaled = *res * 65536;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'i':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov scaled = *res * 240;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'c':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov scaled = *res * 240 / 2.54;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'v':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'P':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov scaled = *res * 40;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'm':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'n':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov scaled = *res * 24;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'p':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov scaled = *res * 10 / 3;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'u':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov scaled = *res;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'M':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov scaled = *res * 6 / 25;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore break;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore default:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov scaled = *res;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov p--;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (flags & ROFFNUM_SCALE)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res = scaled;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *pos = p + 1;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov}
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov/*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Evaluate a string comparison condition.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * The first character is the delimiter.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Succeed if the string up to its second occurrence
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * matches the string up to its third occurence.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Advance the cursor after the third occurrence
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * or lacking that, to the end of the line.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic int
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovroff_evalstrcond(const char *v, int *pos)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char *s1, *s2, *s3;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int match;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov match = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov s1 = v + *pos; /* initial delimiter */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov s2 = s1 + 1; /* for scanning the first string */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov s3 = strchr(s2, *s1); /* for scanning the second string */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (NULL == s3) /* found no middle delimiter */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov goto out;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while ('\0' != *++s3) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*s2 != *s3) { /* mismatch */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov s3 = strchr(s3, *s1);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*s3 == *s1) { /* found the final delimiter */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov match = 1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov s2++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovout:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (NULL == s3)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov s3 = strchr(s2, '\0');
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if (*s3 != '\0')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov s3++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *pos = s3 - v;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return match;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore}
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov/*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Evaluate an optionally negated single character, numerical,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * or string condition.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic int
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovroff_evalcond(struct roff *r, int ln, char *v, int *pos)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov char *cp, *name;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov size_t sz;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int number, savepos, wanttrue;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ('!' == v[*pos]) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov wanttrue = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (*pos)++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov wanttrue = 1;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore switch (v[*pos]) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '\0':
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'n':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'o':
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore (*pos)++;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return wanttrue;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'c':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'd':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'e':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 't':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'v':
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore (*pos)++;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return !wanttrue;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case 'r':
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov cp = name = v + ++*pos;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov sz = roff_getname(r, &cp, ln, *pos);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov *pos = cp - v;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return (sz && roff_hasregn(r, name, sz)) == wanttrue;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore default:
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov savepos = *pos;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (roff_evalnum(r, ln, v, pos, &number, ROFFNUM_SCALE))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return (number > 0) == wanttrue;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if (*pos == savepos)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return roff_evalstrcond(v, pos) == wanttrue;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 0;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_line_ignore(ROFF_ARGS)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic enum rofferr
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovroff_insec(ROFF_ARGS)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_REQ_INSEC, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, ppos, roffs[tok].name);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov}
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic enum rofferr
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovroff_unsupp(ROFF_ARGS)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_REQ_UNSUPP, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, ppos, roffs[tok].name);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov}
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_cond(ROFF_ARGS)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore roffnode_push(r, tok, NULL, ln, ppos);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * An `.el' has no conditional body: it will consume the value
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * of the current rstack entry set in prior `ie' calls or
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * defaults to DENY.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore *
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If we're not an `el', however, then evaluate the conditional.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->last->rule = tok == ROFF_el ?
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (r->rstackpos < 0 ? 0 : r->rstack[r->rstackpos--]) :
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov roff_evalcond(r, ln, buf->buf, &pos);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * An if-else will put the NEGATION of the current evaluated
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * conditional into the stack of rules.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (tok == ROFF_ie) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (r->rstackpos + 1 == r->rstacksz) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->rstacksz += 16;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->rstack = mandoc_reallocarray(r->rstack,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->rstacksz, sizeof(int));
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->rstack[++r->rstackpos] = !r->last->rule;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* If the parent has false as its rule, then so do we. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (r->last->parent && !r->last->parent->rule)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->last->rule = 0;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * Determine scope.
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * If there is nothing on the line after the conditional,
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * not even whitespace, use next-line scope.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (buf->buf[pos] == '\0') {
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore r->last->endspan = 2;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore goto out;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore }
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (buf->buf[pos] == ' ')
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore pos++;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore /* An opening brace requests multiline scope. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (buf->buf[pos] == '\\' && buf->buf[pos + 1] == '{') {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore r->last->endspan = -1;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore pos += 2;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov while (buf->buf[pos] == ' ')
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov pos++;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore goto out;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * Anything else following the conditional causes
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * single-line scope. Warn if the scope contains
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * nothing but trailing whitespace.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (buf->buf[pos] == '\0')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_COND_EMPTY, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, ppos, roffs[tok].name);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore r->last->endspan = 1;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amoreout:
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore *offs = pos;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_RERUN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_ds(ROFF_ARGS)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov char *string;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char *name;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov size_t namesz;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Ignore groff compatibility mode for now. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (tok == ROFF_ds1)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov tok = ROFF_ds;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if (tok == ROFF_as1)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov tok = ROFF_as;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * The first word is the name of the string.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * If it is empty or terminated by an escape sequence,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * abort the `ds' request without defining anything.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov name = string = buf->buf + pos;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*name == '\0')
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov namesz = roff_getname(r, &string, ln, pos);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (name[namesz] == '\\')
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Read past the initial double-quote, if any. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*string == '"')
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore string++;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* The rest is the value. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov roff_setstrn(&r->strtab, name, namesz, string, strlen(string),
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ROFF_as == tok);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov/*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Parse a single operator, one or two characters long.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * If the operator is recognized, return success and advance the
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * parse point, else return failure and let the parse point unchanged.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic int
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovroff_getop(const char *v, int *pos, char *res)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res = v[*pos];
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov switch (*res) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '+':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '-':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '*':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '/':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '%':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '&':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case ':':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '<':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov switch (v[*pos + 1]) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '=':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res = 'l';
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (*pos)++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '>':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res = '!';
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (*pos)++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '?':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res = 'i';
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (*pos)++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov default:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '>':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov switch (v[*pos + 1]) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '=':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res = 'g';
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (*pos)++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '?':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res = 'a';
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (*pos)++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov default:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '=':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ('=' == v[*pos + 1])
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (*pos)++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov default:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (*pos)++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return *res;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov}
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov/*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Evaluate either a parenthesized numeric expression
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * or a single signed integer number.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic int
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovroff_evalpar(struct roff *r, int ln,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char *v, int *pos, int *res, int flags)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ('(' != v[*pos])
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return roff_getnum(v, pos, res, flags);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (*pos)++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ( ! roff_evalnum(r, ln, v, pos, res, flags | ROFFNUM_WHITE))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Omission of the closing parenthesis
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * is an error in validation mode,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * but ignored in evaluation mode.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (')' == v[*pos])
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (*pos)++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if (NULL == res)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov}
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov/*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Evaluate a complete numeric expression.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Proceed left to right, there is no concept of precedence.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic int
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovroff_evalnum(struct roff *r, int ln, const char *v,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int *pos, int *res, int flags)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int mypos, operand2;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov char operator;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (NULL == pos) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mypos = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov pos = &mypos;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (flags & ROFFNUM_WHITE)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (isspace((unsigned char)v[*pos]))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (*pos)++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ( ! roff_evalpar(r, ln, v, pos, res, flags))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (1) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (flags & ROFFNUM_WHITE)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (isspace((unsigned char)v[*pos]))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (*pos)++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ( ! roff_getop(v, pos, &operator))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (flags & ROFFNUM_WHITE)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (isspace((unsigned char)v[*pos]))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (*pos)++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ( ! roff_evalpar(r, ln, v, pos, &operand2, flags))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (flags & ROFFNUM_WHITE)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (isspace((unsigned char)v[*pos]))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (*pos)++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (NULL == res)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov continue;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov switch (operator) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '+':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res += operand2;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '-':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res -= operand2;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '*':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res *= operand2;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '/':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (operand2 == 0) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_DIVZERO,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->parse, ln, *pos, v);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res /= operand2;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '%':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (operand2 == 0) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_DIVZERO,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->parse, ln, *pos, v);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res %= operand2;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '<':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res = *res < operand2;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '>':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res = *res > operand2;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'l':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res = *res <= operand2;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'g':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res = *res >= operand2;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '=':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res = *res == operand2;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '!':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res = *res != operand2;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '&':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res = *res && operand2;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case ':':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res = *res || operand2;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'i':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (operand2 < *res)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res = operand2;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'a':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (operand2 > *res)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res = operand2;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov default:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov abort();
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov}
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov/* --- register management ------------------------------------------------ */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amorevoid
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amoreroff_setreg(struct roff *r, const char *name, int val, char sign)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore{
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore struct roffreg *reg;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore /* Search for an existing register with the same name. */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore reg = r->regtab;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore while (reg && strcmp(name, reg->key.p))
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore reg = reg->next;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore if (NULL == reg) {
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore /* Create a new register. */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore reg = mandoc_malloc(sizeof(struct roffreg));
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore reg->key.p = mandoc_strdup(name);
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore reg->key.sz = strlen(name);
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore reg->val = 0;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore reg->next = r->regtab;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore r->regtab = reg;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore }
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore if ('+' == sign)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore reg->val += val;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore else if ('-' == sign)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore reg->val -= val;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore else
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore reg->val = val;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore}
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov/*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Handle some predefined read-only number registers.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * For now, return -1 if the requested register is not predefined;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * in case a predefined read-only register having the value -1
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * were to turn up, another special value would have to be chosen.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic int
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovroff_getregro(const struct roff *r, const char *name)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov switch (*name) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case '$': /* Number of arguments of the last macro evaluated. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return r->argc;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'A': /* ASCII approximation mode is always off. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'g': /* Groff compatibility mode is always on. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'H': /* Fixed horizontal resolution. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 24;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'j': /* Always adjust left margin only. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'T': /* Some output device is always defined. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'V': /* Fixed vertical resolution. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 40;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov default:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return -1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov}
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreint
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amoreroff_getreg(const struct roff *r, const char *name)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore struct roffreg *reg;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int val;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ('.' == name[0] && '\0' != name[1] && '\0' == name[2]) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov val = roff_getregro(r, name + 1);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (-1 != val)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return val;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore for (reg = r->regtab; reg; reg = reg->next)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore if (0 == strcmp(name, reg->key.p))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return reg->val;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 0;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amorestatic int
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amoreroff_getregn(const struct roff *r, const char *name, size_t len)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore struct roffreg *reg;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int val;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ('.' == name[0] && 2 == len) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov val = roff_getregro(r, name + 1);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (-1 != val)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return val;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov for (reg = r->regtab; reg; reg = reg->next)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (len == reg->key.sz &&
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov 0 == strncmp(name, reg->key.p, len))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return reg->val;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 0;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov}
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic int
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovroff_hasregn(const struct roff *r, const char *name, size_t len)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roffreg *reg;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov int val;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if ('.' == name[0] && 2 == len) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov val = roff_getregro(r, name + 1);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (-1 != val)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore for (reg = r->regtab; reg; reg = reg->next)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore if (len == reg->key.sz &&
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore 0 == strncmp(name, reg->key.p, len))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 1;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 0;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amorestatic void
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amoreroff_freereg(struct roffreg *reg)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore struct roffreg *old_reg;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore while (NULL != reg) {
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore free(reg->key.p);
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore old_reg = reg;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore reg = reg->next;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore free(old_reg);
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_nr(ROFF_ARGS)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov char *key, *val;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov size_t keysz;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore int iv;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore char sign;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov key = val = buf->buf + pos;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*key == '\0')
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov keysz = roff_getname(r, &val, ln, pos);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (key[keysz] == '\\')
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov key[keysz] = '\0';
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore sign = *val;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (sign == '+' || sign == '-')
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore val++;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (roff_evalnum(r, ln, val, NULL, &iv, ROFFNUM_SCALE))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov roff_setreg(r, key, iv, sign);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov}
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic enum rofferr
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovroff_rr(ROFF_ARGS)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov struct roffreg *reg, **prev;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov char *name, *cp;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov size_t namesz;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov name = cp = buf->buf + pos;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*name == '\0')
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov namesz = roff_getname(r, &cp, ln, pos);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov name[namesz] = '\0';
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov prev = &r->regtab;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (1) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov reg = *prev;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (reg == NULL || !strcmp(name, reg->key.p))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov prev = &reg->next;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (reg != NULL) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *prev = reg->next;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov free(reg->key.p);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov free(reg);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov/* --- handler functions for roff requests -------------------------------- */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_rm(ROFF_ARGS)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const char *name;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore char *cp;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov size_t namesz;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov cp = buf->buf + pos;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (*cp != '\0') {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov name = cp;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov namesz = roff_getname(r, &cp, ln, (int)(cp - buf->buf));
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov roff_setstrn(&r->strtab, name, namesz, NULL, 0, 0);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (name[namesz] == '\\')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amorestatic enum rofferr
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amoreroff_it(ROFF_ARGS)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore{
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore int iv;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore /* Parse the number of lines. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ( ! roff_evalnum(r, ln, buf->buf, &pos, &iv, 0)) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_IT_NONUM, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, ppos, buf->buf + 1);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore }
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (isspace((unsigned char)buf->buf[pos]))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov pos++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Arm the input line trap.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Special-casing "an-trap" is an ugly workaround to cope
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * with DocBook stupidly fiddling with man(7) internals.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore roffit_lines = iv;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov roffit_macro = mandoc_strdup(iv != 1 ||
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov strcmp(buf->buf + pos, "an-trap") ?
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov buf->buf + pos : "br");
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore}
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amorestatic enum rofferr
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amoreroff_Dd(ROFF_ARGS)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore{
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore const char *const *cp;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ((r->options & (MPARSE_MDOC | MPARSE_QUICK)) == 0)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore for (cp = __mdoc_reserved; *cp; cp++)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore roff_setstr(r, *cp, NULL, 0);
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (r->format == 0)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->format = MPARSE_MDOC;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_CONT;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore}
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amorestatic enum rofferr
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amoreroff_TH(ROFF_ARGS)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore{
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore const char *const *cp;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ((r->options & MPARSE_QUICK) == 0)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore for (cp = __man_reserved; *cp; cp++)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore roff_setstr(r, *cp, NULL, 0);
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (r->format == 0)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->format = MPARSE_MAN;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_CONT;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore}
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_TE(ROFF_ARGS)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (NULL == r->tbl)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, ppos, "TE");
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if ( ! tbl_end(&r->tbl)) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov free(buf->buf);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov buf->buf = mandoc_strdup(".sp");
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov buf->sz = 4;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_REPARSE;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_T_(ROFF_ARGS)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (NULL == r->tbl)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, ppos, "T&");
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore else
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore tbl_restart(ppos, ln, r->tbl);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov/*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Handle in-line equation delimiters.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic enum rofferr
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovroff_eqndelim(struct roff *r, struct buf *buf, int pos)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov char *cp1, *cp2;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char *bef_pr, *bef_nl, *mac, *aft_nl, *aft_pr;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Outside equations, look for an opening delimiter.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * If we are inside an equation, we already know it is
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * in-line, or this function wouldn't have been called;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * so look for a closing delimiter.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov cp1 = buf->buf + pos;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov cp2 = strchr(cp1, r->eqn == NULL ?
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->last_eqn->odelim : r->last_eqn->cdelim);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (cp2 == NULL)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_CONT;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *cp2++ = '\0';
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov bef_pr = bef_nl = aft_nl = aft_pr = "";
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Handle preceding text, protecting whitespace. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*buf->buf != '\0') {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (r->eqn == NULL)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov bef_pr = "\\&";
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov bef_nl = "\n";
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Prepare replacing the delimiter with an equation macro
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * and drop leading white space from the equation.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (r->eqn == NULL) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (*cp2 == ' ')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov cp2++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mac = ".EQ";
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mac = ".EN";
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Handle following text, protecting whitespace. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*cp2 != '\0') {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov aft_nl = "\n";
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (r->eqn != NULL)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov aft_pr = "\\&";
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Do the actual replacement. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov buf->sz = mandoc_asprintf(&cp1, "%s%s%s%s%s%s%s", buf->buf,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov bef_pr, bef_nl, mac, aft_nl, aft_pr, cp2) + 1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov free(buf->buf);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov buf->buf = cp1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Toggle the in-line state of the eqn subsystem. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->eqn_inline = r->eqn == NULL;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_REPARSE;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_EQ(ROFF_ARGS)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov struct eqn_node *e;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov assert(r->eqn == NULL);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov e = eqn_alloc(ppos, ln, r->parse);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (r->last_eqn) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->last_eqn->next = e;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov e->delim = r->last_eqn->delim;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov e->odelim = r->last_eqn->odelim;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov e->cdelim = r->last_eqn->cdelim;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->first_eqn = r->last_eqn = e;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->eqn = r->last_eqn = e;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (buf->buf[pos] != '\0')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ".EQ %s", buf->buf + pos);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_EN(ROFF_ARGS)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, ln, ppos, "EN");
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_TS(ROFF_ARGS)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore struct tbl_node *tbl;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (r->tbl) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_BLK_BROKEN, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, ppos, "TS breaks TS");
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore tbl_end(&r->tbl);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore tbl = tbl_alloc(ppos, ln, r->parse);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (r->last_tbl)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore r->last_tbl->next = tbl;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore else
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore r->first_tbl = r->last_tbl = tbl;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore r->tbl = r->last_tbl = tbl;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore}
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic enum rofferr
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovroff_brp(ROFF_ARGS)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov buf->buf[pos - 1] = '\0';
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_CONT;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov}
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amorestatic enum rofferr
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amoreroff_cc(ROFF_ARGS)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore{
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore const char *p;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov p = buf->buf + pos;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*p == '\0' || (r->control = *p++) == '.')
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore r->control = 0;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*p != '\0')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, p - buf->buf, "cc ... %s", p);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_tr(ROFF_ARGS)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const char *p, *first, *second;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore size_t fsz, ssz;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore enum mandoc_esc esc;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov p = buf->buf + pos;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*p == '\0') {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_REQ_EMPTY, r->parse, ln, ppos, "tr");
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (*p != '\0') {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore fsz = ssz = 1;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore first = p++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*first == '\\') {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore esc = mandoc_escape(&p, NULL, NULL);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (esc == ESCAPE_ERROR) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_ESC_BAD, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, (int)(p - buf->buf), first);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore fsz = (size_t)(p - first);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore second = p++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*second == '\\') {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore esc = mandoc_escape(&p, NULL, NULL);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (esc == ESCAPE_ERROR) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_ESC_BAD, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, (int)(p - buf->buf), second);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ssz = (size_t)(p - second);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else if (*second == '\0') {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_vmsg(MANDOCERR_TR_ODD, r->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, first - buf->buf, "tr %s", first);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore second = " ";
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore p--;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (fsz > 1) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov roff_setstrn(&r->xmbtab, first, fsz,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov second, ssz, 0);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore continue;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (r->xtab == NULL)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov r->xtab = mandoc_calloc(128,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov sizeof(struct roffstr));
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore free(r->xtab[(int)*first].p);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore r->xtab[(int)*first].p = mandoc_strndup(second, ssz);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore r->xtab[(int)*first].sz = ssz;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_IGN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_so(ROFF_ARGS)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov char *name, *cp;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov name = buf->buf + pos;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_vmsg(MANDOCERR_SO, r->parse, ln, ppos, "so %s", name);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Handle `so'. Be EXTREMELY careful, as we shouldn't be
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * opening anything that's not in our cwd or anything beneath
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * it. Thus, explicitly disallow traversing up the file-system
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * or using absolute paths.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*name == '/' || strstr(name, "../") || strstr(name, "/..")) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_vmsg(MANDOCERR_SO_PATH, r->parse, ln, ppos,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ".so %s", name);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov buf->sz = mandoc_asprintf(&cp,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ".sp\nSee the file %s.\n.sp", name) + 1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov free(buf->buf);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov buf->buf = cp;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *offs = 0;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_REPARSE;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore *offs = pos;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return ROFF_SO;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov/* --- user defined strings and macros ------------------------------------ */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic enum rofferr
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_userdef(ROFF_ARGS)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char *arg[9], *ap;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore char *cp, *n1, *n2;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov int i, ib, ie;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov size_t asz, rsz;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Collect pointers to macro argument strings
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * and NUL-terminate them.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov r->argc = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov cp = buf->buf + pos;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov for (i = 0; i < 9; i++) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (*cp == '\0')
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov arg[i] = "";
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov else {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov arg[i] = mandoc_getarg(r->parse, &cp, ln, &pos);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov r->argc = i + 1;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Expand macro arguments.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov buf->sz = strlen(r->current_string) + 1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov n1 = cp = mandoc_malloc(buf->sz);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov memcpy(n1, r->current_string, buf->sz);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (*cp != '\0') {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Scan ahead for the next argument invocation. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*cp++ != '\\')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov continue;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*cp++ != '$')
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore continue;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (*cp == '*') { /* \\$* inserts all arguments */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov ib = 0;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov ie = r->argc - 1;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov } else { /* \\$1 .. \\$9 insert one argument */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov ib = ie = *cp - '1';
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (ib < 0 || ib > 8)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov continue;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov cp -= 2;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Determine the size of the expanded argument,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * taking escaping of quotes into account.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov asz = ie > ib ? ie - ib : 0; /* for blanks */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov for (i = ib; i <= ie; i++) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov for (ap = arg[i]; *ap != '\0'; ap++) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov asz++;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (*ap == '"')
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov asz += 3;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (asz != 3) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Determine the size of the rest of the
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * unexpanded macro, including the NUL.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov rsz = buf->sz - (cp - n1) - 3;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * When shrinking, move before
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * releasing the storage.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (asz < 3)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov memmove(cp + asz, cp + 3, rsz);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Resize the storage for the macro
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * and readjust the parse pointer.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov buf->sz += asz - 3;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov n2 = mandoc_realloc(n1, buf->sz);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov cp = n2 + (cp - n1);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov n1 = n2;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * When growing, make room
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * for the expanded argument.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (asz > 3)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov memmove(cp + asz, cp + 3, rsz);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Copy the expanded argument, escaping quotes. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov n2 = cp;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov for (i = ib; i <= ie; i++) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov for (ap = arg[i]; *ap != '\0'; ap++) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (*ap == '"') {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov memcpy(n2, "\\(dq", 4);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n2 += 4;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov } else
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov *n2++ = *ap;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (i < ie)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov *n2++ = ' ';
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Replace the macro invocation
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * by the expanded macro.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov free(buf->buf);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov buf->buf = n1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *offs = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return buf->sz > 1 && buf->buf[buf->sz - 2] == '\n' ?
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov ROFF_REPARSE : ROFF_APPEND;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic size_t
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_getname(struct roff *r, char **cpp, int ln, int pos)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore char *name, *cp;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov size_t namesz;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore name = *cpp;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if ('\0' == *name)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 0;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Read until end of name and terminate it with NUL. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov for (cp = name; 1; cp++) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ('\0' == *cp || ' ' == *cp) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov namesz = cp - name;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if ('\\' != *cp)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore continue;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov namesz = cp - name;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ('{' == cp[1] || '}' == cp[1])
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore cp++;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if ('\\' == *cp)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore continue;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_vmsg(MANDOCERR_NAMESC, r->parse, ln, pos,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "%.*s", (int)(cp - name + 1), name);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_escape((const char **)&cp, NULL, NULL);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Read past spaces. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore while (' ' == *cp)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore cp++;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore *cpp = cp;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return namesz;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore/*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Store *string into the user-defined string called *name.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * To clear an existing entry, call with (*r, *name, NULL, 0).
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * append == 0: replace mode
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * append == 1: single-line append mode
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * append == 2: multiline append mode, append '\n' after each call
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_setstr(struct roff *r, const char *name, const char *string,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int append)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore roff_setstrn(&r->strtab, name, strlen(name), string,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov string ? strlen(string) : 0, append);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_setstrn(struct roffkv **r, const char *name, size_t namesz,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char *string, size_t stringsz, int append)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct roffkv *n;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore char *c;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore int i;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore size_t oldch, newch;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Search for an existing string with the same name. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore n = *r;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (n && (namesz != n->key.sz ||
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov strncmp(n->key.p, name, namesz)))
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore n = n->next;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (NULL == n) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Create a new string table entry. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore n = mandoc_malloc(sizeof(struct roffkv));
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore n->key.p = mandoc_strndup(name, namesz);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore n->key.sz = namesz;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore n->val.p = NULL;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore n->val.sz = 0;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore n->next = *r;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore *r = n;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else if (0 == append) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore free(n->val.p);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore n->val.p = NULL;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore n->val.sz = 0;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (NULL == string)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore return;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * One additional byte for the '\n' in multiline mode,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * and one for the terminating '\0'.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov newch = stringsz + (1 < append ? 2u : 1u);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (NULL == n->val.p) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore n->val.p = mandoc_malloc(newch);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore *n->val.p = '\0';
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore oldch = 0;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore } else {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore oldch = n->val.sz;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore n->val.p = mandoc_realloc(n->val.p, oldch + newch);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Skip existing content in the destination buffer. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore c = n->val.p + (int)oldch;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Append new content to the destination buffer. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore i = 0;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore while (i < (int)stringsz) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Rudimentary roff copy mode:
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Handle escaped backslashes.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if ('\\' == string[i] && '\\' == string[i + 1])
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore i++;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore *c++ = string[i++];
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Append terminating bytes. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (1 < append)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore *c++ = '\n';
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore *c = '\0';
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore n->val.sz = (int)(c - n->val.p);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic const char *
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_getstrn(const struct roff *r, const char *name, size_t len)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const struct roffkv *n;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int i;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore for (n = r->strtab; n; n = n->next)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (0 == strncmp(name, n->key.p, len) &&
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov '\0' == n->key.p[(int)len])
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return n->val.p;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov for (i = 0; i < PREDEFS_MAX; i++)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (0 == strncmp(name, predefs[i].name, len) &&
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov '\0' == predefs[i].name[(int)len])
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return predefs[i].str;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return NULL;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_freestr(struct roffkv *r)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct roffkv *n, *nn;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore for (n = r; n; n = nn) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore free(n->key.p);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore free(n->val.p);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore nn = n->next;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore free(n);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov/* --- accessors and utility functions ------------------------------------ */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreconst struct tbl_span *
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_span(const struct roff *r)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return r->tbl ? tbl_span(r->tbl) : NULL;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreconst struct eqn *
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_eqn(const struct roff *r)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return r->last_eqn ? &r->last_eqn->eqn : NULL;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore/*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Duplicate an input string, making the appropriate character
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * conversations (as stipulated by `tr') along the way.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Returns a heap-allocated string with all the replacements made.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorechar *
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreroff_strdup(const struct roff *r, const char *p)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const struct roffkv *cp;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore char *res;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const char *pp;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore size_t ssz, sz;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore enum mandoc_esc esc;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (NULL == r->xmbtab && NULL == r->xtab)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return mandoc_strdup(p);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore else if ('\0' == *p)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return mandoc_strdup("");
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Step through each character looking for term matches
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * (remember that a `tr' can be invoked with an escape, which is
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * a glyph but the escape is multi-character).
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * We only do this if the character hash has been initialised
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * and the string is >0 length.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore res = NULL;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ssz = 0;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore while ('\0' != *p) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if ('\\' != *p && r->xtab && r->xtab[(int)*p].p) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore sz = r->xtab[(int)*p].sz;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore res = mandoc_realloc(res, ssz + sz + 1);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore memcpy(res + ssz, r->xtab[(int)*p].p, sz);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ssz += sz;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore p++;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore continue;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore } else if ('\\' != *p) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore res = mandoc_realloc(res, ssz + 2);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore res[ssz++] = *p++;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore continue;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Search for term matches. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore for (cp = r->xmbtab; cp; cp = cp->next)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (0 == strncmp(p, cp->key.p, cp->key.sz))
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (NULL != cp) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * A match has been found.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Append the match to the array and move
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * forward by its keysize.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov res = mandoc_realloc(res,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ssz + cp->val.sz + 1);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore memcpy(res + ssz, cp->val.p, cp->val.sz);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ssz += cp->val.sz;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore p += (int)cp->key.sz;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore continue;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Handle escapes carefully: we need to copy
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * over just the escape itself, or else we might
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * do replacements within the escape itself.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Make sure to pass along the bogus string.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore pp = p++;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore esc = mandoc_escape(&p, NULL, NULL);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (ESCAPE_ERROR == esc) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore sz = strlen(pp);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore res = mandoc_realloc(res, ssz + sz + 1);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore memcpy(res + ssz, pp, sz);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * We bail out on bad escapes.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * No need to warn: we already did so when
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * roff_res() was called.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore sz = (int)(p - pp);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore res = mandoc_realloc(res, ssz + sz + 1);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore memcpy(res + ssz, pp, sz);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ssz += sz;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore res[(int)ssz] = '\0';
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return res;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovint
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovroff_getformat(const struct roff *r)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return r->format;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov}
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore/*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Find out whether a line is a macro line or not.
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * If it is, adjust the current position and return one; if it isn't,
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * return zero and don't change the current position.
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * If the control character has been set with `.cc', then let that grain
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * precedence.
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * This is slighly contrary to groff, where using the non-breaking
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * control character when `cc' has been invoked will cause the
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * non-breaking macro contents to be printed verbatim.
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amoreint
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amoreroff_getcontrol(const struct roff *r, const char *cp, int *ppos)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore{
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore int pos;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore pos = *ppos;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore if (0 != r->control && cp[pos] == r->control)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore pos++;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore else if (0 != r->control)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 0;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore else if ('\\' == cp[pos] && '.' == cp[pos + 1])
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore pos += 2;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore else if ('.' == cp[pos] || '\'' == cp[pos])
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore pos++;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore else
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 0;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore while (' ' == cp[pos] || '\t' == cp[pos])
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore pos++;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore *ppos = pos;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 1;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore}