-# $OpenBSD: Makefile,v 1.42 2010/06/29 15:49:52 schwarze Exp $
+# $OpenBSD: Makefile,v 1.43 2010/07/13 01:09:12 schwarze Exp $
.include <bsd.own.mk>
-VERSION=1.10.3
+VERSION=1.10.4
CFLAGS+=-DVERSION=\"${VERSION}\"
CFLAGS+=-W -Wall -Wstrict-prototypes
-/* $Id: html.c,v 1.11 2010/06/27 20:28:56 schwarze Exp $ */
+/* $Id: html.c,v 1.12 2010/07/13 01:09:12 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
+ * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
t = NULL;
if ( ! (HTML_NOSPACE & h->flags))
- if ( ! (HTML_CLRLINE & htmltags[tag].flags))
- putchar(' ');
+ if ( ! (HTML_CLRLINE & htmltags[tag].flags)) {
+ /* Manage keeps! */
+ if ( ! (HTML_KEEP & h->flags)) {
+ if (HTML_PREKEEP & h->flags)
+ h->flags |= HTML_KEEP;
+ putchar(' ');
+ } else
+ printf(" ");
+ }
/* Print out the tag name and attributes. */
void
-print_text(struct html *h, const char *p)
+print_text(struct html *h, const char *word)
{
- if (*p && 0 == *(p + 1))
- switch (*p) {
+ if (word[0] && '\0' == word[1])
+ switch (word[0]) {
case('.'):
/* FALLTHROUGH */
case(','):
break;
}
- if ( ! (h->flags & HTML_NOSPACE))
- putchar(' ');
+ if ( ! (HTML_NOSPACE & h->flags)) {
+ /* Manage keeps! */
+ if ( ! (HTML_KEEP & h->flags)) {
+ if (HTML_PREKEEP & h->flags)
+ h->flags |= HTML_KEEP;
+ putchar(' ');
+ } else
+ printf(" ");
+ }
- assert(p);
- if ( ! print_encode(h, p, 0))
+ assert(word);
+ if ( ! print_encode(h, word, 0))
h->flags &= ~HTML_NOSPACE;
/*
* Note that we don't process the pipe: the parser sees it as
* punctuation, but we don't in terms of typography.
*/
- if (*p && 0 == *(p + 1))
- switch (*p) {
+ if (word[0] && '\0' == word[1])
+ switch (word[0]) {
case('('):
/* FALLTHROUGH */
case('['):
-/* $Id: html.h,v 1.6 2010/04/07 23:15:05 schwarze Exp $ */
+/* $Id: html.h,v 1.7 2010/07/13 01:09:12 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
+ * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
struct html {
int flags;
#define HTML_NOSPACE (1 << 0)
-#define HTML_IGNDELIM (1 << 2)
+#define HTML_IGNDELIM (1 << 1)
+#define HTML_KEEP (1 << 2)
+#define HTML_PREKEEP (1 << 3)
struct tagq tags;
struct ordq ords;
void *symtab;
-/* $Id: libman.h,v 1.23 2010/06/27 21:54:41 schwarze Exp $ */
+/* $Id: libman.h,v 1.24 2010/07/13 01:09:12 schwarze Exp $ */
/*
- * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
#ifndef LIBMAN_H
#define LIBMAN_H
-#include "regs.h"
#include "man.h"
enum man_next {
-/* $Id: libmdoc.h,v 1.40 2010/07/01 22:31:52 schwarze Exp $ */
+/* $Id: libmdoc.h,v 1.41 2010/07/13 01:09:12 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
#ifndef LIBMDOC_H
#define LIBMDOC_H
-#include "regs.h"
#include "mdoc.h"
enum mdoc_next {
-/* $Id: main.c,v 1.41 2010/07/01 15:36:59 schwarze Exp $ */
+/* $Id: main.c,v 1.42 2010/07/13 01:09:12 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2010 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
#include <unistd.h>
#include "mandoc.h"
-#include "regs.h"
#include "main.h"
#include "mdoc.h"
#include "man.h"
"no title in document",
"missing list type",
"missing display type",
+ "missing font type",
"line argument(s) will be lost",
"body argument(s) will be lost",
"generic fatal error",
"column syntax is inconsistent",
- "missing font type",
"displays may not be nested",
"unsupported display type",
"blocks badly nested",
-.\" $Id: man.3,v 1.12 2010/06/27 21:54:42 schwarze Exp $
+.\" $Id: man.3,v 1.13 2010/07/13 01:09:12 schwarze Exp $
.\"
.\" Copyright (c) 2009-2010 Kristaps Dzonsons <kristaps@bsd.lv>
.\"
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: June 27 2010 $
+.Dd $Mdocdate: July 13 2010 $
.Dt MAN 3
.Os
.Sh NAME
.Nd man macro compiler library
.Sh SYNOPSIS
.In mandoc.h
-.In regs.h
.In man.h
.Vt extern const char * const * man_macronames;
.Ft "struct man *"
-/* $Id: man.c,v 1.35 2010/06/27 21:54:42 schwarze Exp $ */
+/* $Id: man.c,v 1.36 2010/07/13 01:09:13 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
#include <string.h>
#include "mandoc.h"
-#include "regs.h"
#include "libman.h"
#include "libmandoc.h"
-/* $Id: man_html.c,v 1.16 2010/06/27 21:54:42 schwarze Exp $ */
+/* $Id: man_html.c,v 1.17 2010/07/13 01:09:13 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
#include "mandoc.h"
#include "out.h"
#include "html.h"
-#include "regs.h"
#include "man.h"
#include "main.h"
-/* $Id: man_term.c,v 1.43 2010/06/27 21:54:42 schwarze Exp $ */
+/* $Id: man_term.c,v 1.44 2010/07/13 01:09:13 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
#include "mandoc.h"
#include "out.h"
-#include "regs.h"
#include "man.h"
#include "term.h"
#include "chars.h"
-.\" $OpenBSD: mandoc.1,v 1.34 2010/06/29 15:49:52 schwarze Exp $
+.\" $OpenBSD: mandoc.1,v 1.35 2010/07/13 01:09:13 schwarze Exp $
.\"
-.\" Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+.\" Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: June 29 2010 $
+.Dd $Mdocdate: July 13 2010 $
.Dt MANDOC 1
.Os
.Sh NAME
.Qq Adobe-3.0
Level-2 pages may be generated by
.Fl T Ns Cm ps .
-Output pages are US-letter sized and rendered in fixed, 10-point Courier
-font.
+Output pages default to letter sized and are rendered in the Times font
+family, 11-point.
+Margins are calculated as 1/9 the page length and width.
+Line-height is 1.4m.
.Pp
Special characters are rendered as in
.Sx ASCII Output .
The paper size
.Ar name
may be one of
-.Ar a4
+.Ar a3 ,
+.Ar a4 ,
+.Ar a5 ,
+.Ar legal ,
or
.Ar letter .
+You may also manually specify dimensions as
+.Ar NNxNN ,
+width by height in millimetres.
+If an unknown value is encountered,
+.Ar letter
+is used.
.El
.Ss XHTML Output
Output produced by
-/* $Id: mandoc.h,v 1.9 2010/07/01 15:36:59 schwarze Exp $ */
+/* $Id: mandoc.h,v 1.10 2010/07/13 01:09:13 schwarze Exp $ */
/*
* Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
#ifndef MANDOC_H
#define MANDOC_H
+/*
+ * This contains declarations that are available system-wide.
+ */
+
#define ASCII_NBRSP 31 /* non-breaking space */
#define ASCII_HYPH 30 /* breakable hyphen */
-
__BEGIN_DECLS
enum mandocerr {
MANDOCERR_NOTITLE, /* no title in document */
MANDOCERR_LISTTYPE, /* missing list type */
MANDOCERR_DISPTYPE, /* missing display type */
+ MANDOCERR_FONTTYPE, /* missing font type */
MANDOCERR_ARGSLOST, /* line argument(s) will be lost */
MANDOCERR_BODYLOST, /* body argument(s) will be lost */
MANDOCERR_COLUMNS, /* column syntax is inconsistent */
/* FIXME: this should be a MANDOCERR_ERROR */
- MANDOCERR_FONTTYPE, /* missing font type */
- /* FIXME: this should be a MANDOCERR_ERROR */
MANDOCERR_NESTEDDISP, /* displays may not be nested */
MANDOCERR_BADDISP, /* unsupported display type */
MANDOCERR_SCOPEFATAL, /* blocks badly nested */
MANDOCERR_MAX
};
-typedef int (*mandocmsg)(enum mandocerr,
- void *, int, int, const char *);
+enum regs {
+ REG_nS = 0, /* register: nS */
+ REG__MAX
+};
+
+/*
+ * A single register entity. If "set" is zero, the value of the
+ * register should be the default one, which is per-register. It's
+ * assumed that callers know which type in "v" corresponds to which
+ * register value.
+ */
+struct reg {
+ int set; /* whether set or not */
+ union {
+ unsigned u; /* unsigned integer */
+ } v;
+};
+
+/*
+ * The primary interface to setting register values is in libroff,
+ * although libmdoc and libman from time to time will manipulate
+ * registers (such as `.Sh SYNOPSIS' enabling REG_nS).
+ */
+struct regset {
+ struct reg regs[REG__MAX];
+};
+
+/*
+ * Callback function for warnings, errors, and fatal errors as they
+ * occur in the compilers libroff, libmdoc, and libman.
+ */
+typedef int (*mandocmsg)(enum mandocerr, void *,
+ int, int, const char *);
__END_DECLS
-.\" $Id: mdoc.3,v 1.10 2010/06/29 17:10:29 schwarze Exp $
+.\" $Id: mdoc.3,v 1.11 2010/07/13 01:09:13 schwarze Exp $
.\"
-.\" Copyright (c) 2009-2010 Kristaps Dzonsons <kristaps@bsd.lv>
+.\" Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
+.\" Copyright (c) 2010 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
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: June 29 2010 $
+.Dd $Mdocdate: July 13 2010 $
.Dt MDOC 3
.Os
.Sh NAME
.Nd mdoc macro compiler library
.Sh SYNOPSIS
.In mandoc.h
-.In regs.h
.In mdoc.h
.Vt extern const char * const * mdoc_macronames;
.Vt extern const char * const * mdoc_argnames;
Multiple body parts are only found in invocations of
.Sq \&Bl \-column ,
where a new body introduces a new phrase.
-.Ss Badly nested blocks
-A special kind of node is available to end the formatting
-associated with a given block before the physical end of that block.
-Such an ENDBODY node has a non-null
+.Ss Badly-nested Blocks
+The ENDBODY node is available to end the formatting associated
+with a given block before the physical end of that block.
+It has a non-null
.Va end
field, is of the BODY
.Va type ,
TEXT end
.Ed
.Pp
-Here, the formatting of the Ao block extends from TEXT ao to TEXT ac,
-while the formatting of the Bo block extends from TEXT bo to TEXT bc,
-rendering like this in
+Here, the formatting of the
+.Sq \&Ao
+block extends from TEXT ao to TEXT ac,
+while the formatting of the
+.Sq \&Bo
+block extends from TEXT bo to TEXT bc.
+It renders as follows in
.Fl T Ns Cm ascii
mode:
+.Pp
.Dl <ao [bo ac> bc] end
-Support for badly nested blocks is only provided for backward
+.Pp
+Support for badly-nested blocks is only provided for backward
compatibility with some older
.Xr mdoc 7
implementations.
-Using them in new code is stronly discouraged:
-Some frontends, in particular
-.Fl T Ns Cm html ,
-are unable to render them in any meaningful way,
-many other
-.Xr mdoc 7
-implementations do not support them, and even for those that do,
-the behaviour is not well-defined, in particular when using multiple
-levels of badly nested blocks.
+Using badly-nested blocks is
+.Em strongly discouraged :
+the
+.Fl T Ns Cm html
+and
+.Fl T Ns Cm xhtml
+front-ends are unable to render them in any meaningful way.
+Furthermore, behaviour when encountering badly-nested blocks is not
+consistent across troff implementations, especially when using multiple
+levels of badly-nested blocks.
.Sh EXAMPLES
The following example reads lines from stdin and parses them, operating
on the finished parse tree with
-.\" $Id: mdoc.7,v 1.38 2010/07/01 15:36:59 schwarze Exp $
+.\" $Id: mdoc.7,v 1.39 2010/07/13 01:09:13 schwarze Exp $
.\"
-.\" Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+.\" Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
+.\" Copyright (c) 2010 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
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: July 1 2010 $
+.Dd $Mdocdate: July 13 2010 $
.Dt MDOC 7
.Os
.Sh NAME
block. Does not have any tail arguments.
.Ss \&Bd
Begins a display block.
+Its syntax is as follows:
+.Bd -ragged -offset indent
+.Pf \. Sx \&Bd
+.Fl type
+.Op Fl offset Ar width
+.Op Fl compact
+.Ed
+.Pp
A display is collection of macros or text which may be collectively
offset or justified in a manner different from that
of the enclosing context.
The type must be provided first.
Secondary arguments are as follows:
.Bl -tag -width 12n -offset indent
-.It Fl offset Ar width
+.It Fl offset Ar val
Offset by the value of
-.Ar width ,
+.Ar val ,
which is interpreted as one of the following, specified in order:
.Bl -item
.It
twice
.Ar indent ;
.Ar left ,
-which has no effect ;
+which has no effect;
.Ar right ,
which justifies to the right margin; and
.Ar center ,
If not provided an argument, it will be ignored.
.It Fl compact
Do not assert a vertical space before the block.
-.It Fl file Ar file
-Prepend the file
-.Ar file
-before any text or macros within the block.
.El
.Pp
Examples:
and
.Sx \&Dl .
.Ss \&Bf
+Change the font mode for a scoped block of text.
+Its syntax is as follows:
+.Bd -ragged -offset indent
+.Pf \. Sx \&Bf
+.Oo
+.Fl emphasis | literal | symbolic |
+.Cm \&Em | \&Li | \&Sy
+.Oc
+.Ed
+.Pp
+The
+.Fl emphasis
+and
+.Cm \&Em
+argument are equivalent, as are
+.Fl symbolic
+and
+.Cm \&Sy,
+and
+.Fl literal
+and
+.Cm \&Li .
+Without an argument, this macro does nothing.
+The font mode continues until broken by a new font mode in a nested
+scope or
+.Sx \&Ef
+is encountered.
+.Pp
+See also
+.Sx \&Li ,
+.Sx \&Ef ,
+and
+.Sx \&Sy .
.Ss \&Bk
-Begins a keep block, containing a collection of macros or text
-to be kept together in the output.
-One argument is required; additional arguments are ignored.
-Currently, the only argument implemented is
-.Fl words ,
-requesting to keep together all words of the contained text
-on the same output line.
-A
-.Fl lines
-argument to keep together all lines of the contained text
-on the same page has been desired for a long time,
-but has never been implemented.
+Begins a collection of macros or text not breaking the line.
+Its syntax is as follows:
.Pp
-Examples:
+.D1 Pf \. Sx \&Bk Fl words
+.Pp
+Subsequent arguments are ignored.
+The
+.Fl words
+argument is required.
+.Pp
+Each line within a keep block is kept intact, so the following example
+will not break within each
+.Sx \&Op
+macro line:
.Bd -literal -offset indent
\&.Bk \-words
-\&.Op o Ar output_file
+\&.Op Fl f Ar flags
+\&.Op Fl o Ar output
\&.Ek
.Ed
+.Pp
+Be careful in using over-long lines within a keep block!
+Doing so will clobber the right margin.
.Ss \&Bl
Begins a list composed of one or more list entries.
+Its syntax is as follows:
+.Bd -ragged -offset indent
+.Pf \. Sx \&Bl
+.Fl type
+.Op Fl width Ar val
+.Op Fl offset Ar val
+.Op Fl compact
+.Op HEAD ...
+.Ed
+.Pp
A list is associated with a type, which is a required argument.
Other arguments are
.Fl width ,
and
.Sx \&Ux .
.Ss \&Ec
+Close a scope started by
+.Sx \&Eo .
+Its syntax is as follows:
+.Pp
+.D1 Pf \. Sx \&Ec Op Cm TERM
+.Pp
+The
+.Cm TERM
+argument is used as the enclosure tail, for example, specifying \e(rq
+will emulate
+.Sx \&Dc .
.Ss \&Ed
+End a display context started by
+.Sx \&Bd .
.Ss \&Ef
+Ends a font mode context started by
+.Sx \&Bf .
.Ss \&Ek
Ends a keep context started by
.Sx \&Bk .
.D1 \&.Em Warnings!
.D1 \&.Em Remarks :
.Ss \&En
+This macro is obsolete and not implemented.
.Ss \&Eo
+An arbitrary enclosure.
+Its syntax is as follows:
+.Pp
+.D1 Pf \. Sx \&Eo Op Cm TERM
+.Pp
+The
+.Cm TERM
+argument is used as the enclosure head, for example, specifying \e(lq
+will emulate
+.Sx \&Do .
.Ss \&Er
Display error constants.
.Pp
See also
.Sx \&Dv .
.Ss \&Es
+This macro is obsolete and not implemented.
.Ss \&Ev
Environmental variables such as those specified in
.Xr environ 7 .
See also
.Sx \&Fo .
.Ss \&Fc
+Ends a function context started by
+.Sx \&Fo .
.Ss \&Fd
Historically used to document include files.
This usage has been deprecated in favour of
and
.Sx \&Ux .
.Ss \&Hf
+This macro is obsolete and not implemented.
.Ss \&Ic
+Designate an internal or interactive command.
+This is similar to
+.Sx \&Cm
+but used for instructions rather than values.
+.Pp
+Examples:
+.D1 \&.Ic hash
+.D1 \&.Ic alias
+.Pp
+Note that using
+.Sx \&Bd No Fl literal
+or
+.Sx \&D1
+is preferred for displaying code; the
+.Sx \&Ic
+macro is used when referring to specific instructions.
.Ss \&In
An
.Qq include
.D1 \&.Lb libz
.D1 \&.Lb mdoc
.Ss \&Li
+Denotes text that should be in a literal font mode.
+Note that this is a presentation term and should not be used for
+stylistically decorating technical terms.
.Ss \&Lk
Format a hyperlink.
Its syntax is as follows:
See also
.Sx \&Mt .
.Ss \&Lp
+Synonym for
+.Sx \&Pp .
.Ss \&Ms
.Ss \&Mt
Format a
Examples:
.D1 \&.Mt discuss@manpages.bsd.lv
.Ss \&Nd
+A one-line description of the manual's content.
+This may only be invoked in the
+.Em SYNOPSIS
+section subsequent the
+.Sx \&Nm
+macro.
+.Pp
+Examples:
+.D1 \&.Sx \&Nd mdoc language reference
+.D1 \&.Sx \&Nd format and display UNIX manuals
+.Pp
+The
+.Sx \&Nd
+macro technically accepts child macros and terminates with a subsequent
+.Sx \&Sh
+invocation.
+Do not assume this behaviour: some
+.Xr whatis 1
+database generators are not smart enough to parse more than the line
+arguments and will display macros verbatim.
+.Pp
+See also
+.Sx \&Nm .
.Ss \&Nm
The name of the manual page, or \(em in particular in section 1, 6,
and 8 pages \(em of an additional command or feature documented in
.Sx \&Nm
to mark up the name of the manual page.
.Ss \&No
+A
+.Qq noop
+macro used to terminate prior macro contexts.
+.Pp
+Examples:
+.D1 \&.Sx \&Fl ab \&No cd \&Fl ef
.Ss \&Ns
.Ss \&Nx
Format the NetBSD version provided as an argument, or a default value if
and
.Sx \&Ux .
.Ss \&Oc
+Closes multi-line
+.Sx \&Oo
+context.
.Ss \&Oo
+Multi-line version of
+.Sx \&Op .
+.Pp
+Examples:
+.Bd -literal -offset indent
+\&.Oo
+\&.Op Fl flag Ns Ar value
+\&.Oc
+.Ed
.Ss \&Op
+Command-line option.
+Used when listing options to command-line utilities.
+Prints the argument(s) in brackets.
+.Pp
+Examples:
+.D1 \&.Op \&Fl a \&Ar b
+.D1 \&.Op \&Ar a | b
+.Pp
+See also
+.Sx \&Oo .
.Ss \&Os
Document operating system version.
This is the mandatory third macro of
and
.Sx \&Ux .
.Ss \&Pa
+A file-system path.
+.Pp
+Examples:
+.D1 \&.Pa /usr/bin/mandoc
+.D1 \&.Pa /usr/share/man/man7/mdoc.7
+.Pp
+See also
+.Sx \&Lk .
.Ss \&Pc
+Close parenthesised context opened by
+.Sx \&Po .
.Ss \&Pf
+Removes the space
+.Pq Qq prefix
+between its arguments.
+Its syntax is as follows:
+.Pp
+.D1 Pf \. \&Pf Cm prefix suffix
+.Pp
+The
+.Cm suffix
+argument may be a macro.
+.Pp
+Examples:
+.D1 \&.Pf \e. \&Sx \&Pf \&Cm prefix suffix
.Ss \&Po
+Multi-line version of
+.Sx \&Pq .
.Ss \&Pp
+Break a paragraph.
+This will assert vertical space between prior and subsequent macros
+and/or text.
.Ss \&Pq
+Parenthesised enclosure.
+.Pp
+See also
+.Sx \&Po .
.Ss \&Qc
.Ss \&Ql
.Ss \&Qo
and
.Sx \&Ox .
.Ss \&Va
+A variable name.
+.Pp
+Examples:
+.D1 \&.Va foo
+.D1 \&.Va const char *bar ;
.Ss \&Vt
A variable type.
This is also used for indicating global variables in the
and
.Fl offset Ar right
are disregarded in mandoc.
-Furthermore, the
+Furthermore, troff specifies a
.Fl file Ar file
-argument is not supported in mandoc.
+argument that is not supported in mandoc.
Lastly, since text is not right-justified in mandoc (or even groff),
.Fl ragged
and
-/* $Id: mdoc.c,v 1.60 2010/07/01 22:31:52 schwarze Exp $ */
+/* $Id: mdoc.c,v 1.61 2010/07/13 01:09:13 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2010 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
#include <time.h>
#include "mandoc.h"
-#include "regs.h"
#include "libmdoc.h"
#include "libmandoc.h"
}
-void
+static void
mdoc_node_free(struct mdoc_node *p)
{
+ /*
+ * XXX: if these end up being problematic in terms of memory
+ * management and dereferencing freed blocks, then make them
+ * into reference-counted double-pointers.
+ */
+
+ if (MDOC_Bd == p->tok && MDOC_BLOCK == p->type)
+ if (p->data.Bd)
+ free(p->data.Bd);
+ if (MDOC_Bl == p->tok && MDOC_BLOCK == p->type)
+ if (p->data.Bl)
+ free(p->data.Bl);
+ if (MDOC_Bf == p->tok && MDOC_HEAD == p->type)
+ if (p->data.Bf)
+ free(p->data.Bf);
+
if (p->string)
free(p->string);
if (p->args)
*/
if (MDOC_Bl == n->tok && MDOC_BODY == n->type &&
- LIST_column == n->data.Bl.type) {
+ LIST_column == n->data.Bl->type) {
/* `Bl' is open without any children. */
m->flags |= MDOC_FREECOL;
return(mdoc_macro(m, MDOC_It, line, offs, &offs, buf));
if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
NULL != n->parent &&
MDOC_Bl == n->parent->tok &&
- LIST_column == n->parent->data.Bl.type) {
+ LIST_column == n->parent->data.Bl->type) {
/* `Bl' has block-level `It' children. */
m->flags |= MDOC_FREECOL;
return(mdoc_macro(m, MDOC_It, line, offs, &offs, buf));
* Parse a macro line, that is, a line beginning with the control
* character.
*/
-int
+static int
mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs)
{
enum mdoct tok;
*/
if (MDOC_Bl == n->tok && MDOC_BODY == n->type &&
- LIST_column == n->data.Bl.type) {
+ LIST_column == n->data.Bl->type) {
m->flags |= MDOC_FREECOL;
if ( ! mdoc_macro(m, MDOC_It, ln, sv, &sv, buf))
goto err;
if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
NULL != n->parent &&
MDOC_Bl == n->parent->tok &&
- LIST_column == n->parent->data.Bl.type) {
+ LIST_column == n->parent->data.Bl->type) {
m->flags |= MDOC_FREECOL;
if ( ! mdoc_macro(m, MDOC_It, ln, sv, &sv, buf))
goto err;
-/* $Id: mdoc.h,v 1.30 2010/06/29 17:10:29 schwarze Exp $ */
+/* $Id: mdoc.h,v 1.31 2010/07/13 01:09:13 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
enum mdoc_endbody {
ENDBODY_NOT = 0,
ENDBODY_SPACE,
- ENDBODY_NOSPACE,
+ ENDBODY_NOSPACE
};
enum mdoc_list {
DISP_literal
};
+enum mdoc_auth {
+ AUTH__NONE = 0,
+ AUTH_split,
+ AUTH_nosplit
+};
+
+enum mdoc_font {
+ FONT__NONE = 0,
+ FONT_Em,
+ FONT_Li,
+ FONT_Sy
+};
+
struct mdoc_bd {
const char *offs; /* -offset */
enum mdoc_disp type; /* -ragged, etc. */
const char *offs; /* -offset */
enum mdoc_list type; /* -tag, -enum, etc. */
int comp; /* -compact */
+ size_t ncols; /* -column arg count */
+ const char **cols; /* -column val ptr */
+};
+
+struct mdoc_bf {
+ enum mdoc_font font; /* font */
+};
+
+struct mdoc_an {
+ enum mdoc_auth auth; /* -split, etc. */
};
/* Node in AST. */
enum mdoc_endbody end; /* BODY */
union {
- struct mdoc_bl Bl;
- struct mdoc_bd Bd;
+ struct mdoc_an An;
+ struct mdoc_bd *Bd;
+ struct mdoc_bf *Bf;
+ struct mdoc_bl *Bl;
} data;
};
-/* $Id: mdoc_action.c,v 1.42 2010/07/01 22:31:52 schwarze Exp $ */
+/* $Id: mdoc_action.c,v 1.43 2010/07/13 01:09:13 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
#include "libmdoc.h"
#include "libmandoc.h"
+/*
+ * FIXME: this file is deprecated. All future "actions" should be
+ * pushed into mdoc_validate.c.
+ */
+
#define POST_ARGS struct mdoc *m, struct mdoc_node *n
#define PRE_ARGS struct mdoc *m, struct mdoc_node *n
n->args->argv[i].value[0] = mandoc_strdup(buf);
/* Set our width! */
- n->data.Bl.width = n->args->argv[i].value[0];
+ n->data.Bl->width = n->args->argv[i].value[0];
return(1);
}
* the macro's width as set in share/tmac/mdoc/doc-common.
*/
- if (0 == strcmp(n->data.Bl.width, "Ds"))
+ if (0 == strcmp(n->data.Bl->width, "Ds"))
width = 6;
- else if (MDOC_MAX == (tok = mdoc_hash_find(n->data.Bl.width)))
+ else if (MDOC_MAX == (tok = mdoc_hash_find(n->data.Bl->width)))
return(1);
else if (0 == (width = mdoc_macro2len(tok)))
return(mdoc_nmsg(m, n, MANDOCERR_BADWIDTH));
n->args->argv[i].value[0] = mandoc_strdup(buf);
/* Set our width! */
- n->data.Bl.width = n->args->argv[i].value[0];
+ n->data.Bl->width = n->args->argv[i].value[0];
return(1);
}
int i, c;
struct mdoc_node *np, *nn, *nnp;
- if (LIST_column != n->data.Bl.type)
+ if (LIST_column != n->data.Bl->type)
return(1);
else if (NULL == n->child)
return(1);
np->args->argv[c].value = mandoc_malloc
((size_t)n->nchild * sizeof(char *));
+ n->data.Bl->ncols = np->args->argv[c].sz;
+ n->data.Bl->cols = (const char **)np->args->argv[c].value;
+
for (i = 0, nn = n->child; nn; i++) {
np->args->argv[c].value[i] = nn->string;
nn->string = NULL;
static int
post_bl(POST_ARGS)
{
- struct mdoc_node *nn;
- const char *ww;
if (MDOC_HEAD == n->type)
return(post_bl_head(m, n));
* rewritten into real lengths).
*/
- ww = n->data.Bl.width;
-
- if (LIST_tag == n->data.Bl.type && NULL == n->data.Bl.width) {
+ if (LIST_tag == n->data.Bl->type && NULL == n->data.Bl->width) {
if ( ! post_bl_tagwidth(m, n))
return(0);
- } else if (NULL != n->data.Bl.width) {
+ } else if (NULL != n->data.Bl->width) {
if ( ! post_bl_width(m, n))
return(0);
} else
return(1);
- assert(n->data.Bl.width);
-
- /* If it has changed, propogate new width to children. */
-
- if (ww == n->data.Bl.width)
- return(1);
-
- for (nn = n->child; nn; nn = nn->next)
- if (MDOC_Bl == nn->tok)
- nn->data.Bl.width = n->data.Bl.width;
-
+ assert(n->data.Bl->width);
return(1);
}
if (MDOC_BODY != n->type)
return(1);
- if (DISP_literal == n->data.Bd.type)
+ assert(n->data.Bd);
+ if (DISP_literal == n->data.Bd->type)
m->flags |= MDOC_LITERAL;
- if (DISP_unfilled == n->data.Bd.type)
+ if (DISP_unfilled == n->data.Bd->type)
m->flags |= MDOC_LITERAL;
return(1);
-/* $Id: mdoc_argv.c,v 1.31 2010/06/26 17:56:43 schwarze Exp $ */
+/* $Id: mdoc_argv.c,v 1.32 2010/07/13 01:09:13 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
if (MDOC_Bl == n->tok)
break;
- if (n && LIST_column == n->data.Bl.type) {
+ assert(n->data.Bl);
+ if (n && LIST_column == n->data.Bl->type) {
fl |= ARGS_TABSEP;
fl &= ~ARGS_DELIM;
}
-/* $Id: mdoc_html.c,v 1.24 2010/06/29 17:10:29 schwarze Exp $ */
+/* $Id: mdoc_html.c,v 1.25 2010/07/13 01:09:13 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
#include "mandoc.h"
#include "out.h"
#include "html.h"
-#include "regs.h"
#include "mdoc.h"
#include "main.h"
static int mdoc_ar_pre(MDOC_ARGS);
static int mdoc_bd_pre(MDOC_ARGS);
static int mdoc_bf_pre(MDOC_ARGS);
+static void mdoc_bk_post(MDOC_ARGS);
+static int mdoc_bk_pre(MDOC_ARGS);
static void mdoc_bl_post(MDOC_ARGS);
static int mdoc_bl_pre(MDOC_ARGS);
static void mdoc_bq_post(MDOC_ARGS);
{NULL, NULL}, /* Fc */
{mdoc_op_pre, mdoc_op_post}, /* Oo */
{NULL, NULL}, /* Oc */
- {NULL, NULL}, /* Bk */
+ {mdoc_bk_pre, mdoc_bk_post}, /* Bk */
{NULL, NULL}, /* Ek */
{mdoc_bt_pre, NULL}, /* Bt */
{NULL, NULL}, /* Hf */
print_text(h, n->string);
return;
default:
- if (mdocs[n->tok].pre && !n->end)
+ if (mdocs[n->tok].pre && ENDBODY_NOT == n->end)
child = (*mdocs[n->tok].pre)(m, n, h);
break;
}
+ if (HTML_KEEP & h->flags) {
+ if (n->prev && n->prev->line != n->line) {
+ h->flags &= ~HTML_KEEP;
+ h->flags |= HTML_PREKEEP;
+ } else if (NULL == n->prev) {
+ if (n->parent && n->parent->line != n->line) {
+ h->flags &= ~HTML_KEEP;
+ h->flags |= HTML_PREKEEP;
+ }
+ }
+ }
+
if (child && n->child)
print_mdoc_nodelist(m, n->child, h);
mdoc_root_post(m, n, h);
break;
default:
- if (mdocs[n->tok].post && !n->end)
+ if (mdocs[n->tok].post && ENDBODY_NOT == n->end)
(*mdocs[n->tok].post)(m, n, h);
break;
}
static int
mdoc_nm_pre(MDOC_ARGS)
{
- struct htmlpair tag;
+ struct htmlpair tag;
+ struct roffsu su;
+ const char *cp;
- if (NULL == n->child && NULL == m->name)
- return(1);
+ /*
+ * Accomodate for `Nm' being both an element (which may have
+ * NULL children AND no m->name) and a block.
+ */
- synopsis_pre(h, n);
+ cp = NULL;
+
+ if (MDOC_ELEM == n->type) {
+ if (NULL == n->child && NULL == m->name)
+ return(1);
+ synopsis_pre(h, n);
+ PAIR_CLASS_INIT(&tag, "name");
+ print_otag(h, TAG_SPAN, 1, &tag);
+ if (NULL == n->child)
+ print_text(h, m->name);
+ } else if (MDOC_BLOCK == n->type) {
+ synopsis_pre(h, n);
+
+ bufcat_style(h, "clear", "both");
+ if (n->head->child || m->name) {
+ if (n->head->child && MDOC_TEXT ==
+ n->head->child->type)
+ cp = n->head->child->string;
+ if (NULL == cp || '\0' == *cp)
+ cp = m->name;
+
+ SCALE_HS_INIT(&su, (double)strlen(cp));
+ bufcat_su(h, "padding-left", &su);
+ }
+
+ PAIR_STYLE_INIT(&tag, h);
+ print_otag(h, TAG_DIV, 1, &tag);
+ } else if (MDOC_HEAD == n->type) {
+ if (NULL == n->child && NULL == m->name)
+ return(1);
+
+ if (n->child && MDOC_TEXT == n->child->type)
+ cp = n->child->string;
+ if (NULL == cp || '\0' == *cp)
+ cp = m->name;
+
+ SCALE_HS_INIT(&su, (double)strlen(cp));
+
+ bufcat_style(h, "float", "left");
+ bufcat_su(h, "min-width", &su);
+ SCALE_INVERT(&su);
+ bufcat_su(h, "margin-left", &su);
+
+ PAIR_STYLE_INIT(&tag, h);
+ print_otag(h, TAG_DIV, 1, &tag);
+
+ if (NULL == n->child)
+ print_text(h, m->name);
+ } else if (MDOC_BODY == n->type) {
+ SCALE_HS_INIT(&su, 2);
+ bufcat_su(h, "margin-left", &su);
+ PAIR_STYLE_INIT(&tag, h);
+ print_otag(h, TAG_DIV, 1, &tag);
+ }
- PAIR_CLASS_INIT(&tag, "name");
- print_otag(h, TAG_SPAN, 1, &tag);
- if (NULL == n->child)
- print_text(h, m->name);
return(1);
}
static int
mdoc_it_pre(MDOC_ARGS)
{
- int i, wp, comp;
+ int i, comp;
const struct mdoc_node *bl, *nn;
struct roffsu width, offs;
enum mdoc_list type;
SCALE_HS_INIT(&offs, 0);
- type = bl->data.Bl.type;
- comp = bl->data.Bl.comp;
+ assert(bl->data.Bl);
+ type = bl->data.Bl->type;
+ comp = bl->data.Bl->comp;
- if (bl->data.Bl.offs)
- a2offs(bl->data.Bl.offs, &offs);
+ if (bl->data.Bl->offs)
+ a2offs(bl->data.Bl->offs, &offs);
switch (type) {
case (LIST_enum):
break;
}
- if (bl->data.Bl.width)
- a2width(bl->data.Bl.width, &width);
-
- wp = -1;
- for (i = 0; bl->args && i < (int)bl->args->argc; i++)
- switch (bl->args->argv[i].arg) {
- case (MDOC_Column):
- wp = i; /* Save for later. */
- break;
- default:
- break;
- }
+ if (bl->data.Bl->width)
+ a2width(bl->data.Bl->width, &width);
/* Override width in some cases. */
for (i = 0; nn && nn != n; nn = nn->next)
if (MDOC_BODY == nn->type)
i++;
- if (i < (int)bl->args->argv[wp].sz)
- a2width(bl->args->argv[wp].value[i], &width);
+ if (i < (int)bl->data.Bl->ncols)
+ a2width(bl->data.Bl->cols[i], &width);
}
if (MDOC_HEAD == n->type)
return(0);
if (MDOC_BLOCK != n->type)
return(1);
- if (LIST_enum != n->data.Bl.type)
+ assert(n->data.Bl);
+ if (LIST_enum != n->data.Bl->type)
return(1);
ord = malloc(sizeof(struct ord));
if (MDOC_BLOCK != n->type)
return;
- if (LIST_enum != n->data.Bl.type)
+ if (LIST_enum != n->data.Bl->type)
return;
ord = h->ords.head;
SCALE_VS_INIT(&su, 0);
- if (n->data.Bd.offs)
- a2offs(n->data.Bd.offs, &su);
+ assert(n->data.Bd);
+ if (n->data.Bd->offs)
+ a2offs(n->data.Bd->offs, &su);
- comp = n->data.Bd.comp;
+ comp = n->data.Bd->comp;
/* FIXME: -centered, etc. formatting. */
/* FIXME: does not respect -offset ??? */
return(1);
}
- if (DISP_unfilled != n->data.Bd.type &&
- DISP_literal != n->data.Bd.type)
+ if (DISP_unfilled != n->data.Bd->type &&
+ DISP_literal != n->data.Bd->type)
return(1);
PAIR_CLASS_INIT(&tag[0], "lit");
static int
mdoc_bf_pre(MDOC_ARGS)
{
- int i;
struct htmlpair tag[2];
struct roffsu su;
if (MDOC_HEAD == n->type)
return(0);
- else if (MDOC_BLOCK != n->type)
+ else if (MDOC_BODY != n->type)
return(1);
- PAIR_CLASS_INIT(&tag[0], "lit");
-
- if (n->head->child) {
- if ( ! strcmp("Em", n->head->child->string))
- PAIR_CLASS_INIT(&tag[0], "emph");
- else if ( ! strcmp("Sy", n->head->child->string))
- PAIR_CLASS_INIT(&tag[0], "symb");
- else if ( ! strcmp("Li", n->head->child->string))
- PAIR_CLASS_INIT(&tag[0], "lit");
- } else {
- for (i = 0; n->args && i < (int)n->args->argc; i++)
- switch (n->args->argv[i].arg) {
- case (MDOC_Symbolic):
- PAIR_CLASS_INIT(&tag[0], "symb");
- break;
- case (MDOC_Literal):
- PAIR_CLASS_INIT(&tag[0], "lit");
- break;
- case (MDOC_Emphasis):
- PAIR_CLASS_INIT(&tag[0], "emph");
- break;
- default:
- break;
- }
- }
+ assert(n->data.Bf);
- /* FIXME: div's have spaces stripped--we want them. */
+ if (FONT_Em == n->data.Bf->font)
+ PAIR_CLASS_INIT(&tag[0], "emph");
+ else if (FONT_Sy == n->data.Bf->font)
+ PAIR_CLASS_INIT(&tag[0], "symb");
+ else if (FONT_Li == n->data.Bf->font)
+ PAIR_CLASS_INIT(&tag[0], "lit");
+ else
+ PAIR_CLASS_INIT(&tag[0], "none");
+ /*
+ * We want this to be inline-formatted, but needs to be div to
+ * accept block children.
+ */
bufcat_style(h, "display", "inline");
SCALE_HS_INIT(&su, 1);
- bufcat_su(h, "margin-right", &su);
+ /* Needs a left-margin for spacing. */
+ bufcat_su(h, "margin-left", &su);
PAIR_STYLE_INIT(&tag[1], h);
print_otag(h, TAG_DIV, 2, tag);
return(1);
h->flags |= HTML_NOSPACE;
print_text(h, n->next ? "," : ".");
}
+
+
+/* ARGSUSED */
+static int
+mdoc_bk_pre(MDOC_ARGS)
+{
+
+ switch (n->type) {
+ case (MDOC_BLOCK):
+ break;
+ case (MDOC_HEAD):
+ return(0);
+ case (MDOC_BODY):
+ h->flags |= HTML_PREKEEP;
+ break;
+ default:
+ abort();
+ /* NOTREACHED */
+ }
+
+ return(1);
+}
+
+
+/* ARGSUSED */
+static void
+mdoc_bk_post(MDOC_ARGS)
+{
+
+ if (MDOC_BODY == n->type)
+ h->flags &= ~(HTML_KEEP | HTML_PREKEEP);
+}
-/* $Id: mdoc_macro.c,v 1.53 2010/07/01 22:31:52 schwarze Exp $ */
+/* $Id: mdoc_macro.c,v 1.54 2010/07/13 01:09:13 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
+ * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2010 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
REWIND_THIS,
REWIND_MORE,
REWIND_LATER,
- REWIND_ERROR,
+ REWIND_ERROR
};
static int blk_full(MACRO_PROT_ARGS);
* In particular, always skip block end markers,
* and let all blocks rewind Nm children.
*/
- if (p->end || MDOC_Nm == p->tok ||
+ if (ENDBODY_NOT != p->end || MDOC_Nm == p->tok ||
(MDOC_BLOCK == p->type &&
! (MDOC_EXPLICIT & mdoc_macros[tok].flags)))
return(REWIND_MORE);
! mdoc_body_alloc(m, n->line, n->pos, n->tok))
return(0);
}
+
return(1);
}
/* Remember the start of our own body. */
if (MDOC_BODY == n->type && atok == n->tok) {
- if ( ! n->end)
+ if (ENDBODY_NOT == n->end)
body = n;
continue;
}
return(1);
}
}
+
/* Close out scopes to remain in a consistent state. */
if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
-/* $Id: mdoc_term.c,v 1.94 2010/07/01 15:36:59 schwarze Exp $ */
+/* $Id: mdoc_term.c,v 1.95 2010/07/13 01:09:13 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2010 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
#include "mandoc.h"
#include "out.h"
#include "term.h"
-#include "regs.h"
#include "mdoc.h"
#include "chars.h"
#include "main.h"
static size_t a2height(const struct termp *, const char *);
static size_t a2offs(const struct termp *, const char *);
-static int arg_hasattr(int, const struct mdoc_node *);
-static int arg_getattr(int, const struct mdoc_node *);
static void print_bvspace(struct termp *,
const struct mdoc_node *,
const struct mdoc_node *);
if (MDOC_TEXT == n->type)
term_word(p, n->string);
- else if (termacts[n->tok].pre && !n->end)
+ else if (termacts[n->tok].pre && ENDBODY_NOT == n->end)
chld = (*termacts[n->tok].pre)(p, &npair, m, n);
+ /*
+ * Keeps only work until the end of a line. If a keep was
+ * invoked in a prior line, revert it to PREKEEP.
+ */
+
+ if (TERMP_KEEP & p->flags) {
+ if (n->prev && n->prev->line != n->line) {
+ p->flags &= ~TERMP_KEEP;
+ p->flags |= TERMP_PREKEEP;
+ } else if (NULL == n->prev) {
+ if (n->parent && n->parent->line != n->line) {
+ p->flags &= ~TERMP_KEEP;
+ p->flags |= TERMP_PREKEEP;
+ }
+ }
+ }
+
if (chld && n->child)
print_mdoc_nodelist(p, &npair, m, n->child);
term_fontpopq(p, font);
- if (MDOC_TEXT != n->type &&
- termacts[n->tok].post &&
- ! (MDOC_ENDED & n->flags)) {
- (*termacts[n->tok].post)(p, &npair, m, n);
+ if (MDOC_TEXT != n->type && termacts[n->tok].post &&
+ ! (MDOC_ENDED & n->flags)) {
+ (void)(*termacts[n->tok].post)(p, &npair, m, n);
/*
* Explicit end tokens not only call the post
* handler, but also tell the respective block
* that it must not call the post handler again.
*/
- if (n->end)
+ if (ENDBODY_NOT != n->end)
n->pending->flags |= MDOC_ENDED;
/*
}
-/*
- * Return 1 if an argument has a particular argument value or 0 if it
- * does not. See arg_getattr().
- */
-static int
-arg_hasattr(int arg, const struct mdoc_node *n)
-{
-
- return(-1 != arg_getattr(arg, n));
-}
-
-
-/*
- * Get the index of an argument in a node's argument list or -1 if it
- * does not exist.
- */
-static int
-arg_getattr(int v, const struct mdoc_node *n)
-{
- int i;
-
- if (NULL == n->args)
- return(0);
-
- for (i = 0; i < (int)n->args->argc; i++)
- if (n->args->argv[i].arg == v)
- return(i);
-
- return(-1);
-}
-
-
/*
* Determine how much space to print out before block elements of `It'
* (and thus `Bl') and `Bd'. And then go ahead and print that space,
term_newln(p);
- if (MDOC_Bd == bl->tok && bl->data.Bd.comp)
+ if (MDOC_Bd == bl->tok && bl->data.Bd->comp)
return;
- if (MDOC_Bl == bl->tok && bl->data.Bl.comp)
+ if (MDOC_Bl == bl->tok && bl->data.Bl->comp)
return;
/* Do not vspace directly after Ss/Sh. */
/* A `-column' does not assert vspace within the list. */
- if (MDOC_Bl == bl->tok && LIST_column == bl->data.Bl.type)
+ if (MDOC_Bl == bl->tok && LIST_column == bl->data.Bl->type)
if (n->prev && MDOC_It == n->prev->tok)
return;
/* A `-diag' without body does not vspace. */
- if (MDOC_Bl == bl->tok && LIST_diag == bl->data.Bl.type)
+ if (MDOC_Bl == bl->tok && LIST_diag == bl->data.Bl->type)
if (n->prev && MDOC_It == n->prev->tok) {
assert(n->prev->body);
if (NULL == n->prev->body->child)
{
const struct mdoc_node *bl, *nn;
char buf[7];
- int i, col;
+ int i;
size_t width, offset, ncols, dcol;
enum mdoc_list type;
}
bl = n->parent->parent->parent;
- type = bl->data.Bl.type;
+ assert(bl->data.Bl);
+ type = bl->data.Bl->type;
/*
* First calculate width and offset. This is pretty easy unless
width = offset = 0;
- if (bl->data.Bl.offs)
- offset = a2offs(p, bl->data.Bl.offs);
+ if (bl->data.Bl->offs)
+ offset = a2offs(p, bl->data.Bl->offs);
switch (type) {
case (LIST_column):
if (MDOC_HEAD == n->type)
break;
- col = arg_getattr(MDOC_Column, bl);
-
/*
* Imitate groff's column handling:
* - For each earlier column, add its width.
* column.
* - For more than 5 columns, add only one column.
*/
- ncols = bl->args->argv[col].sz;
+ ncols = bl->data.Bl->ncols;
+
/* LINTED */
dcol = ncols < 5 ? term_len(p, 4) :
ncols == 5 ? term_len(p, 3) : term_len(p, 1);
nn->prev && i < (int)ncols;
nn = nn->prev, i++)
offset += dcol + a2width
- (p, bl->args->argv[col].value[i]);
+ (p, bl->data.Bl->cols[i]);
/*
* When exceeding the declared number of columns, leave
* Use the declared column widths, extended as explained
* in the preceding paragraph.
*/
- width = a2width(p, bl->args->argv[col].value[i]) + dcol;
+ width = a2width(p, bl->data.Bl->cols[i]) + dcol;
break;
default:
- if (NULL == bl->data.Bl.width)
+ if (NULL == bl->data.Bl->width)
break;
/*
* number for buffering single arguments. See the above
* handling for column for how this changes.
*/
- assert(bl->data.Bl.width);
- width = a2width(p, bl->data.Bl.width) + term_len(p, 2);
+ assert(bl->data.Bl->width);
+ width = a2width(p, bl->data.Bl->width) + term_len(p, 2);
break;
}
if (MDOC_BLOCK == n->type)
return;
- type = n->parent->parent->parent->data.Bl.type;
+ type = n->parent->parent->parent->data.Bl->type;
switch (type) {
case (LIST_item):
return;
}
- if (arg_hasattr(MDOC_Split, n)) {
+ if (AUTH_split == n->data.An.auth) {
p->flags &= ~TERMP_NOSPLIT;
p->flags |= TERMP_SPLIT;
- } else {
+ } else if (AUTH_nosplit == n->data.An.auth) {
p->flags &= ~TERMP_SPLIT;
p->flags |= TERMP_NOSPLIT;
}
} else if (MDOC_HEAD == n->type)
return(0);
- if (n->data.Bd.offs)
- p->offset += a2offs(p, n->data.Bd.offs);
+ assert(n->data.Bd);
+ if (n->data.Bd->offs)
+ p->offset += a2offs(p, n->data.Bd->offs);
/*
* If -ragged or -filled are specified, the block does nothing
* lines are allowed.
*/
- if (DISP_literal != n->data.Bd.type &&
- DISP_unfilled != n->data.Bd.type)
+ if (DISP_literal != n->data.Bd->type &&
+ DISP_unfilled != n->data.Bd->type)
return(1);
tabwidth = p->tabwidth;
rm = p->rmargin;
rmax = p->maxrmargin;
- if (DISP_literal == n->data.Bd.type ||
- DISP_unfilled == n->data.Bd.type)
+ assert(n->data.Bd);
+ if (DISP_literal == n->data.Bd->type ||
+ DISP_unfilled == n->data.Bd->type)
p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
p->flags |= TERMP_NOSPACE;
return(1);
}
+ if (NULL == n->child)
+ return(0);
+
/* XXX: we drop non-initial arguments as per groff. */
- assert(n->child);
assert(n->child->string);
term_fontpush(p, TERMFONT_BOLD);
term_word(p, n->child->string);
static int
termp_bf_pre(DECL_ARGS)
{
- const struct mdoc_node *nn;
if (MDOC_HEAD == n->type)
return(0);
else if (MDOC_BLOCK != n->type)
return(1);
- if (NULL == (nn = n->head->child)) {
- if (arg_hasattr(MDOC_Emphasis, n))
- term_fontpush(p, TERMFONT_UNDER);
- else if (arg_hasattr(MDOC_Symbolic, n))
- term_fontpush(p, TERMFONT_BOLD);
- else
- term_fontpush(p, TERMFONT_NONE);
-
- return(1);
- }
+ assert(n->data.Bf);
- assert(MDOC_TEXT == nn->type);
- if (0 == strcmp("Em", nn->string))
+ if (FONT_Em == n->data.Bf->font)
term_fontpush(p, TERMFONT_UNDER);
- else if (0 == strcmp("Sy", nn->string))
+ else if (FONT_Sy == n->data.Bf->font)
term_fontpush(p, TERMFONT_BOLD);
- else
+ else
term_fontpush(p, TERMFONT_NONE);
return(1);
switch (n->type) {
case (MDOC_BLOCK):
- return(1);
+ break;
case (MDOC_HEAD):
return(0);
case (MDOC_BODY):
p->flags |= TERMP_PREKEEP;
- return(1);
+ break;
default:
abort();
+ /* NOTREACHED */
}
+
+ return(1);
}
-/* $Id: mdoc_validate.c,v 1.64 2010/07/02 17:41:05 schwarze Exp $ */
+/* $Id: mdoc_validate.c,v 1.65 2010/07/13 01:09:13 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
{ NULL, posts_notext }, /* Pp */
{ pres_d1, posts_wline }, /* D1 */
{ pres_d1, posts_wline }, /* Dl */
- { pres_bd, posts_bd_bk }, /* Bd */
+ { pres_bd, posts_bd_bk }, /* Bd */
{ NULL, NULL }, /* Ed */
{ pres_bl, posts_bl }, /* Bl */
{ NULL, NULL }, /* El */
{
int c;
+ /*
+ * FIXME: we absolutely cannot let \b get through or it will
+ * destroy some assumptions in terms of format.
+ */
+
for ( ; *p; p++, pos++) {
if ('\t' == *p) {
if ( ! (MDOC_LITERAL & mdoc->flags))
static int
pre_bl(PRE_ARGS)
{
- int i, comp, dup;
- const char *offs, *width;
- enum mdoc_list lt;
+ int i, comp, dup;
+ const char *offs, *width;
+ enum mdoc_list lt;
+ struct mdoc_node *np;
if (MDOC_BLOCK != n->type) {
- assert(n->parent);
- assert(MDOC_BLOCK == n->parent->type);
- assert(MDOC_Bl == n->parent->tok);
- assert(LIST__NONE != n->parent->data.Bl.type);
- memcpy(&n->data.Bl, &n->parent->data.Bl,
- sizeof(struct mdoc_bl));
+ if (ENDBODY_NOT != n->end) {
+ assert(n->pending);
+ np = n->pending->parent;
+ } else
+ np = n->parent;
+
+ assert(np);
+ assert(MDOC_BLOCK == np->type);
+ assert(MDOC_Bl == np->tok);
+ assert(np->data.Bl);
+ n->data.Bl = np->data.Bl;
return(1);
}
* ones. If we find no list type, we default to LIST_item.
*/
- assert(LIST__NONE == n->data.Bl.type);
+ assert(NULL == n->data.Bl);
+ n->data.Bl = mandoc_calloc(1, sizeof(struct mdoc_bl));
/* LINTED */
for (i = 0; n->args && i < (int)n->args->argc; i++) {
break;
/* Set list arguments. */
case (MDOC_Compact):
- dup = n->data.Bl.comp;
+ dup = n->data.Bl->comp;
comp = 1;
break;
case (MDOC_Width):
- dup = (NULL != n->data.Bl.width);
+ dup = (NULL != n->data.Bl->width);
width = n->args->argv[i].value[0];
break;
case (MDOC_Offset):
/* NB: this can be empty! */
if (n->args->argv[i].sz) {
offs = n->args->argv[i].value[0];
- dup = (NULL != n->data.Bl.offs);
+ dup = (NULL != n->data.Bl->offs);
break;
}
if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV))
return(0);
if (comp && ! dup)
- n->data.Bl.comp = comp;
+ n->data.Bl->comp = comp;
if (offs && ! dup)
- n->data.Bl.offs = offs;
+ n->data.Bl->offs = offs;
if (width && ! dup)
- n->data.Bl.width = width;
+ n->data.Bl->width = width;
/* Check: multiple list types. */
- if (LIST__NONE != lt && n->data.Bl.type != LIST__NONE)
+ if (LIST__NONE != lt && n->data.Bl->type != LIST__NONE)
if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_LISTREP))
return(0);
/* Assign list type. */
- if (LIST__NONE != lt && n->data.Bl.type == LIST__NONE)
- n->data.Bl.type = lt;
+ if (LIST__NONE != lt && n->data.Bl->type == LIST__NONE) {
+ n->data.Bl->type = lt;
+ /* Set column information, too. */
+ if (LIST_column == lt) {
+ n->data.Bl->ncols =
+ n->args->argv[i].sz;
+ n->data.Bl->cols = (const char **)
+ n->args->argv[i].value;
+ }
+ }
/* The list type should come first. */
- if (n->data.Bl.type == LIST__NONE)
- if (n->data.Bl.width ||
- n->data.Bl.offs ||
- n->data.Bl.comp)
+ if (n->data.Bl->type == LIST__NONE)
+ if (n->data.Bl->width ||
+ n->data.Bl->offs ||
+ n->data.Bl->comp)
if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST))
return(0);
/* Allow lists to default to LIST_item. */
- if (LIST__NONE == n->data.Bl.type) {
+ if (LIST__NONE == n->data.Bl->type) {
if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE))
return(0);
- n->data.Bl.type = LIST_item;
+ n->data.Bl->type = LIST_item;
}
/*
* and must also be warned.
*/
- switch (n->data.Bl.type) {
+ switch (n->data.Bl->type) {
case (LIST_tag):
- if (n->data.Bl.width)
+ if (n->data.Bl->width)
break;
if (mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG))
break;
case (LIST_inset):
/* FALLTHROUGH */
case (LIST_item):
- if (NULL == n->data.Bl.width)
+ if (NULL == n->data.Bl->width)
break;
if (mdoc_nmsg(mdoc, n, MANDOCERR_WIDTHARG))
break;
static int
pre_bd(PRE_ARGS)
{
- int i, dup, comp;
- enum mdoc_disp dt;
- const char *offs;
+ int i, dup, comp;
+ enum mdoc_disp dt;
+ const char *offs;
+ struct mdoc_node *np;
if (MDOC_BLOCK != n->type) {
- assert(n->parent);
- assert(MDOC_BLOCK == n->parent->type);
- assert(MDOC_Bd == n->parent->tok);
- assert(DISP__NONE != n->parent->data.Bd.type);
- memcpy(&n->data.Bd, &n->parent->data.Bd,
- sizeof(struct mdoc_bd));
+ if (ENDBODY_NOT != n->end) {
+ assert(n->pending);
+ np = n->pending->parent;
+ } else
+ np = n->parent;
+
+ assert(np);
+ assert(MDOC_BLOCK == np->type);
+ assert(MDOC_Bd == np->tok);
+ assert(np->data.Bd);
+ n->data.Bd = np->data.Bd;
return(1);
}
- assert(DISP__NONE == n->data.Bd.type);
+ assert(NULL == n->data.Bd);
+ n->data.Bd = mandoc_calloc(1, sizeof(struct mdoc_bd));
/* LINTED */
for (i = 0; n->args && i < (int)n->args->argc; i++) {
/* NB: this can be empty! */
if (n->args->argv[i].sz) {
offs = n->args->argv[i].value[0];
- dup = (NULL != n->data.Bd.offs);
+ dup = (NULL != n->data.Bd->offs);
break;
}
if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV))
break;
case (MDOC_Compact):
comp = 1;
- dup = n->data.Bd.comp;
+ dup = n->data.Bd->comp;
break;
default:
abort();
/* Make our auxiliary assignments. */
if (offs && ! dup)
- n->data.Bd.offs = offs;
+ n->data.Bd->offs = offs;
if (comp && ! dup)
- n->data.Bd.comp = comp;
+ n->data.Bd->comp = comp;
/* Check whether a type has already been assigned. */
- if (DISP__NONE != dt && n->data.Bd.type != DISP__NONE)
+ if (DISP__NONE != dt && n->data.Bd->type != DISP__NONE)
if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_DISPREP))
return(0);
/* Make our type assignment. */
- if (DISP__NONE != dt && n->data.Bd.type == DISP__NONE)
- n->data.Bd.type = dt;
+ if (DISP__NONE != dt && n->data.Bd->type == DISP__NONE)
+ n->data.Bd->type = dt;
}
- if (DISP__NONE == n->data.Bd.type) {
+ if (DISP__NONE == n->data.Bd->type) {
if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_DISPTYPE))
return(0);
- n->data.Bd.type = DISP_ragged;
+ n->data.Bd->type = DISP_ragged;
}
return(1);
pre_an(PRE_ARGS)
{
- if (NULL == n->args || 1 == n->args->argc)
+ if (NULL == n->args)
return(1);
- mdoc_vmsg(mdoc, MANDOCERR_SYNTARGCOUNT,
- n->line, n->pos,
- "line arguments == 1 (have %d)",
- n->args->argc);
- return(0);
+ if (n->args->argc > 1)
+ if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_ARGCOUNT))
+ return(0);
+
+ if (MDOC_Split == n->args->argv[0].arg)
+ n->data.An.auth = AUTH_split;
+ else if (MDOC_Nosplit == n->args->argv[0].arg)
+ n->data.An.auth = AUTH_nosplit;
+ else
+ abort();
+
+ return(1);
}
static int
post_bf(POST_ARGS)
{
- char *p;
- struct mdoc_node *head;
+ struct mdoc_node *np;
+ int arg;
- if (MDOC_BLOCK != mdoc->last->type)
+ /*
+ * Unlike other data pointers, these are "housed" by the HEAD
+ * element, which contains the goods.
+ */
+
+ if (MDOC_HEAD != mdoc->last->type) {
+ if (ENDBODY_NOT != mdoc->last->end) {
+ assert(mdoc->last->pending);
+ np = mdoc->last->pending->parent->head;
+ } else if (MDOC_BLOCK != mdoc->last->type) {
+ np = mdoc->last->parent->head;
+ } else
+ np = mdoc->last->head;
+
+ assert(np);
+ assert(MDOC_HEAD == np->type);
+ assert(MDOC_Bf == np->tok);
+ assert(np->data.Bf);
+ mdoc->last->data.Bf = np->data.Bf;
return(1);
+ }
- head = mdoc->last->head;
+ np = mdoc->last;
+ assert(MDOC_BLOCK == np->parent->type);
+ assert(MDOC_Bf == np->parent->tok);
+ np->data.Bf = mandoc_calloc(1, sizeof(struct mdoc_bf));
- if (mdoc->last->args && head->child) {
- /* FIXME: this should provide a default. */
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SYNTARGVCOUNT);
- return(0);
- } else if (mdoc->last->args)
- return(1);
+ /*
+ * Cannot have both argument and parameter.
+ * If neither is specified, let it through with a warning.
+ */
- if (NULL == head->child || MDOC_TEXT != head->child->type) {
- /* FIXME: this should provide a default. */
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SYNTARGVCOUNT);
+ if (np->parent->args && np->child) {
+ mdoc_nmsg(mdoc, np, MANDOCERR_SYNTARGVCOUNT);
return(0);
+ } else if (NULL == np->parent->args && NULL == np->child)
+ return(mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE));
+
+ /* Extract argument into data. */
+
+ if (np->parent->args) {
+ arg = np->parent->args->argv[0].arg;
+ if (MDOC_Emphasis == arg)
+ np->data.Bf->font = FONT_Em;
+ else if (MDOC_Literal == arg)
+ np->data.Bf->font = FONT_Li;
+ else if (MDOC_Symbolic == arg)
+ np->data.Bf->font = FONT_Sy;
+ else
+ abort();
+ return(1);
}
- p = head->child->string;
+ /* Extract parameter into data. */
- if (0 == strcmp(p, "Em"))
- return(1);
- else if (0 == strcmp(p, "Li"))
- return(1);
- else if (0 == strcmp(p, "Sy"))
- return(1);
+ if (0 == strcmp(np->child->string, "Em"))
+ np->data.Bf->font = FONT_Em;
+ else if (0 == strcmp(np->child->string, "Li"))
+ np->data.Bf->font = FONT_Li;
+ else if (0 == strcmp(np->child->string, "Sy"))
+ np->data.Bf->font = FONT_Sy;
+ else if ( ! mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE))
+ return(0);
- mdoc_nmsg(mdoc, head, MANDOCERR_FONTTYPE);
- return(0);
+ return(1);
}
static int
post_an(POST_ARGS)
{
+ struct mdoc_node *np;
- if (mdoc->last->args) {
- if (NULL == mdoc->last->child)
- return(1);
- return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGCOUNT));
- }
-
- if (mdoc->last->child)
+ np = mdoc->last;
+ if (AUTH__NONE != np->data.An.auth && np->child)
+ return(mdoc_nmsg(mdoc, np, MANDOCERR_ARGCOUNT));
+ if (AUTH__NONE != np->data.An.auth || np->child)
return(1);
- return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS));
+ return(mdoc_nmsg(mdoc, np, MANDOCERR_NOARGS));
}
return(1);
n = mdoc->last->parent->parent;
- lt = n->data.Bl.type;
+ assert(n->data.Bl);
+ lt = n->data.Bl->type;
if (LIST__NONE == lt) {
mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_LISTTYPE);
return(0);
break;
case (LIST_column):
- cols = -1;
- for (i = 0; i < (int)n->args->argc; i++)
- if (MDOC_Column == n->args->argv[i].arg) {
- cols = (int)n->args->argv[i].sz;
- break;
- }
+ cols = (int)n->data.Bl->ncols;
- assert(-1 != cols);
assert(NULL == mdoc->last->head->child);
if (NULL == mdoc->last->body->child)
assert(mdoc->last->parent);
n = mdoc->last->parent;
- if (LIST_column == n->data.Bl.type) {
- for (i = 0; i < (int)n->args->argc; i++)
- if (MDOC_Column == n->args->argv[i].arg)
- break;
- assert(i < (int)n->args->argc);
-
- if (n->args->argv[i].sz && mdoc->last->nchild) {
+ if (LIST_column == n->data.Bl->type) {
+ if (n->data.Bl->ncols && mdoc->last->nchild) {
mdoc_nmsg(mdoc, n, MANDOCERR_COLUMNS);
return(0);
}
+++ /dev/null
-/* $Id: regs.h,v 1.2 2010/07/03 15:59:05 schwarze Exp $ */
-/*
- * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
- *
- * 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.
- */
-#ifndef REGS_H
-#define REGS_H
-
-__BEGIN_DECLS
-
-enum regs {
- REG_nS = 0, /* nS */
- REG__MAX
-};
-
-struct reg {
- int set; /* whether set or not */
- union {
- unsigned u; /* unsigned integer */
- } v;
-};
-
-/*
- * Registers are non-scoped state. These can be manipulated directly in
- * libroff or indirectly in libman or libmdoc by macros. These should
- * be implemented sparingly (we are NOT roffdoc!) and documented fully
- * in roff.7.
- */
-struct regset {
- struct reg regs[REG__MAX];
-};
-
-char *roff_setstr(const char *, const char *);
-char *roff_getstr(const char *);
-char *roff_getstrn(const char *, size_t);
-void roff_freestr(void);
-
-__END_DECLS
-
-#endif /*!REGS_H*/
-.\" $Id: roff.3,v 1.3 2010/07/03 15:59:05 schwarze Exp $
+.\" $Id: roff.3,v 1.4 2010/07/13 01:09:13 schwarze Exp $
.\"
.\" Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
.\"
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: July 3 2010 $
+.Dd $Mdocdate: July 13 2010 $
.Dt ROFF 3
.Os
.Sh NAME
.Nd roff macro compiler library
.Sh SYNOPSIS
.In mandoc.h
-.In regs.h
.In roff.h
.Ft "struct roff *"
.Fo roff_alloc
.Fc
.Ft void
.Fn roff_reset "struct roff *roff"
-.In regs.h
-.Ft "char *"
-.Fn roff_setstr "const char *name" "const char *string"
-.Ft "char *"
-.Fn roff_getstr "const char *name"
-.Ft "char *"
-.Fn roff_getstrn "const char *name" "size_t len"
-.Ft void
-.Fn roff_freestr void
.Sh DESCRIPTION
The
.Nm
Signals that the parse is complete.
Returns 0 on failure, 1 on success.
.El
-.Sh USER-DEFINED STRINGS
-Strings defined by the
-.Xr roff 7
-.Sx \&ds
-instruction are saved using the
-.Fn roff_setstr
-function and retrieved using the
-.Fn roff_getstr
-and
-.Fn roff_getstrn
-functions.
-.Pp
-These functions take the name of the string to be accessed
-as their first argument.
-While
-.Fn roff_getstr
-requires the name to be null-terminated,
-.Fn roff_getstrn
-accepts non-terminated strings, but requires the length of the name
-to be specified.
-.Pp
-The second argument to
-.Fn roff_setstr
-is the new value of the string.
-It will be copied to internal storage, so both pointers to constant
-strings and pointers to volatile storage are acceptable.
-.Pp
-All of these functions return a pointer to the new value of the string
-in internal storage, which should be considered read-only, so use
-.Xr strdup 3
-on it as appropriate.
-The read functions return NULL when a string of the specified name
-is not available or empty, and
-.Fn roff_setstr
-returns NULL when memory allocation fails.
-In the latter case, the string will remain unset.
-.Pp
-The function
-.Fn roff_freestr
-clears all user-defined strings.
-It always succeeds.
-Both
-.Fn roff_reset
-and
-.Fn roff_free
-call it.
.Sh EXAMPLES
See
.Pa main.c
-.\" $Id: roff.7,v 1.6 2010/06/27 21:54:42 schwarze Exp $
+.\" $Id: roff.7,v 1.7 2010/07/13 01:09:13 schwarze Exp $
.\"
.\" Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
+.\" Copyright (c) 2010 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
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: June 27 2010 $
+.Dd $Mdocdate: July 13 2010 $
.Dt ROFF 7
.Os
.Sh NAME
except that a leading argument must be specified.
It is ignored, as are its children.
.Ss \&ds
-Define a string.
-This macro is intended to have two arguments,
-the name of the string to define and its content.
-Currently, it is ignored including its arguments,
-and the number of arguments is not checked.
+Define a reserved word.
+Its syntax is as follows:
+.Pp
+.D1 Pf \. Sx \&ds No Cm key val
+.Pp
+The
+.Cm key
+and
+.Cm val
+strings are space-separated.
+The
+.Cm key
+values may be invoked in subsequent text by using \e*(NN for two-letter
+pairs, \e*N for one-letter, and \e*[NNN] for arbitrary-length values.
.Ss \&de1
The syntax of this macro is the same as that of
.Sx \&ig ,
-/* $Id: roff.c,v 1.7 2010/07/03 15:59:05 schwarze Exp $ */
+/* $Id: roff.c,v 1.8 2010/07/13 01:09:13 schwarze Exp $ */
/*
* Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2010 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
#include <stdio.h>
#include "mandoc.h"
-#include "regs.h"
#include "roff.h"
+#include "libmandoc.h"
#define RSTACK_MAX 128
ROFFRULE_DENY
};
+
+struct roffstr {
+ char *name; /* key of symbol */
+ char *string; /* current value */
+ struct roffstr *next; /* next in list */
+};
+
struct roff {
struct roffnode *last; /* leaf of stack */
mandocmsg msg; /* err/warn/fatal messages */
enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */
int rstackpos; /* position in rstack */
struct regset *regs; /* read/writable registers */
+ struct roffstr *first_string;
};
struct roffnode {
struct roffmac *next;
};
-struct roffstr {
- char *name;
- char *string;
- struct roffstr *next;
-} *first_string;
-
static enum rofferr roff_block(ROFF_ARGS);
static enum rofferr roff_block_text(ROFF_ARGS);
static enum rofferr roff_block_sub(ROFF_ARGS);
static enum rofferr roff_cond_text(ROFF_ARGS);
static enum rofferr roff_cond_sub(ROFF_ARGS);
static enum rofferr roff_ds(ROFF_ARGS);
+static enum roffrule roff_evalcond(const char *, int *);
+static void roff_freestr(struct roff *);
+static const char *roff_getstrn(const struct roff *,
+ const char *, size_t);
static enum rofferr roff_line(ROFF_ARGS);
static enum rofferr roff_nr(ROFF_ARGS);
-static enum roffrule roff_evalcond(const char *, int *);
+static int roff_res(struct roff *, int,
+ char **, size_t *, int, int *);
+static void roff_setstr(struct roff *,
+ const char *, const char *);
/* See roff_hash_find() */
while (r->last)
roffnode_pop(r);
- roff_freestr();
+ roff_freestr(r);
}
}
+/*
+ * Pre-filter each and every line for reserved words (one beginning with
+ * `\*', e.g., `\*(ab'). These must be handled before the actual line
+ * is processed.
+ */
+static int
+roff_res(struct roff *r, int ln, char **bufp,
+ size_t *szp, int pos, int *offs)
+{
+ const char *cp, *cpp, *st, *res;
+ int i, maxl;
+ size_t nsz;
+ char *n;
+
+ for (cp = &(*bufp)[pos]; (cpp = strstr(cp, "\\*")); cp++) {
+ cp = cpp + 2;
+ switch (*cp) {
+ case ('('):
+ cp++;
+ maxl = 2;
+ break;
+ case ('['):
+ cp++;
+ maxl = 0;
+ break;
+ default:
+ maxl = 1;
+ break;
+ }
+
+ st = cp;
+
+ for (i = 0; 0 == maxl || i < maxl; i++, cp++) {
+ if ('\0' == *cp)
+ return(1); /* Error. */
+ if (0 == maxl && ']' == *cp)
+ break;
+ }
+
+ res = roff_getstrn(r, st, (size_t)i);
+
+ if (NULL == res) {
+ cp -= maxl ? 1 : 0;
+ continue;
+ }
+
+ nsz = *szp + strlen(res) + 1;
+ n = mandoc_malloc(nsz);
+
+ *n = '\0';
+
+ strlcat(n, *bufp, (size_t)(cpp - *bufp + 1));
+ strlcat(n, res, nsz);
+ strlcat(n, cp + (maxl ? 0 : 1), nsz);
+
+ free(*bufp);
+
+ *bufp = n;
+ *szp = nsz;
+ return(0);
+ }
+
+ return(1);
+}
+
+
enum rofferr
roff_parseln(struct roff *r, int ln, char **bufp,
size_t *szp, int pos, int *offs)
enum rofft t;
int ppos;
+ /*
+ * Run the reserved-word filter only if we have some reserved
+ * words to fill in.
+ */
+
+ if (r->first_string && ! roff_res(r, ln, bufp, szp, pos, offs))
+ return(ROFF_RERUN);
+
/*
* First, if a scope is open and we're not a macro, pass the
* text through the macro's filter. If a scope isn't open and
t = r->last->tok;
assert(roffs[t].text);
return((*roffs[t].text)
- (r, t, bufp, szp, ln, pos, pos, offs));
+ (r, t, bufp, szp,
+ ln, pos, pos, offs));
} else if ( ! ROFF_CTL((*bufp)[pos]))
return(ROFF_CONT);
t = r->last->tok;
assert(roffs[t].sub);
return((*roffs[t].sub)
- (r, t, bufp, szp, ln, pos, pos, offs));
+ (r, t, bufp, szp,
+ ln, pos, pos, offs));
}
/*
assert(roffs[t].proc);
return((*roffs[t].proc)
- (r, t, bufp, szp, ln, ppos, pos, offs));
+ (r, t, bufp, szp,
+ ln, ppos, pos, offs));
}
*end = '\0';
}
- roff_setstr(name, string);
+ roff_setstr(r, name, string);
return(ROFF_IGN);
}
}
-char *
-roff_setstr(const char *name, const char *string)
+static void
+roff_setstr(struct roff *r, const char *name, const char *string)
{
struct roffstr *n;
char *namecopy;
- n = first_string;
+ n = r->first_string;
while (n && strcmp(name, n->name))
n = n->next;
- if (n) {
- free(n->string);
- } else {
- if (NULL == (namecopy = strdup(name)))
- return(NULL);
- if (NULL == (n = malloc(sizeof(struct roffstr)))) {
- free(n);
- return(NULL);
- }
- n->name = namecopy;
- n->next = first_string;
- first_string = n;
- }
- if (string)
- n->string = strdup(string);
- else
- n->string = NULL;
- return(n->string);
-}
-char *
-roff_getstr(const char *name)
-{
- struct roffstr *n;
+ if (NULL == n) {
+ namecopy = mandoc_strdup(name);
+ n = mandoc_malloc(sizeof(struct roffstr));
+ n->name = namecopy;
+ n->next = r->first_string;
+ r->first_string = n;
+ } else
+ free(n->string);
- n = first_string;
- while (n && strcmp(name, n->name))
- n = n->next;
- if (n)
- return(n->string);
- else
- return(NULL);
+ n->string = string ? strdup(string) : NULL;
}
-char *
-roff_getstrn(const char *name, size_t len)
+
+static const char *
+roff_getstrn(const struct roff *r, const char *name, size_t len)
{
- struct roffstr *n;
+ const struct roffstr *n;
- n = first_string;
+ n = r->first_string;
while (n && (strncmp(name, n->name, len) || '\0' != n->name[len]))
n = n->next;
- if (n)
- return(n->string);
- else
- return(NULL);
+
+ return(n ? n->string : NULL);
}
-void
-roff_freestr(void)
+
+static void
+roff_freestr(struct roff *r)
{
struct roffstr *n, *nn;
- for (n = first_string; n; n = nn) {
+ for (n = r->first_string; n; n = nn) {
free(n->name);
free(n->string);
nn = n->next;
free(n);
}
- first_string = NULL;
+
+ r->first_string = NULL;
}
-/* $Id: term.c,v 1.43 2010/07/03 15:59:05 schwarze Exp $ */
+/* $Id: term.c,v 1.44 2010/07/13 01:09:13 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2010 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
#include "mandoc.h"
#include "chars.h"
#include "out.h"
-#include "regs.h"
#include "term.h"
#include "main.h"
size_t sz;
rhs = chars_a2res(p->symtab, word, len, &sz);
- if (NULL == rhs) {
- rhs = roff_getstrn(word, len);
- if (rhs)
- sz = strlen(rhs);
- }
if (rhs)
encode(p, rhs, sz);
}
}
+/* ARGSUSED */
size_t
term_vspan(const struct termp *p, const struct roffsu *su)
{
size_t
term_hspan(const struct termp *p, const struct roffsu *su)
{
- double r;
-
- /* XXX: CM, IN, and PT are approximations. */
-
- switch (su->unit) {
- case (SCALE_CM):
- r = 4 * su->scale;
- break;
- case (SCALE_IN):
- /* XXX: this is an approximation. */
- r = 10 * su->scale;
- break;
- case (SCALE_PC):
- r = (10 * su->scale) / 6;
- break;
- case (SCALE_PT):
- r = (10 * su->scale) / 72;
- break;
- case (SCALE_MM):
- r = su->scale / 1000; /* FIXME: double-check. */
- break;
- case (SCALE_VS):
- r = su->scale * 2 - 1; /* FIXME: double-check. */
- break;
- default:
- r = su->scale;
- break;
- }
+ double v;
- if (r < 0.0)
- r = 0.0;
- return((size_t)/* LINTED */
- r);
+ v = ((*p->hspan)(p, su));
+ if (v < 0.0)
+ v = 0.0;
+ return((size_t) /* LINTED */
+ v);
}
-
-
-/* $Id: term.h,v 1.24 2010/06/29 14:41:28 schwarze Exp $ */
+/* $Id: term.h,v 1.25 2010/07/13 01:09:13 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
typedef void (*term_margin)(struct termp *, const void *);
struct termp_ps {
- int psstate; /* state of ps output */
+ int flags;
#define PS_INLINE (1 << 0) /* we're in a word */
#define PS_MARGINS (1 << 1) /* we're in the margins */
- size_t pscol; /* visible column (points) */
- size_t psrow; /* visible row (points) */
+#define PS_NEWPAGE (1 << 2) /* new page, no words yet */
+ size_t pscol; /* visible column (AFM units) */
+ size_t psrow; /* visible row (AFM units) */
char *psmarg; /* margin buf */
size_t psmargsz; /* margin buf size */
size_t psmargcur; /* cur index in margin buf */
char last; /* character buffer */
enum termfont lastf; /* last set font */
+ size_t scale; /* font scaling factor */
size_t pages; /* number of pages shown */
- size_t lineheight; /* each line's height (points) */
- size_t top; /* body top (points) */
- size_t bottom; /* body bottom (points) */
- size_t height; /* total height (points) */
- size_t width; /* total width (points) */
- size_t left; /* body left (points) */
- size_t header; /* header position (points) */
- size_t footer; /* footer position (points) */
+ size_t lineheight; /* line height (AFM units) */
+ size_t top; /* body top (AFM units) */
+ size_t bottom; /* body bottom (AFM units) */
+ size_t height; /* page height (AFM units */
+ size_t width; /* page width (AFM units) */
+ size_t left; /* body left (AFM units) */
+ size_t header; /* header pos (AFM units) */
+ size_t footer; /* footer pos (AFM units) */
};
struct termp {
void (*endline)(struct termp *);
void (*advance)(struct termp *, size_t);
size_t (*width)(const struct termp *, char);
+ double (*hspan)(const struct termp *,
+ const struct roffsu *);
const void *argf; /* arg for headf/footf */
union {
struct termp_ps ps;
-/* $Id: term_ascii.c,v 1.2 2010/06/26 19:08:00 schwarze Exp $ */
+/* $Id: term_ascii.c,v 1.3 2010/07/13 01:09:13 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
+ * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
#include "term.h"
#include "main.h"
-static void ascii_endline(struct termp *);
-static void ascii_letter(struct termp *, char);
-static void ascii_begin(struct termp *);
+static double ascii_hspan(const struct termp *,
+ const struct roffsu *);
+static size_t ascii_width(const struct termp *, char);
static void ascii_advance(struct termp *, size_t);
+static void ascii_begin(struct termp *);
static void ascii_end(struct termp *);
-static size_t ascii_width(const struct termp *, char);
+static void ascii_endline(struct termp *);
+static void ascii_letter(struct termp *, char);
void *
p->tabwidth = 5;
p->defrmargin = 78;
- p->type = TERMTYPE_CHAR;
- p->letter = ascii_letter;
+ p->advance = ascii_advance;
p->begin = ascii_begin;
p->end = ascii_end;
p->endline = ascii_endline;
- p->advance = ascii_advance;
+ p->hspan = ascii_hspan;
+ p->letter = ascii_letter;
+ p->type = TERMTYPE_CHAR;
p->width = ascii_width;
toks[0] = "width";
}
+/* ARGSUSED */
static size_t
ascii_width(const struct termp *p, char c)
{
for (i = 0; i < len; i++)
putchar(' ');
}
+
+
+/* ARGSUSED */
+static double
+ascii_hspan(const struct termp *p, const struct roffsu *su)
+{
+ double r;
+
+ /*
+ * Approximate based on character width. These are generated
+ * entirely by eyeballing the screen, but appear to be correct.
+ */
+
+ switch (su->unit) {
+ case (SCALE_CM):
+ r = 4 * su->scale;
+ break;
+ case (SCALE_IN):
+ r = 10 * su->scale;
+ break;
+ case (SCALE_PC):
+ r = (10 * su->scale) / 6;
+ break;
+ case (SCALE_PT):
+ r = (10 * su->scale) / 72;
+ break;
+ case (SCALE_MM):
+ r = su->scale / 1000;
+ break;
+ case (SCALE_VS):
+ r = su->scale * 2 - 1;
+ break;
+ default:
+ r = su->scale;
+ break;
+ }
+
+ return(r);
+}
+
-/* $Id: term_ps.c,v 1.5 2010/06/29 15:49:52 schwarze Exp $ */
+/* $Id: term_ps.c,v 1.6 2010/07/13 01:09:13 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
#include <stdlib.h>
#include <string.h>
#include <time.h>
+#include <unistd.h>
#include "out.h"
#include "main.h"
#include "term.h"
+/* Convert PostScript point "x" to an AFM unit. */
+#define PNT2AFM(p, x) /* LINTED */ \
+ (size_t)((double)(x) * (1000.0 / (double)(p)->engine.ps.scale))
+
+/* Convert an AFM unit "x" to a PostScript points */
+#define AFM2PNT(p, x) /* LINTED */ \
+ (size_t)((double)(x) / (1000.0 / (double)(p)->engine.ps.scale))
+
struct glyph {
- int wx; /* WX in AFM */
+ size_t wx; /* WX in AFM */
};
struct font {
*/
static const struct font fonts[TERMFONT__MAX] = {
- { "Courier", {
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
+ { "Times-Roman", {
+ { 250 },
+ { 333 },
+ { 408 },
+ { 500 },
+ { 500 },
+ { 833 },
+ { 778 },
+ { 333 },
+ { 333 },
+ { 333 },
+ { 500 },
+ { 564 },
+ { 250 },
+ { 333 },
+ { 250 },
+ { 278 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 278 },
+ { 278 },
+ { 564 },
+ { 564 },
+ { 564 },
+ { 444 },
+ { 921 },
+ { 722 },
+ { 667 },
+ { 667 },
+ { 722 },
+ { 611 },
+ { 556 },
+ { 722 },
+ { 722 },
+ { 333 },
+ { 389 },
+ { 722 },
+ { 611 },
+ { 889 },
+ { 722 },
+ { 722 },
+ { 556 },
+ { 722 },
+ { 667 },
+ { 556 },
+ { 611 },
+ { 722 },
+ { 722 },
+ { 944 },
+ { 722 },
+ { 722 },
+ { 611 },
+ { 333 },
+ { 278 },
+ { 333 },
+ { 469 },
+ { 500 },
+ { 333 },
+ { 444 },
+ { 500 },
+ { 444 },
+ { 500},
+ { 444},
+ { 333},
+ { 500},
+ { 500},
+ { 278},
+ { 278},
+ { 500},
+ { 278},
+ { 778},
+ { 500},
+ { 500},
+ { 500},
+ { 500},
+ { 333},
+ { 389},
+ { 278},
+ { 500},
+ { 500},
+ { 722},
+ { 500},
+ { 500},
+ { 444},
+ { 480},
+ { 200},
+ { 480},
+ { 541},
} },
- { "Courier-Bold", {
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
+ { "Times-Bold", {
+ { 250 },
+ { 333 },
+ { 555 },
+ { 500 },
+ { 500 },
+ { 1000 },
+ { 833 },
+ { 333 },
+ { 333 },
+ { 333 },
+ { 500 },
+ { 570 },
+ { 250 },
+ { 333 },
+ { 250 },
+ { 278 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 333 },
+ { 333 },
+ { 570 },
+ { 570 },
+ { 570 },
+ { 500 },
+ { 930 },
+ { 722 },
+ { 667 },
+ { 722 },
+ { 722 },
+ { 667 },
+ { 611 },
+ { 778 },
+ { 778 },
+ { 389 },
+ { 500 },
+ { 778 },
+ { 667 },
+ { 944 },
+ { 722 },
+ { 778 },
+ { 611 },
+ { 778 },
+ { 722 },
+ { 556 },
+ { 667 },
+ { 722 },
+ { 722 },
+ { 1000 },
+ { 722 },
+ { 722 },
+ { 667 },
+ { 333 },
+ { 278 },
+ { 333 },
+ { 581 },
+ { 500 },
+ { 333 },
+ { 500 },
+ { 556 },
+ { 444 },
+ { 556 },
+ { 444 },
+ { 333 },
+ { 500 },
+ { 556 },
+ { 278 },
+ { 333 },
+ { 556 },
+ { 278 },
+ { 833 },
+ { 556 },
+ { 500 },
+ { 556 },
+ { 556 },
+ { 444 },
+ { 389 },
+ { 333 },
+ { 556 },
+ { 500 },
+ { 722 },
+ { 500 },
+ { 500 },
+ { 444 },
+ { 394 },
+ { 220 },
+ { 394 },
+ { 520 },
} },
- { "Courier-Oblique", {
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
- { 600 },
+ { "Times-Italic", {
+ { 250 },
+ { 333 },
+ { 420 },
+ { 500 },
+ { 500 },
+ { 833 },
+ { 778 },
+ { 333 },
+ { 333 },
+ { 333 },
+ { 500 },
+ { 675 },
+ { 250 },
+ { 333 },
+ { 250 },
+ { 278 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 333 },
+ { 333 },
+ { 675 },
+ { 675 },
+ { 675 },
+ { 500 },
+ { 920 },
+ { 611 },
+ { 611 },
+ { 667 },
+ { 722 },
+ { 611 },
+ { 611 },
+ { 722 },
+ { 722 },
+ { 333 },
+ { 444 },
+ { 667 },
+ { 556 },
+ { 833 },
+ { 667 },
+ { 722 },
+ { 611 },
+ { 722 },
+ { 611 },
+ { 500 },
+ { 556 },
+ { 722 },
+ { 611 },
+ { 833 },
+ { 611 },
+ { 556 },
+ { 556 },
+ { 389 },
+ { 278 },
+ { 389 },
+ { 422 },
+ { 500 },
+ { 333 },
+ { 500 },
+ { 500 },
+ { 444 },
+ { 500 },
+ { 444 },
+ { 278 },
+ { 500 },
+ { 500 },
+ { 278 },
+ { 278 },
+ { 444 },
+ { 278 },
+ { 722 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 389 },
+ { 389 },
+ { 278 },
+ { 500 },
+ { 444 },
+ { 667 },
+ { 444 },
+ { 444 },
+ { 389 },
+ { 400 },
+ { 275 },
+ { 400 },
+ { 541 },
} },
};
} while (/* CONSTCOND */ 0)
-static void ps_letter(struct termp *, char);
+static double ps_hspan(const struct termp *,
+ const struct roffsu *);
+static size_t ps_width(const struct termp *, char);
+static void ps_advance(struct termp *, size_t);
static void ps_begin(struct termp *);
static void ps_end(struct termp *);
-static void ps_advance(struct termp *, size_t);
static void ps_endline(struct termp *);
static void ps_fclose(struct termp *);
-static size_t ps_width(const struct termp *, char);
+static void ps_letter(struct termp *, char);
static void ps_pclose(struct termp *);
static void ps_pletter(struct termp *, int);
static void ps_printf(struct termp *, const char *, ...);
ps_alloc(char *outopts)
{
struct termp *p;
- size_t pagex, pagey, margin;
+ size_t pagex, pagey, marginx, marginy, lineheight;
const char *toks[2];
+ const char *pp;
char *v;
if (NULL == (p = term_alloc(TERMENC_ASCII)))
return(NULL);
- /* Default is USA letter. */
- pagex = 612;
- pagey = 792;
- margin = 72;
-
- p->type = TERMTYPE_PS;
- p->letter = ps_letter;
+ p->advance = ps_advance;
p->begin = ps_begin;
p->end = ps_end;
- p->advance = ps_advance;
p->endline = ps_endline;
+ p->hspan = ps_hspan;
+ p->letter = ps_letter;
+ p->type = TERMTYPE_PS;
p->width = ps_width;
-
+
toks[0] = "paper";
toks[1] = NULL;
+ pp = NULL;
+
while (outopts && *outopts)
switch (getsubopt(&outopts, UNCONST(toks), &v)) {
case (0):
- if (0 == strcasecmp(v, "a4")) {
- pagex = 595;
- pagey = 842;
- } else if (0 == strcasecmp(v, "letter")) {
- pagex = 612;
- pagey = 792;
- }
+ pp = v;
break;
default:
break;
}
- assert(margin * 2 < pagex);
- assert(margin * 2 < pagey);
+ /* Default to US letter (millimetres). */
+
+ pagex = 216;
+ pagey = 279;
+
+ /*
+ * The ISO-269 paper sizes can be calculated automatically, but
+ * it would require bringing in -lm for pow() and I'd rather not
+ * do that. So just do it the easy way for now. Since this
+ * only happens once, I'm not terribly concerned.
+ */
+
+ if (pp && strcasecmp(pp, "letter")) {
+ if (0 == strcasecmp(pp, "a3")) {
+ pagex = 297;
+ pagey = 420;
+ } else if (0 == strcasecmp(pp, "a4")) {
+ pagex = 210;
+ pagey = 297;
+ } else if (0 == strcasecmp(pp, "a5")) {
+ pagex = 148;
+ pagey = 210;
+ } else if (0 == strcasecmp(pp, "legal")) {
+ pagex = 216;
+ pagey = 356;
+ } else if (2 != sscanf(pp, "%zux%zu", &pagex, &pagey))
+ fprintf(stderr, "%s: Unknown paper\n", pp);
+ } else if (NULL == pp)
+ pp = "letter";
+
+ /*
+ * This MUST be defined before any PNT2AFM or AFM2PNT
+ * calculations occur.
+ */
+
+ p->engine.ps.scale = 11;
+
+ /* Remember millimetres -> AFM units. */
+
+ pagex = PNT2AFM(p, ((double)pagex * 2.834));
+ pagey = PNT2AFM(p, ((double)pagey * 2.834));
+
+ /* Margins are 1/9 the page x and y. */
+
+ marginx = /* LINTED */
+ (size_t)((double)pagex / 9.0);
+ marginy = /* LINTED */
+ (size_t)((double)pagey / 9.0);
+
+ /* Line-height is 1.4em. */
+
+ lineheight = PNT2AFM(p, ((double)p->engine.ps.scale * 1.4));
p->engine.ps.width = pagex;
p->engine.ps.height = pagey;
- p->engine.ps.header = pagey - (margin / 2);
- p->engine.ps.top = pagey - margin;
- p->engine.ps.footer = (margin / 2);
- p->engine.ps.bottom = margin;
- p->engine.ps.left = margin;
- p->engine.ps.lineheight = 12;
-
- p->defrmargin = pagex - (margin * 2);
+ p->engine.ps.header = pagey - (marginy / 2) - (lineheight / 2);
+ p->engine.ps.top = pagey - marginy;
+ p->engine.ps.footer = (marginy / 2) - (lineheight / 2);
+ p->engine.ps.bottom = marginy;
+ p->engine.ps.left = marginx;
+ p->engine.ps.lineheight = lineheight;
+
+ p->defrmargin = pagex - (marginx * 2);
return(p);
}
* into our growable margin buffer.
*/
- if ( ! (PS_MARGINS & p->engine.ps.psstate)) {
+ if ( ! (PS_MARGINS & p->engine.ps.flags)) {
vprintf(fmt, ap);
va_end(ap);
return;
/* See ps_printf(). */
- if ( ! (PS_MARGINS & p->engine.ps.psstate)) {
+ if ( ! (PS_MARGINS & p->engine.ps.flags)) {
putchar(c);
return;
}
* well as just one.
*/
- assert(0 == p->engine.ps.psstate);
- assert('\0' == p->engine.ps.last);
- assert(p->engine.ps.psmarg && p->engine.ps.psmarg[0]);
- printf("%s", p->engine.ps.psmarg);
- p->engine.ps.pages++;
- printf("showpage\n");
+ if ( ! (PS_NEWPAGE & p->engine.ps.flags)) {
+ assert(0 == p->engine.ps.flags);
+ assert('\0' == p->engine.ps.last);
+ assert(p->engine.ps.psmarg && p->engine.ps.psmarg[0]);
+ printf("%s", p->engine.ps.psmarg);
+ p->engine.ps.pages++;
+ printf("showpage\n");
+ }
printf("%%%%Trailer\n");
printf("%%%%Pages: %zu\n", p->engine.ps.pages);
}
p->engine.ps.psmargcur = 0;
- p->engine.ps.psstate = PS_MARGINS;
+ p->engine.ps.flags = PS_MARGINS;
p->engine.ps.pscol = p->engine.ps.left;
p->engine.ps.psrow = p->engine.ps.header;
(*p->footf)(p, p->argf);
(*p->endline)(p);
- p->engine.ps.psstate &= ~PS_MARGINS;
+ p->engine.ps.flags &= ~PS_MARGINS;
- assert(0 == p->engine.ps.psstate);
+ assert(0 == p->engine.ps.flags);
assert(p->engine.ps.psmarg);
assert('\0' != p->engine.ps.psmarg[0]);
printf("%%%%Orientation: Portrait\n");
printf("%%%%Pages: (atend)\n");
printf("%%%%PageOrder: Ascend\n");
- printf("%%%%Orientation: Portrait\n");
printf("%%%%DocumentMedia: Default %zu %zu 0 () ()\n",
- p->engine.ps.width,
- p->engine.ps.height);
+ AFM2PNT(p, p->engine.ps.width),
+ AFM2PNT(p, p->engine.ps.height));
printf("%%%%DocumentNeededResources: font");
for (i = 0; i < (int)TERMFONT__MAX; i++)
printf(" %s", fonts[i].name);
printf("\n%%%%EndComments\n");
- printf("%%%%Page: %zu %zu\n",
- p->engine.ps.pages + 1,
- p->engine.ps.pages + 1);
-
- ps_setfont(p, TERMFONT_NONE);
p->engine.ps.pscol = p->engine.ps.left;
p->engine.ps.psrow = p->engine.ps.top;
+ p->engine.ps.flags |= PS_NEWPAGE;
+ ps_setfont(p, TERMFONT_NONE);
}
ps_pletter(struct termp *p, int c)
{
int f;
+
+ /*
+ * If we haven't opened a page context, then output that we're
+ * in a new page and make sure the font is correctly set.
+ */
+
+ if (PS_NEWPAGE & p->engine.ps.flags) {
+ printf("%%%%Page: %zu %zu\n",
+ p->engine.ps.pages + 1,
+ p->engine.ps.pages + 1);
+ ps_printf(p, "/%s %zu selectfont\n",
+ fonts[(int)p->engine.ps.lastf].name,
+ p->engine.ps.scale);
+ p->engine.ps.flags &= ~PS_NEWPAGE;
+ }
/*
* If we're not in a PostScript "word" context, then open one
* now at the current cursor.
*/
- if ( ! (PS_INLINE & p->engine.ps.psstate)) {
+ if ( ! (PS_INLINE & p->engine.ps.flags)) {
ps_printf(p, "%zu %zu moveto\n(",
- p->engine.ps.pscol,
- p->engine.ps.psrow);
- p->engine.ps.psstate |= PS_INLINE;
+ AFM2PNT(p, p->engine.ps.pscol),
+ AFM2PNT(p, p->engine.ps.psrow));
+ p->engine.ps.flags |= PS_INLINE;
}
+ assert( ! (PS_NEWPAGE & p->engine.ps.flags));
+
/*
* We need to escape these characters as per the PostScript
* specification. We would also escape non-graphable characters
if (c <= 32 || (c - 32 > MAXCHAR)) {
ps_putchar(p, ' ');
- p->engine.ps.pscol += (fonts[f].gly[0].wx / 100);
+ p->engine.ps.pscol += fonts[f].gly[0].wx;
return;
}
- ps_putchar(p, c);
+ ps_putchar(p, (char)c);
c -= 32;
- p->engine.ps.pscol += (fonts[f].gly[c].wx / 100);
+ p->engine.ps.pscol += fonts[f].gly[c].wx;
}
* or anything).
*/
- if ( ! (PS_INLINE & p->engine.ps.psstate))
+ if ( ! (PS_INLINE & p->engine.ps.flags))
return;
ps_printf(p, ") show\n");
- p->engine.ps.psstate &= ~PS_INLINE;
+ p->engine.ps.flags &= ~PS_INLINE;
}
p->engine.ps.last = '\0';
}
- if ( ! (PS_INLINE & p->engine.ps.psstate))
+ if ( ! (PS_INLINE & p->engine.ps.flags))
return;
ps_pclose(p);
* lines, we'll do nasty stuff.
*/
- if (PS_MARGINS & p->engine.ps.psstate)
+ if (PS_MARGINS & p->engine.ps.flags)
+ return;
+
+ /* Left-justify. */
+
+ p->engine.ps.pscol = p->engine.ps.left;
+
+ /* If we haven't printed anything, return. */
+
+ if (PS_NEWPAGE & p->engine.ps.flags)
return;
/*
* showpage and restart our row.
*/
- p->engine.ps.pscol = p->engine.ps.left;
if (p->engine.ps.psrow >= p->engine.ps.lineheight +
p->engine.ps.bottom) {
p->engine.ps.psrow -= p->engine.ps.lineheight;
assert(p->engine.ps.psmarg && p->engine.ps.psmarg[0]);
printf("%s", p->engine.ps.psmarg);
- printf("%%%%Page: %zu %zu\n",
- p->engine.ps.pages + 1,
- p->engine.ps.pages + 1);
printf("showpage\n");
p->engine.ps.pages++;
p->engine.ps.psrow = p->engine.ps.top;
+ assert( ! (PS_NEWPAGE & p->engine.ps.flags));
+ p->engine.ps.flags |= PS_NEWPAGE;
}
{
assert(f < TERMFONT__MAX);
- ps_printf(p, "/%s 10 selectfont\n", fonts[(int)f].name);
p->engine.ps.lastf = f;
+
+ /*
+ * If we're still at the top of the page, let the font-setting
+ * be delayed until we actually have stuff to print.
+ */
+
+ if (PS_NEWPAGE & p->engine.ps.flags)
+ return;
+
+ ps_printf(p, "/%s %zu selectfont\n",
+ fonts[(int)f].name, p->engine.ps.scale);
}
{
if (c <= 32 || c - 32 >= MAXCHAR)
- return(fonts[(int)TERMFONT_NONE].gly[0].wx / 100);
+ return(fonts[(int)TERMFONT_NONE].gly[0].wx);
c -= 32;
- return(fonts[(int)TERMFONT_NONE].gly[(int)c].wx / 100);
+ return(fonts[(int)TERMFONT_NONE].gly[(int)c].wx);
}
+
+
+static double
+ps_hspan(const struct termp *p, const struct roffsu *su)
+{
+ double r;
+
+ /*
+ * All of these measurements are derived by converting from the
+ * native measurement to AFM units.
+ */
+
+ switch (su->unit) {
+ case (SCALE_CM):
+ r = PNT2AFM(p, su->scale * 28.34);
+ break;
+ case (SCALE_IN):
+ r = PNT2AFM(p, su->scale * 72);
+ break;
+ case (SCALE_PC):
+ r = PNT2AFM(p, su->scale * 12);
+ break;
+ case (SCALE_PT):
+ r = PNT2AFM(p, su->scale * 100);
+ break;
+ case (SCALE_EM):
+ r = su->scale *
+ fonts[(int)TERMFONT_NONE].gly[109 - 32].wx;
+ break;
+ case (SCALE_MM):
+ r = PNT2AFM(p, su->scale * 2.834);
+ break;
+ case (SCALE_EN):
+ r = su->scale *
+ fonts[(int)TERMFONT_NONE].gly[110 - 32].wx;
+ break;
+ case (SCALE_VS):
+ r = su->scale * p->engine.ps.lineheight;
+ break;
+ default:
+ r = su->scale;
+ break;
+ }
+
+ return(r);
+}
+
-/* $Id: tree.c,v 1.9 2010/06/29 17:10:30 schwarze Exp $ */
+/* $Id: tree.c,v 1.10 2010/07/13 01:09:13 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
#include <time.h>
#include "mandoc.h"
-#include "regs.h"
#include "mdoc.h"
#include "man.h"
#include "main.h"