Home | History | Annotate | Line # | Download | only in dist
      1 /*	Id: man.c,v 1.187 2019/01/05 00:36:50 schwarze Exp  */
      2 /*
      3  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps (at) bsd.lv>
      4  * Copyright (c) 2013-2015, 2017-2019 Ingo Schwarze <schwarze (at) openbsd.org>
      5  * Copyright (c) 2011 Joerg Sonnenberger <joerg (at) netbsd.org>
      6  *
      7  * Permission to use, copy, modify, and distribute this software for any
      8  * purpose with or without fee is hereby granted, provided that the above
      9  * copyright notice and this permission notice appear in all copies.
     10  *
     11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
     12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
     14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18  */
     19 #include "config.h"
     20 
     21 #include <sys/types.h>
     22 
     23 #include <assert.h>
     24 #include <ctype.h>
     25 #include <stdarg.h>
     26 #include <stdlib.h>
     27 #include <stdio.h>
     28 #include <string.h>
     29 
     30 #include "mandoc_aux.h"
     31 #include "mandoc.h"
     32 #include "roff.h"
     33 #include "man.h"
     34 #include "libmandoc.h"
     35 #include "roff_int.h"
     36 #include "libman.h"
     37 
     38 static	char		*man_hasc(char *);
     39 static	int		 man_ptext(struct roff_man *, int, char *, int);
     40 static	int		 man_pmacro(struct roff_man *, int, char *, int);
     41 
     42 
     43 int
     44 man_parseln(struct roff_man *man, int ln, char *buf, int offs)
     45 {
     46 
     47 	if (man->last->type != ROFFT_EQN || ln > man->last->line)
     48 		man->flags |= MAN_NEWLINE;
     49 
     50 	return roff_getcontrol(man->roff, buf, &offs) ?
     51 	    man_pmacro(man, ln, buf, offs) :
     52 	    man_ptext(man, ln, buf, offs);
     53 }
     54 
     55 /*
     56  * If the string ends with \c, return a pointer to the backslash.
     57  * Otherwise, return NULL.
     58  */
     59 static char *
     60 man_hasc(char *start)
     61 {
     62 	char	*cp, *ep;
     63 
     64 	ep = strchr(start, '\0') - 2;
     65 	if (ep < start || ep[0] != '\\' || ep[1] != 'c')
     66 		return NULL;
     67 	for (cp = ep; cp > start; cp--)
     68 		if (cp[-1] != '\\')
     69 			break;
     70 	return (ep - cp) % 2 ? NULL : ep;
     71 }
     72 
     73 void
     74 man_descope(struct roff_man *man, int line, int offs, char *start)
     75 {
     76 	/* Trailing \c keeps next-line scope open. */
     77 
     78 	if (start != NULL && man_hasc(start) != NULL)
     79 		return;
     80 
     81 	/*
     82 	 * Co-ordinate what happens with having a next-line scope open:
     83 	 * first close out the element scopes (if applicable),
     84 	 * then close out the block scope (also if applicable).
     85 	 */
     86 
     87 	if (man->flags & MAN_ELINE) {
     88 		while (man->last->parent->type != ROFFT_ROOT &&
     89 		    man_macro(man->last->parent->tok)->flags & MAN_ESCOPED)
     90 			man_unscope(man, man->last->parent);
     91 		man->flags &= ~MAN_ELINE;
     92 	}
     93 	if ( ! (man->flags & MAN_BLINE))
     94 		return;
     95 	man_unscope(man, man->last->parent);
     96 	roff_body_alloc(man, line, offs, man->last->tok);
     97 	man->flags &= ~(MAN_BLINE | ROFF_NONOFILL);
     98 }
     99 
    100 static int
    101 man_ptext(struct roff_man *man, int line, char *buf, int offs)
    102 {
    103 	int		 i;
    104 	char		*ep;
    105 
    106 	/* In no-fill mode, whitespace is preserved on text lines. */
    107 
    108 	if (man->flags & ROFF_NOFILL) {
    109 		roff_word_alloc(man, line, offs, buf + offs);
    110 		man_descope(man, line, offs, buf + offs);
    111 		return 1;
    112 	}
    113 
    114 	for (i = offs; buf[i] == ' '; i++)
    115 		/* Skip leading whitespace. */ ;
    116 
    117 	/*
    118 	 * Blank lines are ignored in next line scope
    119 	 * and right after headings and cancel preceding \c,
    120 	 * but add a single vertical space elsewhere.
    121 	 */
    122 
    123 	if (buf[i] == '\0') {
    124 		if (man->flags & (MAN_ELINE | MAN_BLINE)) {
    125 			mandoc_msg(MANDOCERR_BLK_BLANK, line, 0, NULL);
    126 			return 1;
    127 		}
    128 		if (man->last->tok == MAN_SH || man->last->tok == MAN_SS)
    129 			return 1;
    130 		if (man->last->type == ROFFT_TEXT &&
    131 		    ((ep = man_hasc(man->last->string)) != NULL)) {
    132 			*ep = '\0';
    133 			return 1;
    134 		}
    135 		roff_elem_alloc(man, line, offs, ROFF_sp);
    136 		man->next = ROFF_NEXT_SIBLING;
    137 		return 1;
    138 	}
    139 
    140 	/*
    141 	 * Warn if the last un-escaped character is whitespace. Then
    142 	 * strip away the remaining spaces (tabs stay!).
    143 	 */
    144 
    145 	i = (int)strlen(buf);
    146 	assert(i);
    147 
    148 	if (' ' == buf[i - 1] || '\t' == buf[i - 1]) {
    149 		if (i > 1 && '\\' != buf[i - 2])
    150 			mandoc_msg(MANDOCERR_SPACE_EOL, line, i - 1, NULL);
    151 
    152 		for (--i; i && ' ' == buf[i]; i--)
    153 			/* Spin back to non-space. */ ;
    154 
    155 		/* Jump ahead of escaped whitespace. */
    156 		i += '\\' == buf[i] ? 2 : 1;
    157 
    158 		buf[i] = '\0';
    159 	}
    160 	roff_word_alloc(man, line, offs, buf + offs);
    161 
    162 	/*
    163 	 * End-of-sentence check.  If the last character is an unescaped
    164 	 * EOS character, then flag the node as being the end of a
    165 	 * sentence.  The front-end will know how to interpret this.
    166 	 */
    167 
    168 	assert(i);
    169 	if (mandoc_eos(buf, (size_t)i))
    170 		man->last->flags |= NODE_EOS;
    171 
    172 	man_descope(man, line, offs, buf + offs);
    173 	return 1;
    174 }
    175 
    176 static int
    177 man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
    178 {
    179 	struct roff_node *n;
    180 	const char	*cp;
    181 	size_t		 sz;
    182 	enum roff_tok	 tok;
    183 	int		 ppos;
    184 	int		 bline;
    185 
    186 	/* Determine the line macro. */
    187 
    188 	ppos = offs;
    189 	tok = TOKEN_NONE;
    190 	for (sz = 0; sz < 4 && strchr(" \t\\", buf[offs]) == NULL; sz++)
    191 		offs++;
    192 	if (sz > 0 && sz < 4)
    193 		tok = roffhash_find(man->manmac, buf + ppos, sz);
    194 	if (tok == TOKEN_NONE) {
    195 		mandoc_msg(MANDOCERR_MACRO, ln, ppos, "%s", buf + ppos - 1);
    196 		return 1;
    197 	}
    198 
    199 	/* Skip a leading escape sequence or tab. */
    200 
    201 	switch (buf[offs]) {
    202 	case '\\':
    203 		cp = buf + offs + 1;
    204 		mandoc_escape(&cp, NULL, NULL);
    205 		offs = cp - buf;
    206 		break;
    207 	case '\t':
    208 		offs++;
    209 		break;
    210 	default:
    211 		break;
    212 	}
    213 
    214 	/* Jump to the next non-whitespace word. */
    215 
    216 	while (buf[offs] == ' ')
    217 		offs++;
    218 
    219 	/*
    220 	 * Trailing whitespace.  Note that tabs are allowed to be passed
    221 	 * into the parser as "text", so we only warn about spaces here.
    222 	 */
    223 
    224 	if (buf[offs] == '\0' && buf[offs - 1] == ' ')
    225 		mandoc_msg(MANDOCERR_SPACE_EOL, ln, offs - 1, NULL);
    226 
    227 	/*
    228 	 * Some macros break next-line scopes; otherwise, remember
    229 	 * whether we are in next-line scope for a block head.
    230 	 */
    231 
    232 	man_breakscope(man, tok);
    233 	bline = man->flags & MAN_BLINE;
    234 
    235 	/*
    236 	 * If the line in next-line scope ends with \c, keep the
    237 	 * next-line scope open for the subsequent input line.
    238 	 * That is not at all portable, only groff >= 1.22.4
    239 	 * does it, but *if* this weird idiom occurs in a manual
    240 	 * page, that's very likely what the author intended.
    241 	 */
    242 
    243 	if (bline && man_hasc(buf + offs))
    244 		bline = 0;
    245 
    246 	/* Call to handler... */
    247 
    248 	(*man_macro(tok)->fp)(man, tok, ln, ppos, &offs, buf);
    249 
    250 	/* In quick mode (for mandocdb), abort after the NAME section. */
    251 
    252 	if (man->quick && tok == MAN_SH) {
    253 		n = man->last;
    254 		if (n->type == ROFFT_BODY &&
    255 		    strcmp(n->prev->child->string, "NAME"))
    256 			return 2;
    257 	}
    258 
    259 	/*
    260 	 * If we are in a next-line scope for a block head,
    261 	 * close it out now and switch to the body,
    262 	 * unless the next-line scope is allowed to continue.
    263 	 */
    264 
    265 	if (bline == 0 ||
    266 	    (man->flags & MAN_BLINE) == 0 ||
    267 	    man->flags & MAN_ELINE ||
    268 	    man_macro(tok)->flags & MAN_NSCOPED)
    269 		return 1;
    270 
    271 	man_unscope(man, man->last->parent);
    272 	roff_body_alloc(man, ln, ppos, man->last->tok);
    273 	man->flags &= ~(MAN_BLINE | ROFF_NONOFILL);
    274 	return 1;
    275 }
    276 
    277 void
    278 man_breakscope(struct roff_man *man, int tok)
    279 {
    280 	struct roff_node *n;
    281 
    282 	/*
    283 	 * An element next line scope is open,
    284 	 * and the new macro is not allowed inside elements.
    285 	 * Delete the element that is being broken.
    286 	 */
    287 
    288 	if (man->flags & MAN_ELINE && (tok < MAN_TH ||
    289 	    (man_macro(tok)->flags & MAN_NSCOPED) == 0)) {
    290 		n = man->last;
    291 		if (n->type == ROFFT_TEXT)
    292 			n = n->parent;
    293 		if (n->tok < MAN_TH ||
    294 		    (man_macro(n->tok)->flags & (MAN_NSCOPED | MAN_ESCOPED))
    295 		     == MAN_NSCOPED)
    296 			n = n->parent;
    297 
    298 		mandoc_msg(MANDOCERR_BLK_LINE, n->line, n->pos,
    299 		    "%s breaks %s", roff_name[tok], roff_name[n->tok]);
    300 
    301 		roff_node_delete(man, n);
    302 		man->flags &= ~MAN_ELINE;
    303 	}
    304 
    305 	/*
    306 	 * Weird special case:
    307 	 * Switching fill mode closes section headers.
    308 	 */
    309 
    310 	if (man->flags & MAN_BLINE &&
    311 	    (tok == ROFF_nf || tok == ROFF_fi) &&
    312 	    (man->last->tok == MAN_SH || man->last->tok == MAN_SS)) {
    313 		n = man->last;
    314 		man_unscope(man, n);
    315 		roff_body_alloc(man, n->line, n->pos, n->tok);
    316 		man->flags &= ~(MAN_BLINE | ROFF_NONOFILL);
    317 	}
    318 
    319 	/*
    320 	 * A block header next line scope is open,
    321 	 * and the new macro is not allowed inside block headers.
    322 	 * Delete the block that is being broken.
    323 	 */
    324 
    325 	if (man->flags & MAN_BLINE && tok != ROFF_nf && tok != ROFF_fi &&
    326 	    (tok < MAN_TH || man_macro(tok)->flags & MAN_XSCOPE)) {
    327 		n = man->last;
    328 		if (n->type == ROFFT_TEXT)
    329 			n = n->parent;
    330 		if (n->tok < MAN_TH ||
    331 		    (man_macro(n->tok)->flags & MAN_XSCOPE) == 0)
    332 			n = n->parent;
    333 
    334 		assert(n->type == ROFFT_HEAD);
    335 		n = n->parent;
    336 		assert(n->type == ROFFT_BLOCK);
    337 		assert(man_macro(n->tok)->flags & MAN_BSCOPED);
    338 
    339 		mandoc_msg(MANDOCERR_BLK_LINE, n->line, n->pos,
    340 		    "%s breaks %s", roff_name[tok], roff_name[n->tok]);
    341 
    342 		roff_node_delete(man, n);
    343 		man->flags &= ~(MAN_BLINE | ROFF_NONOFILL);
    344 	}
    345 }
    346