root/usr/src/cmd/mandoc/mdoc_state.c
/* $Id: mdoc_state.c,v 1.17 2020/06/22 19:20:40 schwarze Exp $ */
/*
 * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
#include "config.h"

#include <sys/types.h>

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "mandoc.h"
#include "roff.h"
#include "mdoc.h"
#include "libmandoc.h"
#include "roff_int.h"
#include "libmdoc.h"

#define STATE_ARGS  struct roff_man *mdoc, struct roff_node *n

typedef void    (*state_handler)(STATE_ARGS);

static  void     state_bl(STATE_ARGS);
static  void     state_sh(STATE_ARGS);
static  void     state_sm(STATE_ARGS);

static  const state_handler state_handlers[MDOC_MAX - MDOC_Dd] = {
        NULL,           /* Dd */
        NULL,           /* Dt */
        NULL,           /* Os */
        state_sh,       /* Sh */
        NULL,           /* Ss */
        NULL,           /* Pp */
        NULL,           /* D1 */
        NULL,           /* Dl */
        NULL,           /* Bd */
        NULL,           /* Ed */
        state_bl,       /* Bl */
        NULL,           /* El */
        NULL,           /* It */
        NULL,           /* Ad */
        NULL,           /* An */
        NULL,           /* Ap */
        NULL,           /* Ar */
        NULL,           /* Cd */
        NULL,           /* Cm */
        NULL,           /* Dv */
        NULL,           /* Er */
        NULL,           /* Ev */
        NULL,           /* Ex */
        NULL,           /* Fa */
        NULL,           /* Fd */
        NULL,           /* Fl */
        NULL,           /* Fn */
        NULL,           /* Ft */
        NULL,           /* Ic */
        NULL,           /* In */
        NULL,           /* Li */
        NULL,           /* Nd */
        NULL,           /* Nm */
        NULL,           /* Op */
        NULL,           /* Ot */
        NULL,           /* Pa */
        NULL,           /* Rv */
        NULL,           /* St */
        NULL,           /* Va */
        NULL,           /* Vt */
        NULL,           /* Xr */
        NULL,           /* %A */
        NULL,           /* %B */
        NULL,           /* %D */
        NULL,           /* %I */
        NULL,           /* %J */
        NULL,           /* %N */
        NULL,           /* %O */
        NULL,           /* %P */
        NULL,           /* %R */
        NULL,           /* %T */
        NULL,           /* %V */
        NULL,           /* Ac */
        NULL,           /* Ao */
        NULL,           /* Aq */
        NULL,           /* At */
        NULL,           /* Bc */
        NULL,           /* Bf */
        NULL,           /* Bo */
        NULL,           /* Bq */
        NULL,           /* Bsx */
        NULL,           /* Bx */
        NULL,           /* Db */
        NULL,           /* Dc */
        NULL,           /* Do */
        NULL,           /* Dq */
        NULL,           /* Ec */
        NULL,           /* Ef */
        NULL,           /* Em */
        NULL,           /* Eo */
        NULL,           /* Fx */
        NULL,           /* Ms */
        NULL,           /* No */
        NULL,           /* Ns */
        NULL,           /* Nx */
        NULL,           /* Ox */
        NULL,           /* Pc */
        NULL,           /* Pf */
        NULL,           /* Po */
        NULL,           /* Pq */
        NULL,           /* Qc */
        NULL,           /* Ql */
        NULL,           /* Qo */
        NULL,           /* Qq */
        NULL,           /* Re */
        NULL,           /* Rs */
        NULL,           /* Sc */
        NULL,           /* So */
        NULL,           /* Sq */
        state_sm,       /* Sm */
        NULL,           /* Sx */
        NULL,           /* Sy */
        NULL,           /* Tn */
        NULL,           /* Ux */
        NULL,           /* Xc */
        NULL,           /* Xo */
        NULL,           /* Fo */
        NULL,           /* Fc */
        NULL,           /* Oo */
        NULL,           /* Oc */
        NULL,           /* Bk */
        NULL,           /* Ek */
        NULL,           /* Bt */
        NULL,           /* Hf */
        NULL,           /* Fr */
        NULL,           /* Ud */
        NULL,           /* Lb */
        NULL,           /* Lp */
        NULL,           /* Lk */
        NULL,           /* Mt */
        NULL,           /* Brq */
        NULL,           /* Bro */
        NULL,           /* Brc */
        NULL,           /* %C */
        NULL,           /* Es */
        NULL,           /* En */
        NULL,           /* Dx */
        NULL,           /* %Q */
        NULL,           /* %U */
        NULL,           /* Ta */
        NULL,           /* Tg */
};


void
mdoc_state(struct roff_man *mdoc, struct roff_node *n)
{
        state_handler handler;

        if (n->tok == TOKEN_NONE || n->tok < ROFF_MAX)
                return;

        assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
        if ((mdoc_macro(n->tok)->flags & MDOC_PROLOGUE) == 0)
                mdoc->flags |= MDOC_PBODY;

        handler = state_handlers[n->tok - MDOC_Dd];
        if (*handler)
                (*handler)(mdoc, n);
}

static void
state_bl(STATE_ARGS)
{
        struct mdoc_arg *args;
        size_t           i;

        if (n->type != ROFFT_HEAD || n->parent->args == NULL)
                return;

        args = n->parent->args;
        for (i = 0; i < args->argc; i++) {
                switch(args->argv[i].arg) {
                case MDOC_Diag:
                        n->norm->Bl.type = LIST_diag;
                        return;
                case MDOC_Column:
                        n->norm->Bl.type = LIST_column;
                        return;
                default:
                        break;
                }
        }
}

static void
state_sh(STATE_ARGS)
{
        struct roff_node *nch;
        char             *secname;

        if (n->type != ROFFT_HEAD)
                return;

        if ( ! (n->flags & NODE_VALID)) {
                secname = NULL;
                deroff(&secname, n);

                /*
                 * Set the section attribute for the BLOCK, HEAD,
                 * and HEAD children; the latter can only be TEXT
                 * nodes, so no recursion is needed.  For other
                 * nodes, including the .Sh BODY, this is done
                 * when allocating the node data structures, but
                 * for .Sh BLOCK and HEAD, the section is still
                 * unknown at that time.
                 */

                n->sec = n->parent->sec = secname == NULL ?
                    SEC_CUSTOM : mdoc_a2sec(secname);
                for (nch = n->child; nch != NULL; nch = nch->next)
                        nch->sec = n->sec;
                free(secname);
        }

        if ((mdoc->lastsec = n->sec) == SEC_SYNOPSIS) {
                roff_setreg(mdoc->roff, "nS", 1, '=');
                mdoc->flags |= MDOC_SYNOPSIS;
        } else {
                roff_setreg(mdoc->roff, "nS", 0, '=');
                mdoc->flags &= ~MDOC_SYNOPSIS;
        }
}

static void
state_sm(STATE_ARGS)
{

        if (n->child == NULL)
                mdoc->flags ^= MDOC_SMOFF;
        else if ( ! strcmp(n->child->string, "on"))
                mdoc->flags &= ~MDOC_SMOFF;
        else if ( ! strcmp(n->child->string, "off"))
                mdoc->flags |= MDOC_SMOFF;
}