/* $OpenBSD: mdoc_state.c,v 1.9 2017/11/29 20:04:36 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 <sys/types.h> #include <assert.h> #include <stdlib.h> #include <string.h> #include "mandoc.h" #include "roff.h" #include "mdoc.h" #include "libmandoc.h" #include "libmdoc.h" #define STATE_ARGS struct roff_man *mdoc, struct roff_node *n typedef void (*state_handler)(STATE_ARGS); static void state_bd(STATE_ARGS); static void state_bl(STATE_ARGS); static void state_dl(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 */ state_dl, /* Dl */ state_bd, /* 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 */ }; static const state_handler *const state_handlers = __state_handlers - MDOC_Dd; 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_macros[n->tok].flags & MDOC_PROLOGUE)) mdoc->flags |= MDOC_PBODY; handler = state_handlers[n->tok]; if (*handler) (*handler)(mdoc, n); } void mdoc_state_reset(struct roff_man *mdoc) { roff_setreg(mdoc->roff, "nS", 0, '='); mdoc->flags = 0; } static void state_bd(STATE_ARGS) { enum mdocargt arg; if (n->type != ROFFT_HEAD && (n->type != ROFFT_BODY || n->end != ENDBODY_NOT)) return; if (n->parent->args == NULL) return; arg = n->parent->args->argv[0].arg; if (arg != MDOC_Literal && arg != MDOC_Unfilled) return; state_dl(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_dl(STATE_ARGS) { switch (n->type) { case ROFFT_HEAD: mdoc->flags |= MDOC_LITERAL; break; case ROFFT_BODY: mdoc->flags &= ~MDOC_LITERAL; break; 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; }