[BACK]Return to mdoc_man.c CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / mandoc

File: [cvsweb.bsd.lv] / mandoc / mdoc_man.c (download)

Revision 1.1, Sat Sep 17 15:00:51 2011 UTC (12 years, 7 months ago) by schwarze
Branch: MAIN

Initial, incomplete support for -Tman
to convert mdoc(7) documents to the man(7) language.
This is work in progress and will be developed in tree.
It does already handle the cat(1) manual,
but will hardly handle all your fancy manuals yet.
go ahead  kristaps@ jmc@ millert@ deraadt@

/*	$Id: mdoc_man.c,v 1.1 2011/09/17 15:00:51 schwarze Exp $ */
/*
 * Copyright (c) 2011 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 <stdio.h>
#include <string.h>

#include "mandoc.h"
#include "mdoc.h"
#include "main.h"

static	int	  need_space = 0;
static	int	  need_nl = 0;

#define	DECL_ARGS const struct mdoc_meta *m, \
		  const struct mdoc_node *n

struct	manact {
	int		(*cond)(DECL_ARGS);
	int		(*pre)(DECL_ARGS);
	void		(*post)(DECL_ARGS);
	char		 *prefix;
	char		 *suffix;
};

static	void	  print_word(const char *);
static	void	  print_node(DECL_ARGS);

static	int	  cond_head(DECL_ARGS);
static	int	  cond_body(DECL_ARGS);
static	int	  pre_enc(DECL_ARGS);
static	void	  post_enc(DECL_ARGS);
static	void	  post_percent(DECL_ARGS);

static	int	  pre_dl(DECL_ARGS);
static	void	  post_dl(DECL_ARGS);
static	int	  pre_it(DECL_ARGS);
static	int	  pre_nm(DECL_ARGS);
static	void	  post_nm(DECL_ARGS);
static	int	  pre_ns(DECL_ARGS);
static	int	  pre_pp(DECL_ARGS);
static	int	  pre_sh(DECL_ARGS);
static	void	  post_sh(DECL_ARGS);
static	int	  pre_xr(DECL_ARGS);


static	const struct manact manacts[MDOC_MAX] = {
	{ NULL, NULL, NULL, NULL, NULL }, /* _Ap */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Dd */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Dt */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Os */
	{ NULL, pre_sh, post_sh, NULL, NULL }, /* Sh */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Ss */
	{ NULL, pre_pp, NULL, NULL, NULL }, /* Pp */
	{ NULL, NULL, NULL, NULL, NULL }, /* _D1 */
	{ cond_body, pre_dl, post_dl, NULL, NULL }, /* Dl */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Bd */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Ed */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Bl */
	{ NULL, NULL, NULL, NULL, NULL }, /* _El */
	{ NULL, pre_it, NULL, NULL, NULL }, /* _It */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Ad */
	{ NULL, NULL, NULL, NULL, NULL }, /* _An */
	{ NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Ar */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Cd */
	{ NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Cm */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Dv */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Er */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Ev */
	{ NULL, pre_enc, post_enc, "The \\fB",
	    "\\fP\nutility exits 0 on success, and >0 if an error occurs."
	    }, /* Ex */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Fa */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Fd */
	{ NULL, pre_enc, post_enc, "\\fB-", "\\fP" }, /* Fl */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Fn */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Ft */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Ic */
	{ NULL, NULL, NULL, NULL, NULL }, /* _In */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Li */
	{ cond_head, pre_enc, NULL, "\\- ", NULL }, /* Nd */
	{ NULL, pre_nm, post_nm, NULL, NULL }, /* Nm */
	{ cond_body, pre_enc, post_enc, "[", "]" }, /* Op */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Ot */
	{ NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* _Pa */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Rv */
	{ NULL, NULL, NULL, NULL, NULL }, /* _St */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Va */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Vt */
	{ NULL, pre_xr, NULL, NULL, NULL }, /* _Xr */
	{ NULL, NULL, post_percent, NULL, NULL }, /* _%A */
	{ NULL, NULL, NULL, NULL, NULL }, /* _%B */
	{ NULL, NULL, post_percent, NULL, NULL }, /* _%D */
	{ NULL, NULL, NULL, NULL, NULL }, /* _%I */
	{ NULL, pre_enc, post_percent, "\\fI", "\\fP" }, /* %J */
	{ NULL, NULL, NULL, NULL, NULL }, /* _%N */
	{ NULL, NULL, NULL, NULL, NULL }, /* _%O */
	{ NULL, NULL, NULL, NULL, NULL }, /* _%P */
	{ NULL, NULL, NULL, NULL, NULL }, /* _%R */
	{ NULL, pre_enc, post_percent, "\"", "\"" }, /* %T */
	{ NULL, NULL, NULL, NULL, NULL }, /* _%V */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Ac */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Ao */
	{ cond_body, pre_enc, post_enc, "<", ">" }, /* Aq */
	{ NULL, NULL, NULL, NULL, NULL }, /* _At */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Bc */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Bf */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Bo */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Bq */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Bsx */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Bx */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Db */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Dc */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Do */
	{ cond_body, pre_enc, post_enc, "``", "''" }, /* Dq */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Ec */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Ef */
	{ NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* _Em */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Eo */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Fx */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Ms */
	{ NULL, NULL, NULL, NULL, NULL }, /* _No */
	{ NULL, pre_ns, NULL, NULL, NULL }, /* Ns */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Nx */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Ox */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Pc */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Pf */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Po */
	{ cond_body, pre_enc, post_enc, "(", ")" }, /* _Pq */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Qc */
	{ cond_body, pre_enc, post_enc, "`", "'" }, /* Ql */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Qo */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Qq */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Re */
	{ cond_body, pre_pp, NULL, NULL, NULL }, /* Rs */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Sc */
	{ NULL, NULL, NULL, NULL, NULL }, /* _So */
	{ cond_body, pre_enc, post_enc, "`", "'" }, /* Sq */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Sm */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Sx */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Sy */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Tn */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Ux */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Xc */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Xo */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Fo */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Fc */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Oo */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Oc */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Bk */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Ek */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Bt */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Hf */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Fr */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Ud */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Lb */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Lp */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Lk */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Mt */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Brq */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Bro */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Brc */
	{ NULL, NULL, NULL, NULL, NULL }, /* _%C */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Es */
	{ NULL, NULL, NULL, NULL, NULL }, /* _En */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Dx */
	{ NULL, NULL, NULL, NULL, NULL }, /* _%Q */
	{ NULL, NULL, NULL, NULL, NULL }, /* _br */
	{ NULL, NULL, NULL, NULL, NULL }, /* _sp */
	{ NULL, NULL, NULL, NULL, NULL }, /* _%U */
	{ NULL, NULL, NULL, NULL, NULL }, /* _Ta */
};


static void
print_word(const char *s)
{
	if (need_nl) {
		putchar('\n');
		need_space = 0;
		need_nl = 0;
	} else if (need_space &&
	    (NULL == strchr(".,:;)]?!", s[0]) || '\0' != s[1]))
		putchar(' ');
	need_space = ('(' != s[0] && '[' != s[0]) || '\0' != s[1];
	for ( ; *s; s++) {
		switch (*s) {
		case (ASCII_NBRSP):
			printf("\\~");
			break;
		case (ASCII_HYPH):
			putchar('-');
			break;
		default:
			putchar(*s);
			break;
		}
	}
}

void
man_mdoc(void *arg, const struct mdoc *mdoc)
{
	const struct mdoc_meta *m;
	const struct mdoc_node *n;

	m = mdoc_meta(mdoc);
	n = mdoc_node(mdoc);

	printf(".TH \"%s\" \"%s\" \"%s\"", m->title, m->msec, m->date);
	need_nl = 1;
	need_space = 0;

	print_node(m, n);
}

static void
print_node(DECL_ARGS)
{
	const struct mdoc_node	*prev, *sub;
	const struct manact	*act = NULL;
	int			 cond, do_sub;

	prev = n->prev ? n->prev : n->parent;
	if (prev && prev->line < n->line)
		need_nl = 1;

	cond = 0;
	do_sub = 1;
	if (MDOC_TEXT == n->type) {
		print_word(n->string);
	} else {
		act = manacts + n->tok;
		cond = NULL == act->cond || (*act->cond)(m, n);
		if (cond && act->pre)
			do_sub = (*act->pre)(m, n);
	}

	if (do_sub)
		for (sub = n->child; sub; sub = sub->next)
			print_node(m, sub);

	if (cond && act->post)
		(*act->post)(m, n);
}

static int
cond_head(DECL_ARGS)
{
	return(MDOC_HEAD == n->type);
}

static int
cond_body(DECL_ARGS)
{
	return(MDOC_BODY == n->type);
}

static int
pre_enc(DECL_ARGS)
{
	const char *prefix;

	prefix = manacts[n->tok].prefix;
	if (NULL == prefix)
		return(1);
	print_word(prefix);
	need_space = 0;
	return(1);
}

static void
post_enc(DECL_ARGS)
{
	const char *suffix;

	suffix = manacts[n->tok].suffix;
	if (NULL == suffix)
		return;
	need_space = 0;
	print_word(suffix);
}

static void
post_percent(DECL_ARGS)
{

	post_enc(m, n);
	if (n->next)
		print_word(",");
	else {
		print_word(".");
		need_nl = 1;
	}
}

static int
pre_dl(DECL_ARGS)
{

	need_nl = 1;
	print_word(".RS 6n");
	need_nl = 1;
	return(1);
}

static void
post_dl(DECL_ARGS)
{

	need_nl = 1;
	print_word(".RE");
	need_nl = 1;
}

static int
pre_it(DECL_ARGS)
{
	const struct mdoc_node *bln;

	if (MDOC_HEAD == n->type) {
		need_nl = 1;
		print_word(".TP");
		bln = n->parent->parent->prev;
		print_word(bln->norm->Bl.width);
		need_nl = 1;
	}
	return(1);
}

static int
pre_nm(DECL_ARGS)
{

	if (MDOC_ELEM != n->type && MDOC_HEAD != n->type)
		return(1);
	print_word("\\fB");
	need_space = 0;
	if (NULL == n->child)
		print_word(m->name);
	return(1);
}

static void
post_nm(DECL_ARGS)
{

	if (MDOC_ELEM != n->type && MDOC_HEAD != n->type)
		return;
	need_space = 0;
	print_word("\\fP");
}

static int
pre_ns(DECL_ARGS)
{

	need_space = 0;
	return(0);
}

static int
pre_pp(DECL_ARGS)
{

	need_nl = 1;
	if (MDOC_It == n->parent->tok)
		print_word(".sp");
	else
		print_word(".PP");
	need_nl = 1;
	return(1);
}

static int
pre_sh(DECL_ARGS)
{

	if (MDOC_HEAD != n->type)
		return(1);
	need_nl = 1;
	print_word(".SH \"");
	need_space = 0;
	return(1);
}

static void
post_sh(DECL_ARGS)
{

	if (MDOC_HEAD != n->type)
		return;
	need_space = 0;
	print_word("\"");
	need_nl = 1;
}

static int
pre_xr(DECL_ARGS)
{

	n = n->child;
	if (NULL == n)
		return(0);
	print_node(m, n);
	n = n->next;
	if (NULL == n)
		return(0);
	need_space = 0;
	print_word("(");
	print_node(m, n);
	print_word(")");
	return(0);
}