371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov/* $Id: man.c,v 1.166 2015/10/22 21:54:23 schwarze Exp $ */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore/*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Copyright (c) 2011 Joerg Sonnenberger <joerg@netbsd.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 *
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * 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
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * 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"
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include <sys/types.h>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include <assert.h>
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#include <ctype.h>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include <stdarg.h>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include <stdlib.h>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include <stdio.h>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include <string.h>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#include "mandoc_aux.h"
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#include "mandoc.h"
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#include "roff.h"
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#include "man.h"
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include "libmandoc.h"
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#include "roff_int.h"
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#include "libman.h"
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovconst char *const __man_macronames[MAN_MAX] = {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "br", "TH", "SH", "SS",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "TP", "LP", "PP", "P",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "IP", "HP", "SM", "SB",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "BI", "IB", "BR", "RB",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "R", "B", "I", "IR",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "RI", "sp", "nf",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "fi", "RE", "RS", "DT",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "UC", "PD", "AT", "in",
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore "ft", "OP", "EX", "EE",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "UR", "UE", "ll"
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore };
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreconst char * const *man_macronames = __man_macronames;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic void man_descope(struct roff_man *, int, int);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic int man_ptext(struct roff_man *, int, char *, int);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic int man_pmacro(struct roff_man *, int, char *, int);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreint
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovman_parseln(struct roff_man *man, int ln, char *buf, int offs)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (man->last->type != ROFFT_EQN || ln > man->last->line)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov man->flags |= MAN_NEWLINE;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return roff_getcontrol(man->roff, buf, &offs) ?
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov man_pmacro(man, ln, buf, offs) :
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man_ptext(man, ln, buf, offs);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic void
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovman_descope(struct roff_man *man, int line, int offs)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Co-ordinate what happens with having a next-line scope open:
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * first close out the element scope (if applicable), then close
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * out the block scope (also if applicable).
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (man->flags & MAN_ELINE) {
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore man->flags &= ~MAN_ELINE;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov man_unscope(man, man->last->parent);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ( ! (man->flags & MAN_BLINE))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov return;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore man->flags &= ~MAN_BLINE;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov man_unscope(man, man->last->parent);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_body_alloc(man, line, offs, man->last->tok);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic int
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovman_ptext(struct roff_man *man, int line, char *buf, int offs)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore int i;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Literal free-form text whitespace is preserved. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (man->flags & MAN_LITERAL) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_word_alloc(man, line, offs, buf + offs);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov man_descope(man, line, offs);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 1;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov for (i = offs; buf[i] == ' '; i++)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Skip leading whitespace. */ ;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore /*
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * Blank lines are ignored right after headings
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * but add a single vertical space elsewhere.
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (buf[i] == '\0') {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Allocate a blank entry. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (man->last->tok != MAN_SH &&
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov man->last->tok != MAN_SS) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_elem_alloc(man, line, offs, MAN_sp);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->next = ROFF_NEXT_SIBLING;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 1;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Warn if the last un-escaped character is whitespace. Then
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * strip away the remaining spaces (tabs stay!).
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore i = (int)strlen(buf);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore assert(i);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (' ' == buf[i - 1] || '\t' == buf[i - 1]) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (i > 1 && '\\' != buf[i - 2])
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov line, i - 1, NULL);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore for (--i; i && ' ' == buf[i]; i--)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Spin back to non-space. */ ;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Jump ahead of escaped whitespace. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore i += '\\' == buf[i] ? 2 : 1;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore buf[i] = '\0';
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_word_alloc(man, line, offs, buf + offs);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * End-of-sentence check. If the last character is an unescaped
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * EOS character, then flag the node as being the end of a
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * sentence. The front-end will know how to interpret this.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore assert(i);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (mandoc_eos(buf, (size_t)i))
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore man->last->flags |= MAN_EOS;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov man_descope(man, line, offs);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 1;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic int
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovman_pmacro(struct roff_man *man, int ln, char *buf, int offs)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *n;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char *cp;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov int tok;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int i, ppos;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int bline;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore char mac[5];
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ppos = offs;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Copy the first word into a nil-terminated buffer.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Stop when a space, tab, escape, or eoln is encountered.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore i = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (i < 4 && strchr(" \t\\", buf[offs]) == NULL)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore mac[i++] = buf[offs++];
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore mac[i] = '\0';
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov tok = (i > 0 && i < 4) ? man_hash_find(mac) : TOKEN_NONE;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (tok == TOKEN_NONE) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_MACRO, man->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, ppos, buf + ppos - 1);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 1;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Skip a leading escape sequence or tab. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov switch (buf[offs]) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '\\':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov cp = buf + offs + 1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_escape(&cp, NULL, NULL);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov offs = cp - buf;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case '\t':
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore offs++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov default:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Jump to the next non-whitespace word. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (buf[offs] && buf[offs] == ' ')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov offs++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Trailing whitespace. Note that tabs are allowed to be passed
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * into the parser as "text", so we only warn about spaces here.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (buf[offs] == '\0' && buf[offs - 1] == ' ')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ln, offs - 1, NULL);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Some macros break next-line scopes; otherwise, remember
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * whether we are in next-line scope for a block head.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov man_breakscope(man, tok);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov bline = man->flags & MAN_BLINE;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Call to handler... */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov assert(man_macros[tok].fp);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* In quick mode (for mandocdb), abort after the NAME section. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (man->quick && tok == MAN_SH) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov n = man->last;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (n->type == ROFFT_BODY &&
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov strcmp(n->prev->child->string, "NAME"))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 2;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * If we are in a next-line scope for a block head,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * close it out now and switch to the body,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * unless the next-line scope is allowed to continue.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ( ! bline || man->flags & MAN_ELINE ||
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov man_macros[tok].flags & MAN_NSCOPED)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 1;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov assert(man->flags & MAN_BLINE);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov man->flags &= ~MAN_BLINE;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov man_unscope(man, man->last->parent);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_body_alloc(man, ln, ppos, man->last->tok);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovvoid
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovman_breakscope(struct roff_man *man, int tok)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *n;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * An element next line scope is open,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * and the new macro is not allowed inside elements.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Delete the element that is being broken.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (man->flags & MAN_ELINE && (tok == TOKEN_NONE ||
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ! (man_macros[tok].flags & MAN_NSCOPED))) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov n = man->last;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov assert(n->type != ROFFT_TEXT);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (man_macros[n->tok].flags & MAN_NSCOPED)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov n = n->parent;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov n->line, n->pos, "%s breaks %s",
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov tok == TOKEN_NONE ? "TS" : man_macronames[tok],
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov man_macronames[n->tok]);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_node_delete(man, n);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov man->flags &= ~MAN_ELINE;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov /*
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * Weird special case:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * Switching fill mode closes section headers.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (man->flags & MAN_BLINE &&
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov (tok == MAN_nf || tok == MAN_fi) &&
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov (man->last->tok == MAN_SH || man->last->tok == MAN_SS)) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n = man->last;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man_unscope(man, n);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_body_alloc(man, n->line, n->pos, n->tok);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->flags &= ~MAN_BLINE;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * A block header next line scope is open,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * and the new macro is not allowed inside block headers.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Delete the block that is being broken.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (man->flags & MAN_BLINE && (tok == TOKEN_NONE ||
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov man_macros[tok].flags & MAN_BSCOPE)) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov n = man->last;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (n->type == ROFFT_TEXT)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov n = n->parent;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ( ! (man_macros[n->tok].flags & MAN_BSCOPE))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov n = n->parent;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov assert(n->type == ROFFT_HEAD);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov n = n->parent;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov assert(n->type == ROFFT_BLOCK);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov assert(man_macros[n->tok].flags & MAN_SCOPED);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov n->line, n->pos, "%s breaks %s",
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov tok == TOKEN_NONE ? "TS" : man_macronames[tok],
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov man_macronames[n->tok]);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_node_delete(man, n);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov man->flags &= ~MAN_BLINE;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreconst struct mparse *
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovman_mparse(const struct roff_man *man)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore assert(man && man->parse);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return man->parse;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovvoid
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovman_state(struct roff_man *man, struct roff_node *n)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov switch(n->tok) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case MAN_nf:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case MAN_EX:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (man->flags & MAN_LITERAL && ! (n->flags & MAN_VALID))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov mandoc_msg(MANDOCERR_NF_SKIP, man->parse,
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->line, n->pos, "nf");
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->flags |= MAN_LITERAL;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov break;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case MAN_fi:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case MAN_EE:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if ( ! (man->flags & MAN_LITERAL) &&
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov ! (n->flags & MAN_VALID))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov mandoc_msg(MANDOCERR_FI_SKIP, man->parse,
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov n->line, n->pos, "fi");
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->flags &= ~MAN_LITERAL;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov break;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov default:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->last->flags |= MAN_VALID;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov}
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovvoid
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovman_validate(struct roff_man *man)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->last = man->first;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man_node_validate(man);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man->flags &= ~MAN_LITERAL;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov}