371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov/* $Id: mdoc_validate.c,v 1.301 2016/01/08 17:48:09 schwarze Exp $ */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * Copyright (c) 2010-2016 Ingo Schwarze <schwarze@openbsd.org>
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
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.
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/* FIXME: .Bl -diag can't have non-text children in HEAD. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic void check_text(struct roff_man *, int, int, char *);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic void check_args(struct roff_man *, struct roff_node *);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic void rewrite_macro2len(char **);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov post_hyph, /* %B */ /* FIXME: can be used outside Rs/Re. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov post_hyph, /* %T */ /* FIXME: can be used outside Rs/Re. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#define RSORD_MAX 14 /* Number of `Rs' blocks. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic const char * const secnames[SEC__MAX] = {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "DESCRIPTION",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "IMPLEMENTATION NOTES",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "RETURN VALUES",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "ENVIRONMENT",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "EXIT STATUS",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "DIAGNOSTICS",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "COMPATIBILITY",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "SECURITY CONSIDERATIONS",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore switch (n->type) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (n->sec != SEC_SYNOPSIS || n->parent->tok != MDOC_Fd)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Closing delimiters are not special at the
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * beginning of a block, opening delimiters
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * are not special at the end.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Call the macro's postprocessor. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovcheck_args(struct roff_man *mdoc, struct roff_node *n)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovcheck_argv(struct roff_man *mdoc, struct roff_node *n, struct mdoc_argv *v)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore for (i = 0; i < (int)v->sz; i++)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore check_text(mdoc, v->line, v->pos, v->value[i]);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovcheck_text(struct roff_man *mdoc, int ln, int pos, char *p)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore for (cp = p; NULL != (p = strchr(p, '\t')); p++)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * First figure out which kind of list to use: bind ourselves to
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * the first mentioned list type and warn about any remaining
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * ones. If we find no list type, we default to LIST_item.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore for (i = 0; n->args && i < (int)n->args->argc; i++) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Set list types. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Set list arguments. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Check: multiple list types. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* The list type should come first. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Allow lists to default to LIST_item. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Validate the width field. Some list types don't need width
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * types and should be warned about them. Others should have it
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * and must also be warned. Yet others have a default and need
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * no warning.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore for (i = 0; n->args && i < (int)n->args->argc; i++) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (n->type == ROFFT_ELEM || n->type == ROFFT_BLOCK)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Unlike other data pointers, these are "housed" by the HEAD
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * element, which contains the goods.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Check the number of arguments. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Extract argument into data. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Extract parameter into data. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (NULL == (stdlibname = mdoc_a2lib(n->string)))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov const struct roff_node *n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov const struct roff_node *n;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*')))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov const struct roff_node *n;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov const struct roff_node *n;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov for (n = mdoc->last->child; n != NULL; n = n->next) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Ignore callbacks and alterations. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov switch (n->type) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov for (np = n->parent; np != NULL; np = np->parent) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (np->type == ROFFT_BLOCK && np->tok == MDOC_Bd) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * The `Ar' defaults to "file ..." if no value is provided as an
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * argument; the `Mt' and `Pa' macros use "~"; the `Li' just
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * gets an empty string.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_word_alloc(mdoc, nn->line, nn->pos, "file");
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_word_alloc(mdoc, nn->line, nn->pos, "...");
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_word_alloc(mdoc, n->line, n->pos, "AT&T UNIX");
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If we have a child, look it up in the standard keys. If a
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * key exist, use that instead of the child; if it doesn't,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * prefix "AT&T UNIX " to the existing data.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if ((std_att = mdoc_a2att(n->string)) == NULL) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_asprintf(&att, "AT&T UNIX %s", n->string);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "Bl -%s It",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (nit->body == NULL || nit->body->child == NULL)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "Bl -%s It",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov for (nch = nit->child; nch != NULL; nch = nch->next)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * These are fairly complicated, so we've broken them into two
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * functions. post_bl_block_tag() is called when a -tag is
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * specified, but no -width (it must be guessed). The second
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * when a -width is specified (macro indicators must be
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * rewritten into real lengths).
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov for (ni = n->body->child; ni != NULL; ni = ni->next) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "%s before It",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * If the argument of -offset or -width is a macro,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * replace it with the associated default width.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov else if ((tok = mdoc_hash_find(*arg)) == TOKEN_NONE)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Calculate the -width for a `Bl -tag' list if it hasn't been
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * provided. Uses the first head macro. NOTE AGAIN: this is
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * ONLY if the -width argument has NOT been provided. See
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * rewrite_macro2len() for converting the -width string.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov for (nn = n->body->child; nn != NULL; nn = nn->next) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Defaults to ten ens. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (void)snprintf(buf, sizeof(buf), "%un", (unsigned int)sz);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * We have to dynamically add this to the macro's argument list.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * We're guaranteed that a MDOC_Width doesn't already exist.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov n->args->argv = mandoc_reallocarray(n->args->argv,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore n->args->argv[i].value = mandoc_malloc(sizeof(char *));
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore n->args->argv[i].value[0] = mandoc_strdup(buf);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Set our width! */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore n->norm->Bl.width = n->args->argv[i].value[0];
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Append old-style lists, where the column width specifiers
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * trail as macro parameters, to the new-style ("normal-form")
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * lists where they're argument values following -column.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Accommodate for new-style groff column syntax. Shuffle the
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * child nodes, all of which must be TEXT, as arguments for the
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * column field. Then, delete the head children.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov for (nch = nh->child; nch != NULL; nch = nch->next)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov for (nch = nh->child; nch != NULL; nch = nnext) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *nparent, *nprev; /* of the Bl block */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *nblock, *nbody; /* of the Bl */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *nchild, *nnext; /* of the Bl body */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * Move the node out of the Bl block.
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * First, collect all required node pointers.
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * Unlink this child.
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * Relink this child.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (n->type == ROFFT_BLOCK && n->body->child == NULL) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "%s %s", mdoc_macronames[mdoc->last->tok], nch->string);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Add missing prologue data. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Check that we begin with a proper `Sh'. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_DOC_EMPTY, mdoc->parse, 0, 0, NULL);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const char *p;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * The full `Rs' block needs special handling to order the
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * sub-elements according to `rsord'. Pick through each element
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * and correctly order it. This is an insertion sort.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov for (nch = np->child->next; nch != NULL; nch = next) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Determine order number of this child. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore for (i = 0; i < RSORD_MAX; i++)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else if (nch->tok == MDOC__J || nch->tok == MDOC__B)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Remove this child from the chain. This somewhat
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * repeats roff_node_unlink(), but since we're
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * just re-ordering, there's no need for the
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * full unlink process.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Scan back until we reach a node that's
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * to be ordered before this child.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Determine order of `prev'. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore for (j = 0; j < RSORD_MAX; j++)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Set this child back into its correct place
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * in front of the `prev' node.
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * For some arguments of some macros,
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * convert all breakable hyphens into ASCII_HYPH.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov for (nch = mdoc->last->child; nch != NULL; nch = nch->next) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov for (n = mdoc->last->child; n != NULL; n = n->next) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov switch (n->tok) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* FALLTHROUGH */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov const struct roff_node *n;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (n != NULL) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Process one .Xr node. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (lastpunct[0] != ',' || lastpunct[1] != '\0')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if (cmp == 0 &&
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Process the following node. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if ((n->tok == MDOC_An && n->child != NULL) || child_an(n))
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Process a new section. Sections are either "named" or
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * "custom". Custom sections are user-defined, while named ones
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * follow a conventional order and may only appear in certain
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * manual sections.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* The NAME should be first. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_vmsg(MANDOCERR_NAMESEC_FIRST, mdoc->parse,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* The SYNOPSIS gets special attention in other areas. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Mark our last section. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* We don't care about custom sections after this. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Check whether our non-custom section is being repeated or is
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * out of order.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Mark the last named section. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Check particular section/manual conventions. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* FALLTHROUGH */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (n->type != ROFFT_ELEM && n->type != ROFFT_BLOCK)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * block: `Lp', `Pp', or non-compact `Bd' or `Bl'.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (n->tok == MDOC_It && n->parent->norm->Bl.comp)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (np->child != NULL && np->child->next != NULL)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov } else if (np->tok != MDOC_Pp && np->tok != MDOC_Lp &&
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "%s after %s", mdoc_macronames[mdoc->last->tok],
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (n->child == NULL || n->child->string[0] == '\0') {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mdoc->meta.date = mdoc->quick ? mandoc_strdup("") :
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_normdate(mdoc->parse, NULL, n->line, n->pos);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Mandatory first argument: title. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Check that all characters are uppercase. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (islower((unsigned char)*p)) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Mandatory second argument: section.�*/
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Infer volume title from section number. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Optional third argument: architecture. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *p = tolower((unsigned char)*p);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Ignore fourth and later arguments. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Make `Bx's second argument always start with an uppercase
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * letter. Groff checks if it's an "accepted" term, but we just
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * uppercase blindly.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if ((n = mdoc->last->child) != NULL && (n = n->next) != NULL)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *n->string = (char)toupper((unsigned char)*n->string);
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * Set the operating system by way of the `Os' macro.
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * The order of precedence is:
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * 1. the argument of the `Os' macro, unless empty
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * 2. the -Ios=foo command line argument, if provided
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * 3. -DOSNAME="\"foo\"", if provided during compilation
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * 4. "sysname release" from uname(3)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#else /*!OSNAME */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#endif /*!OSNAME*/
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * If no argument is provided,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * fill in the name of the current manual page.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov roff_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov for (i = 0; i < (int)SEC__MAX; i++)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (secnames[i] && 0 == strcmp(p, secnames[i]))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return (enum roff_sec)i;