Merge mandoc from vendor into contrib and provide the necessary Makefile glue.
It's not yet connected to the build.
This commit is contained in:
commit
e4d7d10517
39
contrib/mdocml/arch.c
Normal file
39
contrib/mdocml/arch.c
Normal file
@ -0,0 +1,39 @@
|
||||
/* $Id: arch.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "mdoc.h"
|
||||
#include "mandoc.h"
|
||||
#include "libmdoc.h"
|
||||
|
||||
#define LINE(x, y) \
|
||||
if (0 == strcmp(p, x)) return(y);
|
||||
|
||||
const char *
|
||||
mdoc_a2arch(const char *p)
|
||||
{
|
||||
|
||||
#include "arch.in"
|
||||
|
||||
return(NULL);
|
||||
}
|
111
contrib/mdocml/arch.in
Normal file
111
contrib/mdocml/arch.in
Normal file
@ -0,0 +1,111 @@
|
||||
/* $Id: arch.in,v 1.12 2012/01/28 14:02:17 joerg Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file defines the architecture token of the .Dt prologue macro.
|
||||
* All architectures that your system supports (or the manuals of your
|
||||
* system) should be included here. The right-hand-side is the
|
||||
* formatted output.
|
||||
*
|
||||
* Be sure to escape strings.
|
||||
*
|
||||
* REMEMBER TO ADD NEW ARCHITECTURES TO MDOC.7!
|
||||
*/
|
||||
|
||||
LINE("acorn26", "Acorn26")
|
||||
LINE("acorn32", "Acorn32")
|
||||
LINE("algor", "Algor")
|
||||
LINE("alpha", "Alpha")
|
||||
LINE("amd64", "AMD64")
|
||||
LINE("amiga", "Amiga")
|
||||
LINE("amigappc", "AmigaPPC")
|
||||
LINE("arc", "ARC")
|
||||
LINE("arm", "ARM")
|
||||
LINE("arm26", "ARM26")
|
||||
LINE("arm32", "ARM32")
|
||||
LINE("armish", "ARMISH")
|
||||
LINE("aviion", "AViiON")
|
||||
LINE("atari", "ATARI")
|
||||
LINE("beagle", "Beagle")
|
||||
LINE("bebox", "BeBox")
|
||||
LINE("cats", "cats")
|
||||
LINE("cesfic", "CESFIC")
|
||||
LINE("cobalt", "Cobalt")
|
||||
LINE("dreamcast", "Dreamcast")
|
||||
LINE("emips", "EMIPS")
|
||||
LINE("evbarm", "evbARM")
|
||||
LINE("evbmips", "evbMIPS")
|
||||
LINE("evbppc", "evbPPC")
|
||||
LINE("evbsh3", "evbSH3")
|
||||
LINE("ews4800mips", "EWS4800MIPS")
|
||||
LINE("hp300", "HP300")
|
||||
LINE("hp700", "HP700")
|
||||
LINE("hpcarm", "HPCARM")
|
||||
LINE("hpcmips", "HPCMIPS")
|
||||
LINE("hpcsh", "HPCSH")
|
||||
LINE("hppa", "HPPA")
|
||||
LINE("hppa64", "HPPA64")
|
||||
LINE("ia64", "ia64")
|
||||
LINE("i386", "i386")
|
||||
LINE("ibmnws", "IBMNWS")
|
||||
LINE("iyonix", "Iyonix")
|
||||
LINE("landisk", "LANDISK")
|
||||
LINE("loongson", "Loongson")
|
||||
LINE("luna68k", "Luna68k")
|
||||
LINE("luna88k", "Luna88k")
|
||||
LINE("m68k", "m68k")
|
||||
LINE("mac68k", "Mac68k")
|
||||
LINE("macppc", "MacPPC")
|
||||
LINE("mips", "MIPS")
|
||||
LINE("mips64", "MIPS64")
|
||||
LINE("mipsco", "MIPSCo")
|
||||
LINE("mmeye", "mmEye")
|
||||
LINE("mvme68k", "MVME68k")
|
||||
LINE("mvme88k", "MVME88k")
|
||||
LINE("mvmeppc", "MVMEPPC")
|
||||
LINE("netwinder", "NetWinder")
|
||||
LINE("news68k", "NeWS68k")
|
||||
LINE("newsmips", "NeWSMIPS")
|
||||
LINE("next68k", "NeXT68k")
|
||||
LINE("ofppc", "OFPPC")
|
||||
LINE("palm", "Palm")
|
||||
LINE("pc532", "PC532")
|
||||
LINE("playstation2", "PlayStation2")
|
||||
LINE("pmax", "PMAX")
|
||||
LINE("pmppc", "pmPPC")
|
||||
LINE("powerpc", "PowerPC")
|
||||
LINE("prep", "PReP")
|
||||
LINE("rs6000", "RS6000")
|
||||
LINE("sandpoint", "Sandpoint")
|
||||
LINE("sbmips", "SBMIPS")
|
||||
LINE("sgi", "SGI")
|
||||
LINE("sgimips", "SGIMIPS")
|
||||
LINE("sh3", "SH3")
|
||||
LINE("shark", "Shark")
|
||||
LINE("socppc", "SOCPPC")
|
||||
LINE("solbourne", "Solbourne")
|
||||
LINE("sparc", "SPARC")
|
||||
LINE("sparc64", "SPARC64")
|
||||
LINE("sun2", "Sun2")
|
||||
LINE("sun3", "Sun3")
|
||||
LINE("tahoe", "Tahoe")
|
||||
LINE("vax", "VAX")
|
||||
LINE("x68k", "X68k")
|
||||
LINE("x86", "x86")
|
||||
LINE("x86_64", "x86_64")
|
||||
LINE("xen", "Xen")
|
||||
LINE("zaurus", "Zaurus")
|
39
contrib/mdocml/att.c
Normal file
39
contrib/mdocml/att.c
Normal file
@ -0,0 +1,39 @@
|
||||
/* $Id: att.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "mdoc.h"
|
||||
#include "mandoc.h"
|
||||
#include "libmdoc.h"
|
||||
|
||||
#define LINE(x, y) \
|
||||
if (0 == strcmp(p, x)) return(y);
|
||||
|
||||
const char *
|
||||
mdoc_a2att(const char *p)
|
||||
{
|
||||
|
||||
#include "att.in"
|
||||
|
||||
return(NULL);
|
||||
}
|
40
contrib/mdocml/att.in
Normal file
40
contrib/mdocml/att.in
Normal file
@ -0,0 +1,40 @@
|
||||
/* $Id: att.in,v 1.8 2011/07/31 17:30:33 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file defines the AT&T versions of the .At macro. This probably
|
||||
* isn't going to change. The right-hand side is the formatted string.
|
||||
*
|
||||
* Be sure to escape strings.
|
||||
* The non-breaking blanks prevent ending an output line right before
|
||||
* a number. Groff prevent line breaks at the same places.
|
||||
*/
|
||||
|
||||
LINE("v1", "Version\\~1 AT&T UNIX")
|
||||
LINE("v2", "Version\\~2 AT&T UNIX")
|
||||
LINE("v3", "Version\\~3 AT&T UNIX")
|
||||
LINE("v4", "Version\\~4 AT&T UNIX")
|
||||
LINE("v5", "Version\\~5 AT&T UNIX")
|
||||
LINE("v6", "Version\\~6 AT&T UNIX")
|
||||
LINE("v7", "Version\\~7 AT&T UNIX")
|
||||
LINE("32v", "Version\\~32V AT&T UNIX")
|
||||
LINE("III", "AT&T System\\~III UNIX")
|
||||
LINE("V", "AT&T System\\~V UNIX")
|
||||
LINE("V.1", "AT&T System\\~V Release\\~1 UNIX")
|
||||
LINE("V.2", "AT&T System\\~V Release\\~2 UNIX")
|
||||
LINE("V.3", "AT&T System\\~V Release\\~3 UNIX")
|
||||
LINE("V.4", "AT&T System\\~V Release\\~4 UNIX")
|
167
contrib/mdocml/chars.c
Normal file
167
contrib/mdocml/chars.c
Normal file
@ -0,0 +1,167 @@
|
||||
/* $Id: chars.c,v 1.52 2011/11/08 00:15:23 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "libmandoc.h"
|
||||
|
||||
#define PRINT_HI 126
|
||||
#define PRINT_LO 32
|
||||
|
||||
struct ln {
|
||||
struct ln *next;
|
||||
const char *code;
|
||||
const char *ascii;
|
||||
int unicode;
|
||||
};
|
||||
|
||||
#define LINES_MAX 328
|
||||
|
||||
#define CHAR(in, ch, code) \
|
||||
{ NULL, (in), (ch), (code) },
|
||||
|
||||
#define CHAR_TBL_START static struct ln lines[LINES_MAX] = {
|
||||
#define CHAR_TBL_END };
|
||||
|
||||
#include "chars.in"
|
||||
|
||||
struct mchars {
|
||||
struct ln **htab;
|
||||
};
|
||||
|
||||
static const struct ln *find(const struct mchars *,
|
||||
const char *, size_t);
|
||||
|
||||
void
|
||||
mchars_free(struct mchars *arg)
|
||||
{
|
||||
|
||||
free(arg->htab);
|
||||
free(arg);
|
||||
}
|
||||
|
||||
struct mchars *
|
||||
mchars_alloc(void)
|
||||
{
|
||||
struct mchars *tab;
|
||||
struct ln **htab;
|
||||
struct ln *pp;
|
||||
int i, hash;
|
||||
|
||||
/*
|
||||
* Constructs a very basic chaining hashtable. The hash routine
|
||||
* is simply the integral value of the first character.
|
||||
* Subsequent entries are chained in the order they're processed.
|
||||
*/
|
||||
|
||||
tab = mandoc_malloc(sizeof(struct mchars));
|
||||
htab = mandoc_calloc(PRINT_HI - PRINT_LO + 1, sizeof(struct ln **));
|
||||
|
||||
for (i = 0; i < LINES_MAX; i++) {
|
||||
hash = (int)lines[i].code[0] - PRINT_LO;
|
||||
|
||||
if (NULL == (pp = htab[hash])) {
|
||||
htab[hash] = &lines[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
for ( ; pp->next; pp = pp->next)
|
||||
/* Scan ahead. */ ;
|
||||
pp->next = &lines[i];
|
||||
}
|
||||
|
||||
tab->htab = htab;
|
||||
return(tab);
|
||||
}
|
||||
|
||||
int
|
||||
mchars_spec2cp(const struct mchars *arg, const char *p, size_t sz)
|
||||
{
|
||||
const struct ln *ln;
|
||||
|
||||
ln = find(arg, p, sz);
|
||||
if (NULL == ln)
|
||||
return(-1);
|
||||
return(ln->unicode);
|
||||
}
|
||||
|
||||
char
|
||||
mchars_num2char(const char *p, size_t sz)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ((i = mandoc_strntoi(p, sz, 10)) < 0)
|
||||
return('\0');
|
||||
return(i > 0 && i < 256 && isprint(i) ?
|
||||
/* LINTED */ i : '\0');
|
||||
}
|
||||
|
||||
int
|
||||
mchars_num2uc(const char *p, size_t sz)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ((i = mandoc_strntoi(p, sz, 16)) < 0)
|
||||
return('\0');
|
||||
/* FIXME: make sure we're not in a bogus range. */
|
||||
return(i > 0x80 && i <= 0x10FFFF ? i : '\0');
|
||||
}
|
||||
|
||||
const char *
|
||||
mchars_spec2str(const struct mchars *arg,
|
||||
const char *p, size_t sz, size_t *rsz)
|
||||
{
|
||||
const struct ln *ln;
|
||||
|
||||
ln = find(arg, p, sz);
|
||||
if (NULL == ln) {
|
||||
*rsz = 1;
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
*rsz = strlen(ln->ascii);
|
||||
return(ln->ascii);
|
||||
}
|
||||
|
||||
static const struct ln *
|
||||
find(const struct mchars *tab, const char *p, size_t sz)
|
||||
{
|
||||
const struct ln *pp;
|
||||
int hash;
|
||||
|
||||
assert(p);
|
||||
|
||||
if (0 == sz || p[0] < PRINT_LO || p[0] > PRINT_HI)
|
||||
return(NULL);
|
||||
|
||||
hash = (int)p[0] - PRINT_LO;
|
||||
|
||||
for (pp = tab->htab[hash]; pp; pp = pp->next)
|
||||
if (0 == strncmp(pp->code, p, sz) &&
|
||||
'\0' == pp->code[(int)sz])
|
||||
return(pp);
|
||||
|
||||
return(NULL);
|
||||
}
|
397
contrib/mdocml/chars.in
Normal file
397
contrib/mdocml/chars.in
Normal file
@ -0,0 +1,397 @@
|
||||
/* $Id: chars.in,v 1.42 2011/10/02 10:02:26 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The ASCII translation tables.
|
||||
*
|
||||
* The left-hand side corresponds to the input sequence (\x, \(xx, \*(xx
|
||||
* and so on) whose length is listed second element. The right-hand
|
||||
* side is what's produced by the front-end, with the fourth element
|
||||
* being its length.
|
||||
*
|
||||
* XXX - C-escape strings!
|
||||
* XXX - update LINES_MAX if adding more!
|
||||
*/
|
||||
|
||||
/* Non-breaking, non-collapsing space uses unit separator. */
|
||||
static const char ascii_nbrsp[2] = { ASCII_NBRSP, '\0' };
|
||||
|
||||
CHAR_TBL_START
|
||||
|
||||
/* Spacing. */
|
||||
CHAR("c", "", 0)
|
||||
CHAR("0", " ", 8194)
|
||||
CHAR(" ", ascii_nbrsp, 160)
|
||||
CHAR("~", ascii_nbrsp, 160)
|
||||
CHAR("%", "", 0)
|
||||
CHAR("&", "", 0)
|
||||
CHAR("^", "", 0)
|
||||
CHAR("|", "", 0)
|
||||
CHAR("}", "", 0)
|
||||
|
||||
/* Accents. */
|
||||
CHAR("a\"", "\"", 779)
|
||||
CHAR("a-", "-", 175)
|
||||
CHAR("a.", ".", 729)
|
||||
CHAR("a^", "^", 770)
|
||||
CHAR("\'", "\'", 769)
|
||||
CHAR("aa", "\'", 769)
|
||||
CHAR("ga", "`", 768)
|
||||
CHAR("`", "`", 768)
|
||||
CHAR("ab", "`", 774)
|
||||
CHAR("ac", ",", 807)
|
||||
CHAR("ad", "\"", 776)
|
||||
CHAR("ah", "v", 711)
|
||||
CHAR("ao", "o", 730)
|
||||
CHAR("a~", "~", 771)
|
||||
CHAR("ho", ",", 808)
|
||||
CHAR("ha", "^", 94)
|
||||
CHAR("ti", "~", 126)
|
||||
|
||||
/* Quotes. */
|
||||
CHAR("Bq", ",,", 8222)
|
||||
CHAR("bq", ",", 8218)
|
||||
CHAR("lq", "``", 8220)
|
||||
CHAR("rq", "\'\'", 8221)
|
||||
CHAR("oq", "`", 8216)
|
||||
CHAR("cq", "\'", 8217)
|
||||
CHAR("aq", "\'", 39)
|
||||
CHAR("dq", "\"", 34)
|
||||
CHAR("Fo", "<<", 171)
|
||||
CHAR("Fc", ">>", 187)
|
||||
CHAR("fo", "<", 8249)
|
||||
CHAR("fc", ">", 8250)
|
||||
|
||||
/* Brackets. */
|
||||
CHAR("lB", "[", 91)
|
||||
CHAR("rB", "]", 93)
|
||||
CHAR("lC", "{", 123)
|
||||
CHAR("rC", "}", 125)
|
||||
CHAR("la", "<", 60)
|
||||
CHAR("ra", ">", 62)
|
||||
CHAR("bv", "|", 9130)
|
||||
CHAR("braceex", "|", 9130)
|
||||
CHAR("bracketlefttp", "|", 9121)
|
||||
CHAR("bracketleftbp", "|", 9123)
|
||||
CHAR("bracketleftex", "|", 9122)
|
||||
CHAR("bracketrighttp", "|", 9124)
|
||||
CHAR("bracketrightbp", "|", 9126)
|
||||
CHAR("bracketrightex", "|", 9125)
|
||||
CHAR("lt", ",-", 9127)
|
||||
CHAR("bracelefttp", ",-", 9127)
|
||||
CHAR("lk", "{", 9128)
|
||||
CHAR("braceleftmid", "{", 9128)
|
||||
CHAR("lb", ",-", 9129)
|
||||
CHAR("braceleftbp", "`-", 9129)
|
||||
CHAR("braceleftex", "|", 9130)
|
||||
CHAR("rt", "-.", 9131)
|
||||
CHAR("bracerighttp", "-.", 9131)
|
||||
CHAR("rk", "}", 9132)
|
||||
CHAR("bracerightmid", "}", 9132)
|
||||
CHAR("rb", "-\'", 9133)
|
||||
CHAR("bracerightbp", "-\'", 9133)
|
||||
CHAR("bracerightex", "|", 9130)
|
||||
CHAR("parenlefttp", "/", 9115)
|
||||
CHAR("parenleftbp", "\\", 9117)
|
||||
CHAR("parenleftex", "|", 9116)
|
||||
CHAR("parenrighttp", "\\", 9118)
|
||||
CHAR("parenrightbp", "/", 9120)
|
||||
CHAR("parenrightex", "|", 9119)
|
||||
|
||||
/* Greek characters. */
|
||||
CHAR("*A", "A", 913)
|
||||
CHAR("*B", "B", 914)
|
||||
CHAR("*G", "|", 915)
|
||||
CHAR("*D", "/\\", 916)
|
||||
CHAR("*E", "E", 917)
|
||||
CHAR("*Z", "Z", 918)
|
||||
CHAR("*Y", "H", 919)
|
||||
CHAR("*H", "O", 920)
|
||||
CHAR("*I", "I", 921)
|
||||
CHAR("*K", "K", 922)
|
||||
CHAR("*L", "/\\", 923)
|
||||
CHAR("*M", "M", 924)
|
||||
CHAR("*N", "N", 925)
|
||||
CHAR("*C", "H", 926)
|
||||
CHAR("*O", "O", 927)
|
||||
CHAR("*P", "TT", 928)
|
||||
CHAR("*R", "P", 929)
|
||||
CHAR("*S", ">", 931)
|
||||
CHAR("*T", "T", 932)
|
||||
CHAR("*U", "Y", 933)
|
||||
CHAR("*F", "O_", 934)
|
||||
CHAR("*X", "X", 935)
|
||||
CHAR("*Q", "Y", 936)
|
||||
CHAR("*W", "O", 937)
|
||||
CHAR("*a", "a", 945)
|
||||
CHAR("*b", "B", 946)
|
||||
CHAR("*g", "y", 947)
|
||||
CHAR("*d", "d", 948)
|
||||
CHAR("*e", "e", 949)
|
||||
CHAR("*z", "C", 950)
|
||||
CHAR("*y", "n", 951)
|
||||
CHAR("*h", "0", 952)
|
||||
CHAR("*i", "i", 953)
|
||||
CHAR("*k", "k", 954)
|
||||
CHAR("*l", "\\", 955)
|
||||
CHAR("*m", "u", 956)
|
||||
CHAR("*n", "v", 957)
|
||||
CHAR("*c", "E", 958)
|
||||
CHAR("*o", "o", 959)
|
||||
CHAR("*p", "n", 960)
|
||||
CHAR("*r", "p", 961)
|
||||
CHAR("*s", "o", 963)
|
||||
CHAR("*t", "t", 964)
|
||||
CHAR("*u", "u", 965)
|
||||
CHAR("*f", "o", 981)
|
||||
CHAR("*x", "x", 967)
|
||||
CHAR("*q", "u", 968)
|
||||
CHAR("*w", "w", 969)
|
||||
CHAR("+h", "0", 977)
|
||||
CHAR("+f", "o", 966)
|
||||
CHAR("+p", "w", 982)
|
||||
CHAR("+e", "e", 1013)
|
||||
CHAR("ts", "s", 962)
|
||||
|
||||
/* Accented letters. */
|
||||
CHAR(",C", "C", 199)
|
||||
CHAR(",c", "c", 231)
|
||||
CHAR("/L", "L", 321)
|
||||
CHAR("/O", "O", 216)
|
||||
CHAR("/l", "l", 322)
|
||||
CHAR("/o", "o", 248)
|
||||
CHAR("oA", "A", 197)
|
||||
CHAR("oa", "a", 229)
|
||||
CHAR(":A", "A", 196)
|
||||
CHAR(":E", "E", 203)
|
||||
CHAR(":I", "I", 207)
|
||||
CHAR(":O", "O", 214)
|
||||
CHAR(":U", "U", 220)
|
||||
CHAR(":a", "a", 228)
|
||||
CHAR(":e", "e", 235)
|
||||
CHAR(":i", "i", 239)
|
||||
CHAR(":o", "o", 246)
|
||||
CHAR(":u", "u", 252)
|
||||
CHAR(":y", "y", 255)
|
||||
CHAR("\'A", "A", 193)
|
||||
CHAR("\'E", "E", 201)
|
||||
CHAR("\'I", "I", 205)
|
||||
CHAR("\'O", "O", 211)
|
||||
CHAR("\'U", "U", 218)
|
||||
CHAR("\'a", "a", 225)
|
||||
CHAR("\'e", "e", 233)
|
||||
CHAR("\'i", "i", 237)
|
||||
CHAR("\'o", "o", 243)
|
||||
CHAR("\'u", "u", 250)
|
||||
CHAR("^A", "A", 194)
|
||||
CHAR("^E", "E", 202)
|
||||
CHAR("^I", "I", 206)
|
||||
CHAR("^O", "O", 212)
|
||||
CHAR("^U", "U", 219)
|
||||
CHAR("^a", "a", 226)
|
||||
CHAR("^e", "e", 234)
|
||||
CHAR("^i", "i", 238)
|
||||
CHAR("^o", "o", 244)
|
||||
CHAR("^u", "u", 251)
|
||||
CHAR("`A", "A", 192)
|
||||
CHAR("`E", "E", 200)
|
||||
CHAR("`I", "I", 204)
|
||||
CHAR("`O", "O", 210)
|
||||
CHAR("`U", "U", 217)
|
||||
CHAR("`a", "a", 224)
|
||||
CHAR("`e", "e", 232)
|
||||
CHAR("`i", "i", 236)
|
||||
CHAR("`o", "o", 242)
|
||||
CHAR("`u", "u", 249)
|
||||
CHAR("~A", "A", 195)
|
||||
CHAR("~N", "N", 209)
|
||||
CHAR("~O", "O", 213)
|
||||
CHAR("~a", "a", 227)
|
||||
CHAR("~n", "n", 241)
|
||||
CHAR("~o", "o", 245)
|
||||
|
||||
/* Arrows and lines. */
|
||||
CHAR("<-", "<-", 8592)
|
||||
CHAR("->", "->", 8594)
|
||||
CHAR("<>", "<>", 8596)
|
||||
CHAR("da", "v", 8595)
|
||||
CHAR("ua", "^", 8593)
|
||||
CHAR("va", "^v", 8597)
|
||||
CHAR("lA", "<=", 8656)
|
||||
CHAR("rA", "=>", 8658)
|
||||
CHAR("hA", "<=>", 8660)
|
||||
CHAR("dA", "v", 8659)
|
||||
CHAR("uA", "^", 8657)
|
||||
CHAR("vA", "^=v", 8661)
|
||||
|
||||
/* Logic. */
|
||||
CHAR("AN", "^", 8743)
|
||||
CHAR("OR", "v", 8744)
|
||||
CHAR("no", "~", 172)
|
||||
CHAR("tno", "~", 172)
|
||||
CHAR("te", "3", 8707)
|
||||
CHAR("fa", "V", 8704)
|
||||
CHAR("st", "-)", 8715)
|
||||
CHAR("tf", ".:.", 8756)
|
||||
CHAR("3d", ".:.", 8756)
|
||||
CHAR("or", "|", 124)
|
||||
|
||||
/* Mathematicals. */
|
||||
CHAR("pl", "+", 43)
|
||||
CHAR("mi", "-", 8722)
|
||||
CHAR("-", "-", 45)
|
||||
CHAR("-+", "-+", 8723)
|
||||
CHAR("+-", "+-", 177)
|
||||
CHAR("t+-", "+-", 177)
|
||||
CHAR("pc", ".", 183)
|
||||
CHAR("md", ".", 8901)
|
||||
CHAR("mu", "x", 215)
|
||||
CHAR("tmu", "x", 215)
|
||||
CHAR("c*", "x", 8855)
|
||||
CHAR("c+", "+", 8853)
|
||||
CHAR("di", "-:-", 247)
|
||||
CHAR("tdi", "-:-", 247)
|
||||
CHAR("f/", "/", 8260)
|
||||
CHAR("**", "*", 8727)
|
||||
CHAR("<=", "<=", 8804)
|
||||
CHAR(">=", ">=", 8805)
|
||||
CHAR("<<", "<<", 8810)
|
||||
CHAR(">>", ">>", 8811)
|
||||
CHAR("eq", "=", 61)
|
||||
CHAR("!=", "!=", 8800)
|
||||
CHAR("==", "==", 8801)
|
||||
CHAR("ne", "!==", 8802)
|
||||
CHAR("=~", "=~", 8773)
|
||||
CHAR("-~", "-~", 8771)
|
||||
CHAR("ap", "~", 8764)
|
||||
CHAR("~~", "~~", 8776)
|
||||
CHAR("~=", "~=", 8780)
|
||||
CHAR("pt", "oc", 8733)
|
||||
CHAR("es", "{}", 8709)
|
||||
CHAR("mo", "E", 8712)
|
||||
CHAR("nm", "!E", 8713)
|
||||
CHAR("sb", "(=", 8834)
|
||||
CHAR("nb", "(!=", 8836)
|
||||
CHAR("sp", "=)", 8835)
|
||||
CHAR("nc", "!=)", 8837)
|
||||
CHAR("ib", "(=", 8838)
|
||||
CHAR("ip", "=)", 8839)
|
||||
CHAR("ca", "(^)", 8745)
|
||||
CHAR("cu", "U", 8746)
|
||||
CHAR("/_", "/_", 8736)
|
||||
CHAR("pp", "_|_", 8869)
|
||||
CHAR("is", "I", 8747)
|
||||
CHAR("integral", "I", 8747)
|
||||
CHAR("sum", "E", 8721)
|
||||
CHAR("product", "TT", 8719)
|
||||
CHAR("coproduct", "U", 8720)
|
||||
CHAR("gr", "V", 8711)
|
||||
CHAR("sr", "\\/", 8730)
|
||||
CHAR("sqrt", "\\/", 8730)
|
||||
CHAR("lc", "|~", 8968)
|
||||
CHAR("rc", "~|", 8969)
|
||||
CHAR("lf", "|_", 8970)
|
||||
CHAR("rf", "_|", 8971)
|
||||
CHAR("if", "oo", 8734)
|
||||
CHAR("Ah", "N", 8501)
|
||||
CHAR("Im", "I", 8465)
|
||||
CHAR("Re", "R", 8476)
|
||||
CHAR("pd", "a", 8706)
|
||||
CHAR("-h", "/h", 8463)
|
||||
CHAR("12", "1/2", 189)
|
||||
CHAR("14", "1/4", 188)
|
||||
CHAR("34", "3/4", 190)
|
||||
|
||||
/* Ligatures. */
|
||||
CHAR("ff", "ff", 64256)
|
||||
CHAR("fi", "fi", 64257)
|
||||
CHAR("fl", "fl", 64258)
|
||||
CHAR("Fi", "ffi", 64259)
|
||||
CHAR("Fl", "ffl", 64260)
|
||||
CHAR("AE", "AE", 198)
|
||||
CHAR("ae", "ae", 230)
|
||||
CHAR("OE", "OE", 338)
|
||||
CHAR("oe", "oe", 339)
|
||||
CHAR("ss", "ss", 223)
|
||||
CHAR("IJ", "IJ", 306)
|
||||
CHAR("ij", "ij", 307)
|
||||
|
||||
/* Special letters. */
|
||||
CHAR("-D", "D", 208)
|
||||
CHAR("Sd", "o", 240)
|
||||
CHAR("TP", "b", 222)
|
||||
CHAR("Tp", "b", 254)
|
||||
CHAR(".i", "i", 305)
|
||||
CHAR(".j", "j", 567)
|
||||
|
||||
/* Currency. */
|
||||
CHAR("Do", "$", 36)
|
||||
CHAR("ct", "c", 162)
|
||||
CHAR("Eu", "EUR", 8364)
|
||||
CHAR("eu", "EUR", 8364)
|
||||
CHAR("Ye", "Y", 165)
|
||||
CHAR("Po", "L", 163)
|
||||
CHAR("Cs", "x", 164)
|
||||
CHAR("Fn", "f", 402)
|
||||
|
||||
/* Lines. */
|
||||
CHAR("ba", "|", 124)
|
||||
CHAR("br", "|", 9474)
|
||||
CHAR("ul", "_", 95)
|
||||
CHAR("rl", "-", 8254)
|
||||
CHAR("bb", "|", 166)
|
||||
CHAR("sl", "/", 47)
|
||||
CHAR("rs", "\\", 92)
|
||||
|
||||
/* Text markers. */
|
||||
CHAR("ci", "o", 9675)
|
||||
CHAR("bu", "o", 8226)
|
||||
CHAR("dd", "=", 8225)
|
||||
CHAR("dg", "-", 8224)
|
||||
CHAR("lz", "<>", 9674)
|
||||
CHAR("sq", "[]", 9633)
|
||||
CHAR("ps", "9|", 182)
|
||||
CHAR("sc", "S", 167)
|
||||
CHAR("lh", "<=", 9756)
|
||||
CHAR("rh", "=>", 9758)
|
||||
CHAR("at", "@", 64)
|
||||
CHAR("sh", "#", 35)
|
||||
CHAR("CR", "_|", 8629)
|
||||
CHAR("OK", "\\/", 10003)
|
||||
|
||||
/* Legal symbols. */
|
||||
CHAR("co", "(C)", 169)
|
||||
CHAR("rg", "(R)", 174)
|
||||
CHAR("tm", "tm", 8482)
|
||||
|
||||
/* Punctuation. */
|
||||
CHAR(".", ".", 46)
|
||||
CHAR("r!", "i", 161)
|
||||
CHAR("r?", "c", 191)
|
||||
CHAR("em", "--", 8212)
|
||||
CHAR("en", "-", 8211)
|
||||
CHAR("hy", "-", 8208)
|
||||
CHAR("e", "\\", 92)
|
||||
|
||||
/* Units. */
|
||||
CHAR("de", "o", 176)
|
||||
CHAR("%0", "%o", 8240)
|
||||
CHAR("fm", "\'", 8242)
|
||||
CHAR("sd", "\"", 8243)
|
||||
CHAR("mc", "mu", 181)
|
||||
|
||||
CHAR_TBL_END
|
93
contrib/mdocml/compat_fgetln.c
Normal file
93
contrib/mdocml/compat_fgetln.c
Normal file
@ -0,0 +1,93 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FGETLN
|
||||
|
||||
int dummy;
|
||||
|
||||
#else
|
||||
|
||||
/* $NetBSD: fgetln.c,v 1.3 2006/09/25 07:18:17 lukem Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Christos Zoulas.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
char *
|
||||
fgetln(fp, len)
|
||||
FILE *fp;
|
||||
size_t *len;
|
||||
{
|
||||
static char *buf = NULL;
|
||||
static size_t bufsiz = 0;
|
||||
char *ptr;
|
||||
|
||||
|
||||
if (buf == NULL) {
|
||||
bufsiz = BUFSIZ;
|
||||
if ((buf = malloc(bufsiz)) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fgets(buf, bufsiz, fp) == NULL)
|
||||
return NULL;
|
||||
|
||||
*len = 0;
|
||||
while ((ptr = strchr(&buf[*len], '\n')) == NULL) {
|
||||
size_t nbufsiz = bufsiz + BUFSIZ;
|
||||
char *nbuf = realloc(buf, nbufsiz);
|
||||
|
||||
if (nbuf == NULL) {
|
||||
int oerrno = errno;
|
||||
free(buf);
|
||||
errno = oerrno;
|
||||
buf = NULL;
|
||||
return NULL;
|
||||
} else
|
||||
buf = nbuf;
|
||||
|
||||
*len = bufsiz;
|
||||
if (fgets(&buf[bufsiz], BUFSIZ, fp) == NULL)
|
||||
return buf;
|
||||
|
||||
bufsiz = nbufsiz;
|
||||
}
|
||||
|
||||
*len = (ptr - buf) + 1;
|
||||
return buf;
|
||||
}
|
||||
|
||||
#endif
|
104
contrib/mdocml/compat_getsubopt.c
Normal file
104
contrib/mdocml/compat_getsubopt.c
Normal file
@ -0,0 +1,104 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GETSUBOPT
|
||||
|
||||
int dummy;
|
||||
|
||||
#else
|
||||
|
||||
/* $OpenBSD: getsubopt.c,v 1.4 2005/08/08 08:05:36 espie Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* The SVID interface to getsubopt provides no way of figuring out which
|
||||
* part of the suboptions list wasn't matched. This makes error messages
|
||||
* tricky... The extern variable suboptarg is a pointer to the token
|
||||
* which didn't match.
|
||||
*/
|
||||
char *suboptarg;
|
||||
|
||||
int
|
||||
getsubopt(char **optionp, char * const *tokens, char **valuep)
|
||||
{
|
||||
int cnt;
|
||||
char *p;
|
||||
|
||||
suboptarg = *valuep = NULL;
|
||||
|
||||
if (!optionp || !*optionp)
|
||||
return(-1);
|
||||
|
||||
/* skip leading white-space, commas */
|
||||
for (p = *optionp; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p);
|
||||
|
||||
if (!*p) {
|
||||
*optionp = p;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* save the start of the token, and skip the rest of the token. */
|
||||
for (suboptarg = p;
|
||||
*++p && *p != ',' && *p != '=' && *p != ' ' && *p != '\t';);
|
||||
|
||||
if (*p) {
|
||||
/*
|
||||
* If there's an equals sign, set the value pointer, and
|
||||
* skip over the value part of the token. Terminate the
|
||||
* token.
|
||||
*/
|
||||
if (*p == '=') {
|
||||
*p = '\0';
|
||||
for (*valuep = ++p;
|
||||
*p && *p != ',' && *p != ' ' && *p != '\t'; ++p);
|
||||
if (*p)
|
||||
*p++ = '\0';
|
||||
} else
|
||||
*p++ = '\0';
|
||||
/* Skip any whitespace or commas after this token. */
|
||||
for (; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p);
|
||||
}
|
||||
|
||||
/* set optionp for next round. */
|
||||
*optionp = p;
|
||||
|
||||
for (cnt = 0; *tokens; ++tokens, ++cnt)
|
||||
if (!strcmp(suboptarg, *tokens))
|
||||
return(cnt);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
#endif
|
67
contrib/mdocml/compat_strlcat.c
Normal file
67
contrib/mdocml/compat_strlcat.c
Normal file
@ -0,0 +1,67 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRLCAT
|
||||
|
||||
int dummy;
|
||||
|
||||
#else
|
||||
|
||||
/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Appends src to string dst of size siz (unlike strncat, siz is the
|
||||
* full size of dst, not space left). At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
|
||||
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
|
||||
* If retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t
|
||||
strlcat(char *dst, const char *src, size_t siz)
|
||||
{
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
size_t n = siz;
|
||||
size_t dlen;
|
||||
|
||||
/* Find the end of dst and adjust bytes left but don't go past end */
|
||||
while (n-- != 0 && *d != '\0')
|
||||
d++;
|
||||
dlen = d - dst;
|
||||
n = siz - dlen;
|
||||
|
||||
if (n == 0)
|
||||
return(dlen + strlen(s));
|
||||
while (*s != '\0') {
|
||||
if (n != 1) {
|
||||
*d++ = *s;
|
||||
n--;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
*d = '\0';
|
||||
|
||||
return(dlen + (s - src)); /* count does not include NUL */
|
||||
}
|
||||
|
||||
#endif
|
63
contrib/mdocml/compat_strlcpy.c
Normal file
63
contrib/mdocml/compat_strlcpy.c
Normal file
@ -0,0 +1,63 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRLCPY
|
||||
|
||||
int dummy;
|
||||
|
||||
#else
|
||||
|
||||
/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Copy src to string dst of size siz. At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz == 0).
|
||||
* Returns strlen(src); if retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t
|
||||
strlcpy(char *dst, const char *src, size_t siz)
|
||||
{
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
size_t n = siz;
|
||||
|
||||
/* Copy as many bytes as will fit */
|
||||
if (n != 0) {
|
||||
while (--n != 0) {
|
||||
if ((*d++ = *s++) == '\0')
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not enough room in dst, add NUL and traverse rest of src */
|
||||
if (n == 0) {
|
||||
if (siz != 0)
|
||||
*d = '\0'; /* NUL-terminate dst */
|
||||
while (*s++)
|
||||
;
|
||||
}
|
||||
|
||||
return(s - src - 1); /* count does not include NUL */
|
||||
}
|
||||
|
||||
#endif
|
58
contrib/mdocml/config.h
Normal file
58
contrib/mdocml/config.h
Normal file
@ -0,0 +1,58 @@
|
||||
#ifndef MANDOC_CONFIG_H
|
||||
#define MANDOC_CONFIG_H
|
||||
|
||||
#if defined(__linux__) || defined(__MINT__)
|
||||
# define _GNU_SOURCE /* strptime(), getsubopt() */
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define HAVE_FGETLN
|
||||
#define HAVE_STRPTIME
|
||||
#define HAVE_GETSUBOPT
|
||||
#define HAVE_STRLCAT
|
||||
#define HAVE_MMAP
|
||||
#define HAVE_STRLCPY
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#if !defined(__BEGIN_DECLS)
|
||||
# ifdef __cplusplus
|
||||
# define __BEGIN_DECLS extern "C" {
|
||||
# else
|
||||
# define __BEGIN_DECLS
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(__END_DECLS)
|
||||
# ifdef __cplusplus
|
||||
# define __END_DECLS }
|
||||
# else
|
||||
# define __END_DECLS
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# define htobe32(x) OSSwapHostToBigInt32(x)
|
||||
# define betoh32(x) OSSwapBigToHostInt32(x)
|
||||
# define htobe64(x) OSSwapHostToBigInt64(x)
|
||||
# define betoh64(x) OSSwapBigToHostInt64(x)
|
||||
#elif defined(__linux__)
|
||||
# define betoh32(x) be32toh(x)
|
||||
# define betoh64(x) be64toh(x)
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRLCAT
|
||||
extern size_t strlcat(char *, const char *, size_t);
|
||||
#endif
|
||||
#ifndef HAVE_STRLCPY
|
||||
extern size_t strlcpy(char *, const char *, size_t);
|
||||
#endif
|
||||
#ifndef HAVE_GETSUBOPT
|
||||
extern int getsubopt(char **, char * const *, char **);
|
||||
extern char *suboptarg;
|
||||
#endif
|
||||
#ifndef HAVE_FGETLN
|
||||
extern char *fgetln(FILE *, size_t *);
|
||||
#endif
|
||||
|
||||
#endif /* MANDOC_CONFIG_H */
|
280
contrib/mdocml/eqn.7
Normal file
280
contrib/mdocml/eqn.7
Normal file
@ -0,0 +1,280 @@
|
||||
.\" $Id: eqn.7,v 1.28 2011/09/25 18:37:09 schwarze Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2011 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.
|
||||
.\"
|
||||
.Dd $Mdocdate: September 25 2011 $
|
||||
.Dt EQN 7
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm eqn
|
||||
.Nd eqn language reference for mandoc
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm eqn
|
||||
language is an equation-formatting language.
|
||||
It is used within
|
||||
.Xr mdoc 7
|
||||
and
|
||||
.Xr man 7
|
||||
.Ux
|
||||
manual pages.
|
||||
It describes the
|
||||
.Em structure
|
||||
of an equation, not its mathematical meaning.
|
||||
This manual describes the
|
||||
.Nm
|
||||
language accepted by the
|
||||
.Xr mandoc 1
|
||||
utility, which corresponds to the Second Edition eqn specification (see
|
||||
.Sx SEE ALSO
|
||||
for references).
|
||||
.Pp
|
||||
Equations within
|
||||
.Xr mdoc 7
|
||||
or
|
||||
.Xr man 7
|
||||
documents are enclosed by the standalone
|
||||
.Sq \&.EQ
|
||||
and
|
||||
.Sq \&.EN
|
||||
tags.
|
||||
Equations are multi-line blocks consisting of formulas and control
|
||||
statements.
|
||||
.Sh EQUATION STRUCTURE
|
||||
Each equation is bracketed by
|
||||
.Sq \&.EQ
|
||||
and
|
||||
.Sq \&.EN
|
||||
strings.
|
||||
.Em Note :
|
||||
these are not the same as
|
||||
.Xr roff 7
|
||||
macros, and may only be invoked as
|
||||
.Sq \&.EQ .
|
||||
.Pp
|
||||
The equation grammar is as follows, where quoted strings are
|
||||
case-sensitive literals in the input:
|
||||
.Bd -literal -offset indent
|
||||
eqn : box | eqn box
|
||||
box : text
|
||||
| \*q{\*q eqn \*q}\*q
|
||||
| \*qdefine\*q text text
|
||||
| \*qndefine\*q text text
|
||||
| \*qtdefine\*q text text
|
||||
| \*qgfont\*q text
|
||||
| \*qgsize\*q text
|
||||
| \*qset\*q text text
|
||||
| \*qundef\*q text
|
||||
| box pos box
|
||||
| box mark
|
||||
| \*qmatrix\*q \*q{\*q [col \*q{\*q list \*q}\*q ]*
|
||||
| pile \*q{\*q list \*q}\*q
|
||||
| font box
|
||||
| \*qsize\*q text box
|
||||
| \*qleft\*q text eqn [\*qright\*q text]
|
||||
col : \*qlcol\*q | \*qrcol\*q | \*qccol\*q | \*qcol\*q
|
||||
text : [^space\e\*q]+ | \e\*q.*\e\*q
|
||||
pile : \*qlpile\*q | \*qcpile\*q | \*qrpile\*q | \*qpile\*q
|
||||
pos : \*qover\*q | \*qsup\*q | \*qsub\*q | \*qto\*q | \*qfrom\*q
|
||||
mark : \*qdot\*q | \*qdotdot\*q | \*qhat\*q | \*qtilde\*q | \*qvec\*q
|
||||
| \*qdyad\*q | \*qbar\*q | \*qunder\*q
|
||||
font : \*qroman\*q | \*qitalic\*q | \*qbold\*q | \*qfat\*q
|
||||
list : eqn
|
||||
| list \*qabove\*q eqn
|
||||
space : [\e^~ \et]
|
||||
.Ed
|
||||
.Pp
|
||||
White-space consists of the space, tab, circumflex, and tilde
|
||||
characters.
|
||||
If within a quoted string, these space characters are retained.
|
||||
Quoted strings are also not scanned for replacement definitions.
|
||||
.Pp
|
||||
The following text terms are translated into a rendered glyph, if
|
||||
available: alpha, beta, chi, delta, epsilon, eta, gamma, iota, kappa,
|
||||
lambda, mu, nu, omega, omicron, phi, pi, psi, rho, sigma, tau, theta,
|
||||
upsilon, xi, zeta, DELTA, GAMMA, LAMBDA, OMEGA, PHI, PI, PSI, SIGMA,
|
||||
THETA, UPSILON, XI, inter (intersection), union (union), prod (product),
|
||||
int (integral), sum (summation), grad (gradient), del (vector
|
||||
differential), times (multiply), cdot (centre-dot), nothing (zero-width
|
||||
space), approx (approximately equals), prime (prime), half (one-half),
|
||||
partial (partial differential), inf (infinity), >> (much greater), <<
|
||||
(much less), \-> (left arrow), <\- (right arrow), += (plus-minus), !=
|
||||
(not equal), == (equivalence), <= (less-than-equal), and >=
|
||||
(more-than-equal).
|
||||
.Pp
|
||||
The following control statements are available:
|
||||
.Bl -tag -width Ds
|
||||
.It Cm define
|
||||
Replace all occurrences of a key with a value.
|
||||
Its syntax is as follows:
|
||||
.Pp
|
||||
.D1 define Ar key cvalc
|
||||
.Pp
|
||||
The first character of the value string,
|
||||
.Ar c ,
|
||||
is used as the delimiter for the value
|
||||
.Ar val .
|
||||
This allows for arbitrary enclosure of terms (not just quotes), such as
|
||||
.Pp
|
||||
.D1 define Ar foo 'bar baz'
|
||||
.D1 define Ar foo cbar bazc
|
||||
.Pp
|
||||
It is an error to have an empty
|
||||
.Ar key
|
||||
or
|
||||
.Ar val .
|
||||
Note that a quoted
|
||||
.Ar key
|
||||
causes errors in some
|
||||
.Nm
|
||||
implementations and should not be considered portable.
|
||||
It is not expanded for replacements.
|
||||
Definitions may refer to other definitions; these are evaluated
|
||||
recursively when text replacement occurs and not when the definition is
|
||||
created.
|
||||
.Pp
|
||||
Definitions can create arbitrary strings, for example, the following is
|
||||
a legal construction.
|
||||
.Bd -literal -offset indent
|
||||
define foo 'define'
|
||||
foo bar 'baz'
|
||||
.Ed
|
||||
.Pp
|
||||
Self-referencing definitions will raise an error.
|
||||
The
|
||||
.Cm ndefine
|
||||
statement is a synonym for
|
||||
.Cm define ,
|
||||
while
|
||||
.Cm tdefine
|
||||
is discarded.
|
||||
.It Cm gfont
|
||||
Set the default font of subsequent output.
|
||||
Its syntax is as follows:
|
||||
.Pp
|
||||
.D1 gfont Ar font
|
||||
.Pp
|
||||
In mandoc, this value is discarded.
|
||||
.It Cm gsize
|
||||
Set the default size of subsequent output.
|
||||
Its syntax is as follows:
|
||||
.Pp
|
||||
.D1 gsize Ar size
|
||||
.Pp
|
||||
The
|
||||
.Ar size
|
||||
value should be an integer.
|
||||
.It Cm set
|
||||
Set an equation mode.
|
||||
In mandoc, both arguments are thrown away.
|
||||
Its syntax is as follows:
|
||||
.Pp
|
||||
.D1 set Ar key val
|
||||
.Pp
|
||||
The
|
||||
.Ar key
|
||||
and
|
||||
.Ar val
|
||||
are not expanded for replacements.
|
||||
This statement is a GNU extension.
|
||||
.It Cm undef
|
||||
Unset a previously-defined key.
|
||||
Its syntax is as follows:
|
||||
.Pp
|
||||
.D1 define Ar key
|
||||
.Pp
|
||||
Once invoked, the definition for
|
||||
.Ar key
|
||||
is discarded.
|
||||
The
|
||||
.Ar key
|
||||
is not expanded for replacements.
|
||||
This statement is a GNU extension.
|
||||
.El
|
||||
.Sh COMPATIBILITY
|
||||
This section documents the compatibility of mandoc
|
||||
.Nm
|
||||
and the troff
|
||||
.Nm
|
||||
implementation (including GNU troff).
|
||||
.Pp
|
||||
.Bl -dash -compact
|
||||
.It
|
||||
The text string
|
||||
.Sq \e\*q
|
||||
is interpreted as a literal quote in troff.
|
||||
In mandoc, this is interpreted as a comment.
|
||||
.It
|
||||
In troff, The circumflex and tilde white-space symbols map to
|
||||
fixed-width spaces.
|
||||
In mandoc, these characters are synonyms for the space character.
|
||||
.It
|
||||
The troff implementation of
|
||||
.Nm
|
||||
allows for equation alignment with the
|
||||
.Cm mark
|
||||
and
|
||||
.Cm lineup
|
||||
tokens.
|
||||
mandoc discards these tokens.
|
||||
The
|
||||
.Cm back Ar n ,
|
||||
.Cm fwd Ar n ,
|
||||
.Cm up Ar n ,
|
||||
and
|
||||
.Cm down Ar n
|
||||
commands are also ignored.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr mandoc 1 ,
|
||||
.Xr man 7 ,
|
||||
.Xr mandoc_char 7 ,
|
||||
.Xr mdoc 7 ,
|
||||
.Xr roff 7
|
||||
.Rs
|
||||
.%A Brian W. Kernighan
|
||||
.%A Lorinda L. Cherry
|
||||
.%T System for Typesetting Mathematics
|
||||
.%J Communications of the ACM
|
||||
.%V 18
|
||||
.%P 151\(en157
|
||||
.%D March, 1975
|
||||
.Re
|
||||
.Rs
|
||||
.%A Brian W. Kernighan
|
||||
.%A Lorinda L. Cherry
|
||||
.%T Typesetting Mathematics, User's Guide
|
||||
.%D 1976
|
||||
.Re
|
||||
.Rs
|
||||
.%A Brian W. Kernighan
|
||||
.%A Lorinda L. Cherry
|
||||
.%T Typesetting Mathematics, User's Guide (Second Edition)
|
||||
.%D 1978
|
||||
.Re
|
||||
.Sh HISTORY
|
||||
The eqn utility, a preprocessor for troff, was originally written by
|
||||
Brian W. Kernighan and Lorinda L. Cherry in 1975.
|
||||
The GNU reimplementation of eqn, part of the GNU troff package, was
|
||||
released in 1989 by James Clark.
|
||||
The eqn component of
|
||||
.Xr mandoc 1
|
||||
was added in 2011.
|
||||
.Sh AUTHORS
|
||||
This
|
||||
.Nm
|
||||
reference was written by
|
||||
.An Kristaps Dzonsons ,
|
||||
.Mt kristaps@bsd.lv .
|
949
contrib/mdocml/eqn.c
Normal file
949
contrib/mdocml/eqn.c
Normal file
@ -0,0 +1,949 @@
|
||||
/* $Id: eqn.c,v 1.38 2011/07/25 15:37:00 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "libmandoc.h"
|
||||
#include "libroff.h"
|
||||
|
||||
#define EQN_NEST_MAX 128 /* maximum nesting of defines */
|
||||
#define EQN_MSG(t, x) mandoc_msg((t), (x)->parse, (x)->eqn.ln, (x)->eqn.pos, NULL)
|
||||
|
||||
enum eqn_rest {
|
||||
EQN_DESCOPE,
|
||||
EQN_ERR,
|
||||
EQN_OK,
|
||||
EQN_EOF
|
||||
};
|
||||
|
||||
enum eqn_symt {
|
||||
EQNSYM_alpha,
|
||||
EQNSYM_beta,
|
||||
EQNSYM_chi,
|
||||
EQNSYM_delta,
|
||||
EQNSYM_epsilon,
|
||||
EQNSYM_eta,
|
||||
EQNSYM_gamma,
|
||||
EQNSYM_iota,
|
||||
EQNSYM_kappa,
|
||||
EQNSYM_lambda,
|
||||
EQNSYM_mu,
|
||||
EQNSYM_nu,
|
||||
EQNSYM_omega,
|
||||
EQNSYM_omicron,
|
||||
EQNSYM_phi,
|
||||
EQNSYM_pi,
|
||||
EQNSYM_ps,
|
||||
EQNSYM_rho,
|
||||
EQNSYM_sigma,
|
||||
EQNSYM_tau,
|
||||
EQNSYM_theta,
|
||||
EQNSYM_upsilon,
|
||||
EQNSYM_xi,
|
||||
EQNSYM_zeta,
|
||||
EQNSYM_DELTA,
|
||||
EQNSYM_GAMMA,
|
||||
EQNSYM_LAMBDA,
|
||||
EQNSYM_OMEGA,
|
||||
EQNSYM_PHI,
|
||||
EQNSYM_PI,
|
||||
EQNSYM_PSI,
|
||||
EQNSYM_SIGMA,
|
||||
EQNSYM_THETA,
|
||||
EQNSYM_UPSILON,
|
||||
EQNSYM_XI,
|
||||
EQNSYM_inter,
|
||||
EQNSYM_union,
|
||||
EQNSYM_prod,
|
||||
EQNSYM_int,
|
||||
EQNSYM_sum,
|
||||
EQNSYM_grad,
|
||||
EQNSYM_del,
|
||||
EQNSYM_times,
|
||||
EQNSYM_cdot,
|
||||
EQNSYM_nothing,
|
||||
EQNSYM_approx,
|
||||
EQNSYM_prime,
|
||||
EQNSYM_half,
|
||||
EQNSYM_partial,
|
||||
EQNSYM_inf,
|
||||
EQNSYM_muchgreat,
|
||||
EQNSYM_muchless,
|
||||
EQNSYM_larrow,
|
||||
EQNSYM_rarrow,
|
||||
EQNSYM_pm,
|
||||
EQNSYM_nequal,
|
||||
EQNSYM_equiv,
|
||||
EQNSYM_lessequal,
|
||||
EQNSYM_moreequal,
|
||||
EQNSYM__MAX
|
||||
};
|
||||
|
||||
enum eqnpartt {
|
||||
EQN_DEFINE = 0,
|
||||
EQN_NDEFINE,
|
||||
EQN_TDEFINE,
|
||||
EQN_SET,
|
||||
EQN_UNDEF,
|
||||
EQN_GFONT,
|
||||
EQN_GSIZE,
|
||||
EQN_BACK,
|
||||
EQN_FWD,
|
||||
EQN_UP,
|
||||
EQN_DOWN,
|
||||
EQN__MAX
|
||||
};
|
||||
|
||||
struct eqnstr {
|
||||
const char *name;
|
||||
size_t sz;
|
||||
};
|
||||
|
||||
#define STRNEQ(p1, sz1, p2, sz2) \
|
||||
((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1)))
|
||||
#define EQNSTREQ(x, p, sz) \
|
||||
STRNEQ((x)->name, (x)->sz, (p), (sz))
|
||||
|
||||
struct eqnpart {
|
||||
struct eqnstr str;
|
||||
int (*fp)(struct eqn_node *);
|
||||
};
|
||||
|
||||
struct eqnsym {
|
||||
struct eqnstr str;
|
||||
const char *sym;
|
||||
};
|
||||
|
||||
|
||||
static enum eqn_rest eqn_box(struct eqn_node *, struct eqn_box *);
|
||||
static struct eqn_box *eqn_box_alloc(struct eqn_node *,
|
||||
struct eqn_box *);
|
||||
static void eqn_box_free(struct eqn_box *);
|
||||
static struct eqn_def *eqn_def_find(struct eqn_node *,
|
||||
const char *, size_t);
|
||||
static int eqn_do_gfont(struct eqn_node *);
|
||||
static int eqn_do_gsize(struct eqn_node *);
|
||||
static int eqn_do_define(struct eqn_node *);
|
||||
static int eqn_do_ign1(struct eqn_node *);
|
||||
static int eqn_do_ign2(struct eqn_node *);
|
||||
static int eqn_do_tdefine(struct eqn_node *);
|
||||
static int eqn_do_undef(struct eqn_node *);
|
||||
static enum eqn_rest eqn_eqn(struct eqn_node *, struct eqn_box *);
|
||||
static enum eqn_rest eqn_list(struct eqn_node *, struct eqn_box *);
|
||||
static enum eqn_rest eqn_matrix(struct eqn_node *, struct eqn_box *);
|
||||
static const char *eqn_nexttok(struct eqn_node *, size_t *);
|
||||
static const char *eqn_nextrawtok(struct eqn_node *, size_t *);
|
||||
static const char *eqn_next(struct eqn_node *,
|
||||
char, size_t *, int);
|
||||
static void eqn_rewind(struct eqn_node *);
|
||||
|
||||
static const struct eqnpart eqnparts[EQN__MAX] = {
|
||||
{ { "define", 6 }, eqn_do_define }, /* EQN_DEFINE */
|
||||
{ { "ndefine", 7 }, eqn_do_define }, /* EQN_NDEFINE */
|
||||
{ { "tdefine", 7 }, eqn_do_tdefine }, /* EQN_TDEFINE */
|
||||
{ { "set", 3 }, eqn_do_ign2 }, /* EQN_SET */
|
||||
{ { "undef", 5 }, eqn_do_undef }, /* EQN_UNDEF */
|
||||
{ { "gfont", 5 }, eqn_do_gfont }, /* EQN_GFONT */
|
||||
{ { "gsize", 5 }, eqn_do_gsize }, /* EQN_GSIZE */
|
||||
{ { "back", 4 }, eqn_do_ign1 }, /* EQN_BACK */
|
||||
{ { "fwd", 3 }, eqn_do_ign1 }, /* EQN_FWD */
|
||||
{ { "up", 2 }, eqn_do_ign1 }, /* EQN_UP */
|
||||
{ { "down", 4 }, eqn_do_ign1 }, /* EQN_DOWN */
|
||||
};
|
||||
|
||||
static const struct eqnstr eqnmarks[EQNMARK__MAX] = {
|
||||
{ "", 0 }, /* EQNMARK_NONE */
|
||||
{ "dot", 3 }, /* EQNMARK_DOT */
|
||||
{ "dotdot", 6 }, /* EQNMARK_DOTDOT */
|
||||
{ "hat", 3 }, /* EQNMARK_HAT */
|
||||
{ "tilde", 5 }, /* EQNMARK_TILDE */
|
||||
{ "vec", 3 }, /* EQNMARK_VEC */
|
||||
{ "dyad", 4 }, /* EQNMARK_DYAD */
|
||||
{ "bar", 3 }, /* EQNMARK_BAR */
|
||||
{ "under", 5 }, /* EQNMARK_UNDER */
|
||||
};
|
||||
|
||||
static const struct eqnstr eqnfonts[EQNFONT__MAX] = {
|
||||
{ "", 0 }, /* EQNFONT_NONE */
|
||||
{ "roman", 5 }, /* EQNFONT_ROMAN */
|
||||
{ "bold", 4 }, /* EQNFONT_BOLD */
|
||||
{ "fat", 3 }, /* EQNFONT_FAT */
|
||||
{ "italic", 6 }, /* EQNFONT_ITALIC */
|
||||
};
|
||||
|
||||
static const struct eqnstr eqnposs[EQNPOS__MAX] = {
|
||||
{ "", 0 }, /* EQNPOS_NONE */
|
||||
{ "over", 4 }, /* EQNPOS_OVER */
|
||||
{ "sup", 3 }, /* EQNPOS_SUP */
|
||||
{ "sub", 3 }, /* EQNPOS_SUB */
|
||||
{ "to", 2 }, /* EQNPOS_TO */
|
||||
{ "from", 4 }, /* EQNPOS_FROM */
|
||||
};
|
||||
|
||||
static const struct eqnstr eqnpiles[EQNPILE__MAX] = {
|
||||
{ "", 0 }, /* EQNPILE_NONE */
|
||||
{ "pile", 4 }, /* EQNPILE_PILE */
|
||||
{ "cpile", 5 }, /* EQNPILE_CPILE */
|
||||
{ "rpile", 5 }, /* EQNPILE_RPILE */
|
||||
{ "lpile", 5 }, /* EQNPILE_LPILE */
|
||||
{ "col", 3 }, /* EQNPILE_COL */
|
||||
{ "ccol", 4 }, /* EQNPILE_CCOL */
|
||||
{ "rcol", 4 }, /* EQNPILE_RCOL */
|
||||
{ "lcol", 4 }, /* EQNPILE_LCOL */
|
||||
};
|
||||
|
||||
static const struct eqnsym eqnsyms[EQNSYM__MAX] = {
|
||||
{ { "alpha", 5 }, "*a" }, /* EQNSYM_alpha */
|
||||
{ { "beta", 4 }, "*b" }, /* EQNSYM_beta */
|
||||
{ { "chi", 3 }, "*x" }, /* EQNSYM_chi */
|
||||
{ { "delta", 5 }, "*d" }, /* EQNSYM_delta */
|
||||
{ { "epsilon", 7 }, "*e" }, /* EQNSYM_epsilon */
|
||||
{ { "eta", 3 }, "*y" }, /* EQNSYM_eta */
|
||||
{ { "gamma", 5 }, "*g" }, /* EQNSYM_gamma */
|
||||
{ { "iota", 4 }, "*i" }, /* EQNSYM_iota */
|
||||
{ { "kappa", 5 }, "*k" }, /* EQNSYM_kappa */
|
||||
{ { "lambda", 6 }, "*l" }, /* EQNSYM_lambda */
|
||||
{ { "mu", 2 }, "*m" }, /* EQNSYM_mu */
|
||||
{ { "nu", 2 }, "*n" }, /* EQNSYM_nu */
|
||||
{ { "omega", 5 }, "*w" }, /* EQNSYM_omega */
|
||||
{ { "omicron", 7 }, "*o" }, /* EQNSYM_omicron */
|
||||
{ { "phi", 3 }, "*f" }, /* EQNSYM_phi */
|
||||
{ { "pi", 2 }, "*p" }, /* EQNSYM_pi */
|
||||
{ { "psi", 2 }, "*q" }, /* EQNSYM_psi */
|
||||
{ { "rho", 3 }, "*r" }, /* EQNSYM_rho */
|
||||
{ { "sigma", 5 }, "*s" }, /* EQNSYM_sigma */
|
||||
{ { "tau", 3 }, "*t" }, /* EQNSYM_tau */
|
||||
{ { "theta", 5 }, "*h" }, /* EQNSYM_theta */
|
||||
{ { "upsilon", 7 }, "*u" }, /* EQNSYM_upsilon */
|
||||
{ { "xi", 2 }, "*c" }, /* EQNSYM_xi */
|
||||
{ { "zeta", 4 }, "*z" }, /* EQNSYM_zeta */
|
||||
{ { "DELTA", 5 }, "*D" }, /* EQNSYM_DELTA */
|
||||
{ { "GAMMA", 5 }, "*G" }, /* EQNSYM_GAMMA */
|
||||
{ { "LAMBDA", 6 }, "*L" }, /* EQNSYM_LAMBDA */
|
||||
{ { "OMEGA", 5 }, "*W" }, /* EQNSYM_OMEGA */
|
||||
{ { "PHI", 3 }, "*F" }, /* EQNSYM_PHI */
|
||||
{ { "PI", 2 }, "*P" }, /* EQNSYM_PI */
|
||||
{ { "PSI", 3 }, "*Q" }, /* EQNSYM_PSI */
|
||||
{ { "SIGMA", 5 }, "*S" }, /* EQNSYM_SIGMA */
|
||||
{ { "THETA", 5 }, "*H" }, /* EQNSYM_THETA */
|
||||
{ { "UPSILON", 7 }, "*U" }, /* EQNSYM_UPSILON */
|
||||
{ { "XI", 2 }, "*C" }, /* EQNSYM_XI */
|
||||
{ { "inter", 5 }, "ca" }, /* EQNSYM_inter */
|
||||
{ { "union", 5 }, "cu" }, /* EQNSYM_union */
|
||||
{ { "prod", 4 }, "product" }, /* EQNSYM_prod */
|
||||
{ { "int", 3 }, "integral" }, /* EQNSYM_int */
|
||||
{ { "sum", 3 }, "sum" }, /* EQNSYM_sum */
|
||||
{ { "grad", 4 }, "gr" }, /* EQNSYM_grad */
|
||||
{ { "del", 3 }, "gr" }, /* EQNSYM_del */
|
||||
{ { "times", 5 }, "mu" }, /* EQNSYM_times */
|
||||
{ { "cdot", 4 }, "pc" }, /* EQNSYM_cdot */
|
||||
{ { "nothing", 7 }, "&" }, /* EQNSYM_nothing */
|
||||
{ { "approx", 6 }, "~~" }, /* EQNSYM_approx */
|
||||
{ { "prime", 5 }, "aq" }, /* EQNSYM_prime */
|
||||
{ { "half", 4 }, "12" }, /* EQNSYM_half */
|
||||
{ { "partial", 7 }, "pd" }, /* EQNSYM_partial */
|
||||
{ { "inf", 3 }, "if" }, /* EQNSYM_inf */
|
||||
{ { ">>", 2 }, ">>" }, /* EQNSYM_muchgreat */
|
||||
{ { "<<", 2 }, "<<" }, /* EQNSYM_muchless */
|
||||
{ { "<-", 2 }, "<-" }, /* EQNSYM_larrow */
|
||||
{ { "->", 2 }, "->" }, /* EQNSYM_rarrow */
|
||||
{ { "+-", 2 }, "+-" }, /* EQNSYM_pm */
|
||||
{ { "!=", 2 }, "!=" }, /* EQNSYM_nequal */
|
||||
{ { "==", 2 }, "==" }, /* EQNSYM_equiv */
|
||||
{ { "<=", 2 }, "<=" }, /* EQNSYM_lessequal */
|
||||
{ { ">=", 2 }, ">=" }, /* EQNSYM_moreequal */
|
||||
};
|
||||
|
||||
/* ARGSUSED */
|
||||
enum rofferr
|
||||
eqn_read(struct eqn_node **epp, int ln,
|
||||
const char *p, int pos, int *offs)
|
||||
{
|
||||
size_t sz;
|
||||
struct eqn_node *ep;
|
||||
enum rofferr er;
|
||||
|
||||
ep = *epp;
|
||||
|
||||
/*
|
||||
* If we're the terminating mark, unset our equation status and
|
||||
* validate the full equation.
|
||||
*/
|
||||
|
||||
if (0 == strncmp(p, ".EN", 3)) {
|
||||
er = eqn_end(epp);
|
||||
p += 3;
|
||||
while (' ' == *p || '\t' == *p)
|
||||
p++;
|
||||
if ('\0' == *p)
|
||||
return(er);
|
||||
mandoc_msg(MANDOCERR_ARGSLOST, ep->parse, ln, pos, NULL);
|
||||
return(er);
|
||||
}
|
||||
|
||||
/*
|
||||
* Build up the full string, replacing all newlines with regular
|
||||
* whitespace.
|
||||
*/
|
||||
|
||||
sz = strlen(p + pos) + 1;
|
||||
ep->data = mandoc_realloc(ep->data, ep->sz + sz + 1);
|
||||
|
||||
/* First invocation: nil terminate the string. */
|
||||
|
||||
if (0 == ep->sz)
|
||||
*ep->data = '\0';
|
||||
|
||||
ep->sz += sz;
|
||||
strlcat(ep->data, p + pos, ep->sz + 1);
|
||||
strlcat(ep->data, " ", ep->sz + 1);
|
||||
return(ROFF_IGN);
|
||||
}
|
||||
|
||||
struct eqn_node *
|
||||
eqn_alloc(const char *name, int pos, int line, struct mparse *parse)
|
||||
{
|
||||
struct eqn_node *p;
|
||||
size_t sz;
|
||||
const char *end;
|
||||
|
||||
p = mandoc_calloc(1, sizeof(struct eqn_node));
|
||||
|
||||
if (name && '\0' != *name) {
|
||||
sz = strlen(name);
|
||||
assert(sz);
|
||||
do {
|
||||
sz--;
|
||||
end = name + (int)sz;
|
||||
} while (' ' == *end || '\t' == *end);
|
||||
p->eqn.name = mandoc_strndup(name, sz + 1);
|
||||
}
|
||||
|
||||
p->parse = parse;
|
||||
p->eqn.ln = line;
|
||||
p->eqn.pos = pos;
|
||||
p->gsize = EQN_DEFSIZE;
|
||||
|
||||
return(p);
|
||||
}
|
||||
|
||||
enum rofferr
|
||||
eqn_end(struct eqn_node **epp)
|
||||
{
|
||||
struct eqn_node *ep;
|
||||
struct eqn_box *root;
|
||||
enum eqn_rest c;
|
||||
|
||||
ep = *epp;
|
||||
*epp = NULL;
|
||||
|
||||
ep->eqn.root = mandoc_calloc(1, sizeof(struct eqn_box));
|
||||
|
||||
root = ep->eqn.root;
|
||||
root->type = EQN_ROOT;
|
||||
|
||||
if (0 == ep->sz)
|
||||
return(ROFF_IGN);
|
||||
|
||||
if (EQN_DESCOPE == (c = eqn_eqn(ep, root))) {
|
||||
EQN_MSG(MANDOCERR_EQNNSCOPE, ep);
|
||||
c = EQN_ERR;
|
||||
}
|
||||
|
||||
return(EQN_EOF == c ? ROFF_EQN : ROFF_IGN);
|
||||
}
|
||||
|
||||
static enum eqn_rest
|
||||
eqn_eqn(struct eqn_node *ep, struct eqn_box *last)
|
||||
{
|
||||
struct eqn_box *bp;
|
||||
enum eqn_rest c;
|
||||
|
||||
bp = eqn_box_alloc(ep, last);
|
||||
bp->type = EQN_SUBEXPR;
|
||||
|
||||
while (EQN_OK == (c = eqn_box(ep, bp)))
|
||||
/* Spin! */ ;
|
||||
|
||||
return(c);
|
||||
}
|
||||
|
||||
static enum eqn_rest
|
||||
eqn_matrix(struct eqn_node *ep, struct eqn_box *last)
|
||||
{
|
||||
struct eqn_box *bp;
|
||||
const char *start;
|
||||
size_t sz;
|
||||
enum eqn_rest c;
|
||||
|
||||
bp = eqn_box_alloc(ep, last);
|
||||
bp->type = EQN_MATRIX;
|
||||
|
||||
if (NULL == (start = eqn_nexttok(ep, &sz))) {
|
||||
EQN_MSG(MANDOCERR_EQNEOF, ep);
|
||||
return(EQN_ERR);
|
||||
}
|
||||
if ( ! STRNEQ(start, sz, "{", 1)) {
|
||||
EQN_MSG(MANDOCERR_EQNSYNT, ep);
|
||||
return(EQN_ERR);
|
||||
}
|
||||
|
||||
while (EQN_OK == (c = eqn_box(ep, bp)))
|
||||
switch (bp->last->pile) {
|
||||
case (EQNPILE_LCOL):
|
||||
/* FALLTHROUGH */
|
||||
case (EQNPILE_CCOL):
|
||||
/* FALLTHROUGH */
|
||||
case (EQNPILE_RCOL):
|
||||
continue;
|
||||
default:
|
||||
EQN_MSG(MANDOCERR_EQNSYNT, ep);
|
||||
return(EQN_ERR);
|
||||
};
|
||||
|
||||
if (EQN_DESCOPE != c) {
|
||||
if (EQN_EOF == c)
|
||||
EQN_MSG(MANDOCERR_EQNEOF, ep);
|
||||
return(EQN_ERR);
|
||||
}
|
||||
|
||||
eqn_rewind(ep);
|
||||
start = eqn_nexttok(ep, &sz);
|
||||
assert(start);
|
||||
if (STRNEQ(start, sz, "}", 1))
|
||||
return(EQN_OK);
|
||||
|
||||
EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
|
||||
return(EQN_ERR);
|
||||
}
|
||||
|
||||
static enum eqn_rest
|
||||
eqn_list(struct eqn_node *ep, struct eqn_box *last)
|
||||
{
|
||||
struct eqn_box *bp;
|
||||
const char *start;
|
||||
size_t sz;
|
||||
enum eqn_rest c;
|
||||
|
||||
bp = eqn_box_alloc(ep, last);
|
||||
bp->type = EQN_LIST;
|
||||
|
||||
if (NULL == (start = eqn_nexttok(ep, &sz))) {
|
||||
EQN_MSG(MANDOCERR_EQNEOF, ep);
|
||||
return(EQN_ERR);
|
||||
}
|
||||
if ( ! STRNEQ(start, sz, "{", 1)) {
|
||||
EQN_MSG(MANDOCERR_EQNSYNT, ep);
|
||||
return(EQN_ERR);
|
||||
}
|
||||
|
||||
while (EQN_DESCOPE == (c = eqn_eqn(ep, bp))) {
|
||||
eqn_rewind(ep);
|
||||
start = eqn_nexttok(ep, &sz);
|
||||
assert(start);
|
||||
if ( ! STRNEQ(start, sz, "above", 5))
|
||||
break;
|
||||
}
|
||||
|
||||
if (EQN_DESCOPE != c) {
|
||||
if (EQN_ERR != c)
|
||||
EQN_MSG(MANDOCERR_EQNSCOPE, ep);
|
||||
return(EQN_ERR);
|
||||
}
|
||||
|
||||
eqn_rewind(ep);
|
||||
start = eqn_nexttok(ep, &sz);
|
||||
assert(start);
|
||||
if (STRNEQ(start, sz, "}", 1))
|
||||
return(EQN_OK);
|
||||
|
||||
EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
|
||||
return(EQN_ERR);
|
||||
}
|
||||
|
||||
static enum eqn_rest
|
||||
eqn_box(struct eqn_node *ep, struct eqn_box *last)
|
||||
{
|
||||
size_t sz;
|
||||
const char *start;
|
||||
char *left;
|
||||
char sym[64];
|
||||
enum eqn_rest c;
|
||||
int i, size;
|
||||
struct eqn_box *bp;
|
||||
|
||||
if (NULL == (start = eqn_nexttok(ep, &sz)))
|
||||
return(EQN_EOF);
|
||||
|
||||
if (STRNEQ(start, sz, "}", 1))
|
||||
return(EQN_DESCOPE);
|
||||
else if (STRNEQ(start, sz, "right", 5))
|
||||
return(EQN_DESCOPE);
|
||||
else if (STRNEQ(start, sz, "above", 5))
|
||||
return(EQN_DESCOPE);
|
||||
else if (STRNEQ(start, sz, "mark", 4))
|
||||
return(EQN_OK);
|
||||
else if (STRNEQ(start, sz, "lineup", 6))
|
||||
return(EQN_OK);
|
||||
|
||||
for (i = 0; i < (int)EQN__MAX; i++) {
|
||||
if ( ! EQNSTREQ(&eqnparts[i].str, start, sz))
|
||||
continue;
|
||||
return((*eqnparts[i].fp)(ep) ?
|
||||
EQN_OK : EQN_ERR);
|
||||
}
|
||||
|
||||
if (STRNEQ(start, sz, "{", 1)) {
|
||||
if (EQN_DESCOPE != (c = eqn_eqn(ep, last))) {
|
||||
if (EQN_ERR != c)
|
||||
EQN_MSG(MANDOCERR_EQNSCOPE, ep);
|
||||
return(EQN_ERR);
|
||||
}
|
||||
eqn_rewind(ep);
|
||||
start = eqn_nexttok(ep, &sz);
|
||||
assert(start);
|
||||
if (STRNEQ(start, sz, "}", 1))
|
||||
return(EQN_OK);
|
||||
EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
|
||||
return(EQN_ERR);
|
||||
}
|
||||
|
||||
for (i = 0; i < (int)EQNPILE__MAX; i++) {
|
||||
if ( ! EQNSTREQ(&eqnpiles[i], start, sz))
|
||||
continue;
|
||||
if (EQN_OK == (c = eqn_list(ep, last)))
|
||||
last->last->pile = (enum eqn_pilet)i;
|
||||
return(c);
|
||||
}
|
||||
|
||||
if (STRNEQ(start, sz, "matrix", 6))
|
||||
return(eqn_matrix(ep, last));
|
||||
|
||||
if (STRNEQ(start, sz, "left", 4)) {
|
||||
if (NULL == (start = eqn_nexttok(ep, &sz))) {
|
||||
EQN_MSG(MANDOCERR_EQNEOF, ep);
|
||||
return(EQN_ERR);
|
||||
}
|
||||
left = mandoc_strndup(start, sz);
|
||||
c = eqn_eqn(ep, last);
|
||||
if (last->last)
|
||||
last->last->left = left;
|
||||
else
|
||||
free(left);
|
||||
if (EQN_DESCOPE != c)
|
||||
return(c);
|
||||
assert(last->last);
|
||||
eqn_rewind(ep);
|
||||
start = eqn_nexttok(ep, &sz);
|
||||
assert(start);
|
||||
if ( ! STRNEQ(start, sz, "right", 5))
|
||||
return(EQN_DESCOPE);
|
||||
if (NULL == (start = eqn_nexttok(ep, &sz))) {
|
||||
EQN_MSG(MANDOCERR_EQNEOF, ep);
|
||||
return(EQN_ERR);
|
||||
}
|
||||
last->last->right = mandoc_strndup(start, sz);
|
||||
return(EQN_OK);
|
||||
}
|
||||
|
||||
for (i = 0; i < (int)EQNPOS__MAX; i++) {
|
||||
if ( ! EQNSTREQ(&eqnposs[i], start, sz))
|
||||
continue;
|
||||
if (NULL == last->last) {
|
||||
EQN_MSG(MANDOCERR_EQNSYNT, ep);
|
||||
return(EQN_ERR);
|
||||
}
|
||||
last->last->pos = (enum eqn_post)i;
|
||||
if (EQN_EOF == (c = eqn_box(ep, last))) {
|
||||
EQN_MSG(MANDOCERR_EQNEOF, ep);
|
||||
return(EQN_ERR);
|
||||
}
|
||||
return(c);
|
||||
}
|
||||
|
||||
for (i = 0; i < (int)EQNMARK__MAX; i++) {
|
||||
if ( ! EQNSTREQ(&eqnmarks[i], start, sz))
|
||||
continue;
|
||||
if (NULL == last->last) {
|
||||
EQN_MSG(MANDOCERR_EQNSYNT, ep);
|
||||
return(EQN_ERR);
|
||||
}
|
||||
last->last->mark = (enum eqn_markt)i;
|
||||
if (EQN_EOF == (c = eqn_box(ep, last))) {
|
||||
EQN_MSG(MANDOCERR_EQNEOF, ep);
|
||||
return(EQN_ERR);
|
||||
}
|
||||
return(c);
|
||||
}
|
||||
|
||||
for (i = 0; i < (int)EQNFONT__MAX; i++) {
|
||||
if ( ! EQNSTREQ(&eqnfonts[i], start, sz))
|
||||
continue;
|
||||
if (EQN_EOF == (c = eqn_box(ep, last))) {
|
||||
EQN_MSG(MANDOCERR_EQNEOF, ep);
|
||||
return(EQN_ERR);
|
||||
} else if (EQN_OK == c)
|
||||
last->last->font = (enum eqn_fontt)i;
|
||||
return(c);
|
||||
}
|
||||
|
||||
if (STRNEQ(start, sz, "size", 4)) {
|
||||
if (NULL == (start = eqn_nexttok(ep, &sz))) {
|
||||
EQN_MSG(MANDOCERR_EQNEOF, ep);
|
||||
return(EQN_ERR);
|
||||
}
|
||||
size = mandoc_strntoi(start, sz, 10);
|
||||
if (EQN_EOF == (c = eqn_box(ep, last))) {
|
||||
EQN_MSG(MANDOCERR_EQNEOF, ep);
|
||||
return(EQN_ERR);
|
||||
} else if (EQN_OK != c)
|
||||
return(c);
|
||||
last->last->size = size;
|
||||
}
|
||||
|
||||
bp = eqn_box_alloc(ep, last);
|
||||
bp->type = EQN_TEXT;
|
||||
for (i = 0; i < (int)EQNSYM__MAX; i++)
|
||||
if (EQNSTREQ(&eqnsyms[i].str, start, sz)) {
|
||||
sym[63] = '\0';
|
||||
snprintf(sym, 62, "\\[%s]", eqnsyms[i].sym);
|
||||
bp->text = mandoc_strdup(sym);
|
||||
return(EQN_OK);
|
||||
}
|
||||
|
||||
bp->text = mandoc_strndup(start, sz);
|
||||
return(EQN_OK);
|
||||
}
|
||||
|
||||
void
|
||||
eqn_free(struct eqn_node *p)
|
||||
{
|
||||
int i;
|
||||
|
||||
eqn_box_free(p->eqn.root);
|
||||
|
||||
for (i = 0; i < (int)p->defsz; i++) {
|
||||
free(p->defs[i].key);
|
||||
free(p->defs[i].val);
|
||||
}
|
||||
|
||||
free(p->eqn.name);
|
||||
free(p->data);
|
||||
free(p->defs);
|
||||
free(p);
|
||||
}
|
||||
|
||||
static struct eqn_box *
|
||||
eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent)
|
||||
{
|
||||
struct eqn_box *bp;
|
||||
|
||||
bp = mandoc_calloc(1, sizeof(struct eqn_box));
|
||||
bp->parent = parent;
|
||||
bp->size = ep->gsize;
|
||||
|
||||
if (NULL == parent->first)
|
||||
parent->first = bp;
|
||||
else
|
||||
parent->last->next = bp;
|
||||
|
||||
parent->last = bp;
|
||||
return(bp);
|
||||
}
|
||||
|
||||
static void
|
||||
eqn_box_free(struct eqn_box *bp)
|
||||
{
|
||||
|
||||
if (bp->first)
|
||||
eqn_box_free(bp->first);
|
||||
if (bp->next)
|
||||
eqn_box_free(bp->next);
|
||||
|
||||
free(bp->text);
|
||||
free(bp->left);
|
||||
free(bp->right);
|
||||
free(bp);
|
||||
}
|
||||
|
||||
static const char *
|
||||
eqn_nextrawtok(struct eqn_node *ep, size_t *sz)
|
||||
{
|
||||
|
||||
return(eqn_next(ep, '"', sz, 0));
|
||||
}
|
||||
|
||||
static const char *
|
||||
eqn_nexttok(struct eqn_node *ep, size_t *sz)
|
||||
{
|
||||
|
||||
return(eqn_next(ep, '"', sz, 1));
|
||||
}
|
||||
|
||||
static void
|
||||
eqn_rewind(struct eqn_node *ep)
|
||||
{
|
||||
|
||||
ep->cur = ep->rew;
|
||||
}
|
||||
|
||||
static const char *
|
||||
eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
|
||||
{
|
||||
char *start, *next;
|
||||
int q, diff, lim;
|
||||
size_t ssz, dummy;
|
||||
struct eqn_def *def;
|
||||
|
||||
if (NULL == sz)
|
||||
sz = &dummy;
|
||||
|
||||
lim = 0;
|
||||
ep->rew = ep->cur;
|
||||
again:
|
||||
/* Prevent self-definitions. */
|
||||
|
||||
if (lim >= EQN_NEST_MAX) {
|
||||
EQN_MSG(MANDOCERR_ROFFLOOP, ep);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
ep->cur = ep->rew;
|
||||
start = &ep->data[(int)ep->cur];
|
||||
q = 0;
|
||||
|
||||
if ('\0' == *start)
|
||||
return(NULL);
|
||||
|
||||
if (quote == *start) {
|
||||
ep->cur++;
|
||||
q = 1;
|
||||
}
|
||||
|
||||
start = &ep->data[(int)ep->cur];
|
||||
|
||||
if ( ! q) {
|
||||
if ('{' == *start || '}' == *start)
|
||||
ssz = 1;
|
||||
else
|
||||
ssz = strcspn(start + 1, " ^~\"{}\t") + 1;
|
||||
next = start + (int)ssz;
|
||||
if ('\0' == *next)
|
||||
next = NULL;
|
||||
} else
|
||||
next = strchr(start, quote);
|
||||
|
||||
if (NULL != next) {
|
||||
*sz = (size_t)(next - start);
|
||||
ep->cur += *sz;
|
||||
if (q)
|
||||
ep->cur++;
|
||||
while (' ' == ep->data[(int)ep->cur] ||
|
||||
'\t' == ep->data[(int)ep->cur] ||
|
||||
'^' == ep->data[(int)ep->cur] ||
|
||||
'~' == ep->data[(int)ep->cur])
|
||||
ep->cur++;
|
||||
} else {
|
||||
if (q)
|
||||
EQN_MSG(MANDOCERR_BADQUOTE, ep);
|
||||
next = strchr(start, '\0');
|
||||
*sz = (size_t)(next - start);
|
||||
ep->cur += *sz;
|
||||
}
|
||||
|
||||
/* Quotes aren't expanded for values. */
|
||||
|
||||
if (q || ! repl)
|
||||
return(start);
|
||||
|
||||
if (NULL != (def = eqn_def_find(ep, start, *sz))) {
|
||||
diff = def->valsz - *sz;
|
||||
|
||||
if (def->valsz > *sz) {
|
||||
ep->sz += diff;
|
||||
ep->data = mandoc_realloc(ep->data, ep->sz + 1);
|
||||
ep->data[ep->sz] = '\0';
|
||||
start = &ep->data[(int)ep->rew];
|
||||
}
|
||||
|
||||
diff = def->valsz - *sz;
|
||||
memmove(start + *sz + diff, start + *sz,
|
||||
(strlen(start) - *sz) + 1);
|
||||
memcpy(start, def->val, def->valsz);
|
||||
goto again;
|
||||
}
|
||||
|
||||
return(start);
|
||||
}
|
||||
|
||||
static int
|
||||
eqn_do_ign1(struct eqn_node *ep)
|
||||
{
|
||||
|
||||
if (NULL == eqn_nextrawtok(ep, NULL))
|
||||
EQN_MSG(MANDOCERR_EQNEOF, ep);
|
||||
else
|
||||
return(1);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
eqn_do_ign2(struct eqn_node *ep)
|
||||
{
|
||||
|
||||
if (NULL == eqn_nextrawtok(ep, NULL))
|
||||
EQN_MSG(MANDOCERR_EQNEOF, ep);
|
||||
else if (NULL == eqn_nextrawtok(ep, NULL))
|
||||
EQN_MSG(MANDOCERR_EQNEOF, ep);
|
||||
else
|
||||
return(1);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
eqn_do_tdefine(struct eqn_node *ep)
|
||||
{
|
||||
|
||||
if (NULL == eqn_nextrawtok(ep, NULL))
|
||||
EQN_MSG(MANDOCERR_EQNEOF, ep);
|
||||
else if (NULL == eqn_next(ep, ep->data[(int)ep->cur], NULL, 0))
|
||||
EQN_MSG(MANDOCERR_EQNEOF, ep);
|
||||
else
|
||||
return(1);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
eqn_do_define(struct eqn_node *ep)
|
||||
{
|
||||
const char *start;
|
||||
size_t sz;
|
||||
struct eqn_def *def;
|
||||
int i;
|
||||
|
||||
if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
|
||||
EQN_MSG(MANDOCERR_EQNEOF, ep);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Search for a key that already exists.
|
||||
* Create a new key if none is found.
|
||||
*/
|
||||
|
||||
if (NULL == (def = eqn_def_find(ep, start, sz))) {
|
||||
/* Find holes in string array. */
|
||||
for (i = 0; i < (int)ep->defsz; i++)
|
||||
if (0 == ep->defs[i].keysz)
|
||||
break;
|
||||
|
||||
if (i == (int)ep->defsz) {
|
||||
ep->defsz++;
|
||||
ep->defs = mandoc_realloc
|
||||
(ep->defs, ep->defsz *
|
||||
sizeof(struct eqn_def));
|
||||
ep->defs[i].key = ep->defs[i].val = NULL;
|
||||
}
|
||||
|
||||
ep->defs[i].keysz = sz;
|
||||
ep->defs[i].key = mandoc_realloc
|
||||
(ep->defs[i].key, sz + 1);
|
||||
|
||||
memcpy(ep->defs[i].key, start, sz);
|
||||
ep->defs[i].key[(int)sz] = '\0';
|
||||
def = &ep->defs[i];
|
||||
}
|
||||
|
||||
start = eqn_next(ep, ep->data[(int)ep->cur], &sz, 0);
|
||||
|
||||
if (NULL == start) {
|
||||
EQN_MSG(MANDOCERR_EQNEOF, ep);
|
||||
return(0);
|
||||
}
|
||||
|
||||
def->valsz = sz;
|
||||
def->val = mandoc_realloc(def->val, sz + 1);
|
||||
memcpy(def->val, start, sz);
|
||||
def->val[(int)sz] = '\0';
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int
|
||||
eqn_do_gfont(struct eqn_node *ep)
|
||||
{
|
||||
|
||||
if (NULL == eqn_nextrawtok(ep, NULL)) {
|
||||
EQN_MSG(MANDOCERR_EQNEOF, ep);
|
||||
return(0);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int
|
||||
eqn_do_gsize(struct eqn_node *ep)
|
||||
{
|
||||
const char *start;
|
||||
size_t sz;
|
||||
|
||||
if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
|
||||
EQN_MSG(MANDOCERR_EQNEOF, ep);
|
||||
return(0);
|
||||
}
|
||||
ep->gsize = mandoc_strntoi(start, sz, 10);
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int
|
||||
eqn_do_undef(struct eqn_node *ep)
|
||||
{
|
||||
const char *start;
|
||||
struct eqn_def *def;
|
||||
size_t sz;
|
||||
|
||||
if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
|
||||
EQN_MSG(MANDOCERR_EQNEOF, ep);
|
||||
return(0);
|
||||
} else if (NULL != (def = eqn_def_find(ep, start, sz)))
|
||||
def->keysz = 0;
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
static struct eqn_def *
|
||||
eqn_def_find(struct eqn_node *ep, const char *key, size_t sz)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (int)ep->defsz; i++)
|
||||
if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key,
|
||||
ep->defs[i].keysz, key, sz))
|
||||
return(&ep->defs[i]);
|
||||
|
||||
return(NULL);
|
||||
}
|
81
contrib/mdocml/eqn_html.c
Normal file
81
contrib/mdocml/eqn_html.c
Normal file
@ -0,0 +1,81 @@
|
||||
/* $Id: eqn_html.c,v 1.2 2011/07/24 10:09:03 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "out.h"
|
||||
#include "html.h"
|
||||
|
||||
static const enum htmltag fontmap[EQNFONT__MAX] = {
|
||||
TAG_SPAN, /* EQNFONT_NONE */
|
||||
TAG_SPAN, /* EQNFONT_ROMAN */
|
||||
TAG_B, /* EQNFONT_BOLD */
|
||||
TAG_B, /* EQNFONT_FAT */
|
||||
TAG_I /* EQNFONT_ITALIC */
|
||||
};
|
||||
|
||||
|
||||
static void eqn_box(struct html *, const struct eqn_box *);
|
||||
|
||||
void
|
||||
print_eqn(struct html *p, const struct eqn *ep)
|
||||
{
|
||||
struct htmlpair tag;
|
||||
struct tag *t;
|
||||
|
||||
PAIR_CLASS_INIT(&tag, "eqn");
|
||||
t = print_otag(p, TAG_SPAN, 1, &tag);
|
||||
|
||||
p->flags |= HTML_NONOSPACE;
|
||||
eqn_box(p, ep->root);
|
||||
p->flags &= ~HTML_NONOSPACE;
|
||||
|
||||
print_tagq(p, t);
|
||||
}
|
||||
|
||||
static void
|
||||
eqn_box(struct html *p, const struct eqn_box *bp)
|
||||
{
|
||||
struct tag *t;
|
||||
|
||||
t = EQNFONT_NONE == bp->font ? NULL :
|
||||
print_otag(p, fontmap[(int)bp->font], 0, NULL);
|
||||
|
||||
if (bp->left)
|
||||
print_text(p, bp->left);
|
||||
|
||||
if (bp->text)
|
||||
print_text(p, bp->text);
|
||||
|
||||
if (bp->first)
|
||||
eqn_box(p, bp->first);
|
||||
|
||||
if (NULL != t)
|
||||
print_tagq(p, t);
|
||||
if (bp->right)
|
||||
print_text(p, bp->right);
|
||||
|
||||
if (bp->next)
|
||||
eqn_box(p, bp->next);
|
||||
}
|
76
contrib/mdocml/eqn_term.c
Normal file
76
contrib/mdocml/eqn_term.c
Normal file
@ -0,0 +1,76 @@
|
||||
/* $Id: eqn_term.c,v 1.4 2011/07/24 10:09:03 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "out.h"
|
||||
#include "term.h"
|
||||
|
||||
static const enum termfont fontmap[EQNFONT__MAX] = {
|
||||
TERMFONT_NONE, /* EQNFONT_NONE */
|
||||
TERMFONT_NONE, /* EQNFONT_ROMAN */
|
||||
TERMFONT_BOLD, /* EQNFONT_BOLD */
|
||||
TERMFONT_BOLD, /* EQNFONT_FAT */
|
||||
TERMFONT_UNDER /* EQNFONT_ITALIC */
|
||||
};
|
||||
|
||||
static void eqn_box(struct termp *, const struct eqn_box *);
|
||||
|
||||
void
|
||||
term_eqn(struct termp *p, const struct eqn *ep)
|
||||
{
|
||||
|
||||
p->flags |= TERMP_NONOSPACE;
|
||||
eqn_box(p, ep->root);
|
||||
term_word(p, " ");
|
||||
p->flags &= ~TERMP_NONOSPACE;
|
||||
}
|
||||
|
||||
static void
|
||||
eqn_box(struct termp *p, const struct eqn_box *bp)
|
||||
{
|
||||
|
||||
if (EQNFONT_NONE != bp->font)
|
||||
term_fontpush(p, fontmap[(int)bp->font]);
|
||||
if (bp->left)
|
||||
term_word(p, bp->left);
|
||||
if (EQN_SUBEXPR == bp->type)
|
||||
term_word(p, "(");
|
||||
|
||||
if (bp->text)
|
||||
term_word(p, bp->text);
|
||||
|
||||
if (bp->first)
|
||||
eqn_box(p, bp->first);
|
||||
|
||||
if (EQN_SUBEXPR == bp->type)
|
||||
term_word(p, ")");
|
||||
if (bp->right)
|
||||
term_word(p, bp->right);
|
||||
if (EQNFONT_NONE != bp->font)
|
||||
term_fontpop(p);
|
||||
|
||||
if (bp->next)
|
||||
eqn_box(p, bp->next);
|
||||
}
|
110
contrib/mdocml/example.style.css
Normal file
110
contrib/mdocml/example.style.css
Normal file
@ -0,0 +1,110 @@
|
||||
/* $Id: example.style.css,v 1.49 2011/12/15 12:18:57 kristaps Exp $ */
|
||||
/*
|
||||
* This is an example style-sheet provided for mandoc(1) and the -Thtml
|
||||
* or -Txhtml output mode.
|
||||
* It mimics the appearance of the legacy man.cgi output.
|
||||
* See mdoc(7) and man(7) for macro explanations.
|
||||
*/
|
||||
|
||||
div.mandoc { min-width: 102ex;
|
||||
width: 102ex;
|
||||
font-family: monospace; } /* This is the outer node of all mandoc -T[x]html documents. */
|
||||
div.mandoc h1 { margin-bottom: 0ex; font-size: inherit; margin-left: -4ex; } /* Section header (Sh, SH). */
|
||||
div.mandoc h2 { margin-bottom: 0ex; font-size: inherit; margin-left: -2ex; } /* Sub-section header (Ss, SS). */
|
||||
div.mandoc table { width: 100%; margin-top: 0ex; margin-bottom: 0ex; } /* All tables. */
|
||||
div.mandoc td { vertical-align: top; } /* All table cells. */
|
||||
div.mandoc p { } /* Paragraph: Pp, Lp. */
|
||||
div.mandoc blockquote { margin-left: 5ex; margin-top: 0ex; margin-bottom: 0ex; } /* D1, Dl. */
|
||||
div.mandoc div.section { margin-bottom: 2ex; margin-left: 5ex; } /* Sections (Sh, SH). */
|
||||
div.mandoc div.subsection { } /* Sub-sections (Ss, SS). */
|
||||
div.mandoc table.synopsis { } /* SYNOPSIS section table. */
|
||||
div.mandoc table.foot { } /* Document footer. */
|
||||
div.mandoc td.foot-date { width: 50%; } /* Document footer: date. */
|
||||
div.mandoc td.foot-os { width: 50%; text-align: right; } /* Document footer: OS/source. */
|
||||
div.mandoc table.head { } /* Document header. */
|
||||
div.mandoc td.head-ltitle { width: 10%; } /* Document header: left-title. */
|
||||
div.mandoc td.head-vol { width: 80%; text-align: center; } /* Document header: volume. */
|
||||
div.mandoc td.head-rtitle { width: 10%; text-align: right; } /* Document header: right-title. */
|
||||
div.mandoc .display { } /* All Bd, D1, Dl. */
|
||||
div.mandoc .list { } /* All Bl. */
|
||||
div.mandoc i { } /* Italic: BI, IB, I, (implicit). */
|
||||
div.mandoc b { } /* Bold: SB, BI, IB, BR, RB, B, (implicit). */
|
||||
div.mandoc small { } /* Small: SB, SM. */
|
||||
div.mandoc .emph { font-style: italic; font-weight: normal; } /* Emphasis: Em, Bl -emphasis. */
|
||||
div.mandoc .symb { font-style: normal; font-weight: bold; } /* Symbolic: Sy, Ms, Bf -symbolic. */
|
||||
div.mandoc .lit { font-style: normal; font-weight: normal; font-family: monospace; } /* Literal: Dl, Li, Ql, Bf -literal, Bl -literal, Bl -unfilled. */
|
||||
div.mandoc i.addr { font-weight: normal; } /* Address (Ad). */
|
||||
div.mandoc i.arg { font-weight: normal; } /* Command argument (Ar). */
|
||||
div.mandoc span.author { } /* Author name (An). */
|
||||
div.mandoc b.cmd { font-style: normal; } /* Command (Cm). */
|
||||
div.mandoc b.config { font-style: normal; } /* Config statement (Cd). */
|
||||
div.mandoc span.define { } /* Defines (Dv). */
|
||||
div.mandoc span.desc { } /* Nd. After em-dash. */
|
||||
div.mandoc b.diag { font-style: normal; } /* Diagnostic (Bl -diag). */
|
||||
div.mandoc span.env { } /* Environment variables (Ev). */
|
||||
div.mandoc span.errno { } /* Error string (Er). */
|
||||
div.mandoc i.farg { font-weight: normal; } /* Function argument (Fa, Fn). */
|
||||
div.mandoc i.file { font-weight: normal; } /* File (Pa). */
|
||||
div.mandoc b.flag { font-style: normal; } /* Flag (Fl, Cm). */
|
||||
div.mandoc b.fname { font-style: normal; } /* Function name (Fa, Fn, Rv). */
|
||||
div.mandoc i.ftype { font-weight: normal; } /* Function types (Ft, Fn). */
|
||||
div.mandoc b.includes { font-style: normal; } /* Header includes (In). */
|
||||
div.mandoc span.lib { } /* Library (Lb). */
|
||||
div.mandoc i.link-sec { font-weight: normal; } /* Section links (Sx). */
|
||||
div.mandoc b.macro { font-style: normal; } /* Macro-ish thing (Fd). */
|
||||
div.mandoc b.name { font-style: normal; } /* Name of utility (Nm). */
|
||||
div.mandoc span.opt { } /* Options (Op, Oo/Oc). */
|
||||
div.mandoc span.ref { } /* Citations (Rs). */
|
||||
div.mandoc span.ref-auth { } /* Reference author (%A). */
|
||||
div.mandoc i.ref-book { font-weight: normal; } /* Reference book (%B). */
|
||||
div.mandoc span.ref-city { } /* Reference city (%C). */
|
||||
div.mandoc span.ref-date { } /* Reference date (%D). */
|
||||
div.mandoc i.ref-issue { font-weight: normal; } /* Reference issuer/publisher (%I). */
|
||||
div.mandoc i.ref-jrnl { font-weight: normal; } /* Reference journal (%J). */
|
||||
div.mandoc span.ref-num { } /* Reference number (%N). */
|
||||
div.mandoc span.ref-opt { } /* Reference optionals (%O). */
|
||||
div.mandoc span.ref-page { } /* Reference page (%P). */
|
||||
div.mandoc span.ref-corp { } /* Reference corporate/foreign author (%Q). */
|
||||
div.mandoc span.ref-rep { } /* Reference report (%R). */
|
||||
div.mandoc span.ref-title { text-decoration: underline; } /* Reference title (%T). */
|
||||
div.mandoc span.ref-vol { } /* Reference volume (%V). */
|
||||
div.mandoc span.type { font-style: italic; font-weight: normal; } /* Variable types (Vt). */
|
||||
div.mandoc span.unix { } /* Unices (Ux, Ox, Nx, Fx, Bx, Bsx, Dx). */
|
||||
div.mandoc b.utility { font-style: normal; } /* Name of utility (Ex). */
|
||||
div.mandoc b.var { font-style: normal; } /* Variables (Rv). */
|
||||
div.mandoc a.link-ext { } /* Off-site link (Lk). */
|
||||
div.mandoc a.link-includes { } /* Include-file link (In). */
|
||||
div.mandoc a.link-mail { } /* Mailto links (Mt). */
|
||||
div.mandoc a.link-man { } /* Manual links (Xr). */
|
||||
div.mandoc a.link-ref { } /* Reference section links (%Q). */
|
||||
div.mandoc a.link-sec { } /* Section links (Sx). */
|
||||
div.mandoc dl.list-diag { } /* Formatting for lists. See mdoc(7). */
|
||||
div.mandoc dt.list-diag { }
|
||||
div.mandoc dd.list-diag { }
|
||||
div.mandoc dl.list-hang { }
|
||||
div.mandoc dt.list-hang { }
|
||||
div.mandoc dd.list-hang { }
|
||||
div.mandoc dl.list-inset { }
|
||||
div.mandoc dt.list-inset { }
|
||||
div.mandoc dd.list-inset { }
|
||||
div.mandoc dl.list-ohang { }
|
||||
div.mandoc dt.list-ohang { }
|
||||
div.mandoc dd.list-ohang { margin-left: 0ex; }
|
||||
div.mandoc dl.list-tag { }
|
||||
div.mandoc dt.list-tag { }
|
||||
div.mandoc dd.list-tag { }
|
||||
div.mandoc table.list-col { }
|
||||
div.mandoc tr.list-col { }
|
||||
div.mandoc td.list-col { }
|
||||
div.mandoc ul.list-bul { list-style-type: disc; padding-left: 1em; }
|
||||
div.mandoc li.list-bul { }
|
||||
div.mandoc ul.list-dash { list-style-type: none; padding-left: 0em; }
|
||||
div.mandoc li.list-dash:before { content: "\2014 "; }
|
||||
div.mandoc ul.list-hyph { list-style-type: none; padding-left: 0em; }
|
||||
div.mandoc li.list-hyph:before { content: "\2013 "; }
|
||||
div.mandoc ul.list-item { list-style-type: none; padding-left: 0em; }
|
||||
div.mandoc li.list-item { }
|
||||
div.mandoc ol.list-enum { padding-left: 2em; }
|
||||
div.mandoc li.list-enum { }
|
||||
div.mandoc span.eqn { } /* Equation modes. See eqn(7). */
|
||||
div.mandoc table.tbl { } /* Table modes. See tbl(7). */
|
BIN
contrib/mdocml/external.png
Normal file
BIN
contrib/mdocml/external.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 165 B |
699
contrib/mdocml/html.c
Normal file
699
contrib/mdocml/html.c
Normal file
@ -0,0 +1,699 @@
|
||||
/* $Id: html.c,v 1.150 2011/10/05 21:35:17 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "libmandoc.h"
|
||||
#include "out.h"
|
||||
#include "html.h"
|
||||
#include "main.h"
|
||||
|
||||
struct htmldata {
|
||||
const char *name;
|
||||
int flags;
|
||||
#define HTML_CLRLINE (1 << 0)
|
||||
#define HTML_NOSTACK (1 << 1)
|
||||
#define HTML_AUTOCLOSE (1 << 2) /* Tag has auto-closure. */
|
||||
};
|
||||
|
||||
static const struct htmldata htmltags[TAG_MAX] = {
|
||||
{"html", HTML_CLRLINE}, /* TAG_HTML */
|
||||
{"head", HTML_CLRLINE}, /* TAG_HEAD */
|
||||
{"body", HTML_CLRLINE}, /* TAG_BODY */
|
||||
{"meta", HTML_CLRLINE | HTML_NOSTACK | HTML_AUTOCLOSE}, /* TAG_META */
|
||||
{"title", HTML_CLRLINE}, /* TAG_TITLE */
|
||||
{"div", HTML_CLRLINE}, /* TAG_DIV */
|
||||
{"h1", 0}, /* TAG_H1 */
|
||||
{"h2", 0}, /* TAG_H2 */
|
||||
{"span", 0}, /* TAG_SPAN */
|
||||
{"link", HTML_CLRLINE | HTML_NOSTACK | HTML_AUTOCLOSE}, /* TAG_LINK */
|
||||
{"br", HTML_CLRLINE | HTML_NOSTACK | HTML_AUTOCLOSE}, /* TAG_BR */
|
||||
{"a", 0}, /* TAG_A */
|
||||
{"table", HTML_CLRLINE}, /* TAG_TABLE */
|
||||
{"tbody", HTML_CLRLINE}, /* TAG_TBODY */
|
||||
{"col", HTML_CLRLINE | HTML_NOSTACK | HTML_AUTOCLOSE}, /* TAG_COL */
|
||||
{"tr", HTML_CLRLINE}, /* TAG_TR */
|
||||
{"td", HTML_CLRLINE}, /* TAG_TD */
|
||||
{"li", HTML_CLRLINE}, /* TAG_LI */
|
||||
{"ul", HTML_CLRLINE}, /* TAG_UL */
|
||||
{"ol", HTML_CLRLINE}, /* TAG_OL */
|
||||
{"dl", HTML_CLRLINE}, /* TAG_DL */
|
||||
{"dt", HTML_CLRLINE}, /* TAG_DT */
|
||||
{"dd", HTML_CLRLINE}, /* TAG_DD */
|
||||
{"blockquote", HTML_CLRLINE}, /* TAG_BLOCKQUOTE */
|
||||
{"p", HTML_CLRLINE | HTML_NOSTACK | HTML_AUTOCLOSE}, /* TAG_P */
|
||||
{"pre", HTML_CLRLINE }, /* TAG_PRE */
|
||||
{"b", 0 }, /* TAG_B */
|
||||
{"i", 0 }, /* TAG_I */
|
||||
{"code", 0 }, /* TAG_CODE */
|
||||
{"small", 0 }, /* TAG_SMALL */
|
||||
};
|
||||
|
||||
static const char *const htmlattrs[ATTR_MAX] = {
|
||||
"http-equiv", /* ATTR_HTTPEQUIV */
|
||||
"content", /* ATTR_CONTENT */
|
||||
"name", /* ATTR_NAME */
|
||||
"rel", /* ATTR_REL */
|
||||
"href", /* ATTR_HREF */
|
||||
"type", /* ATTR_TYPE */
|
||||
"media", /* ATTR_MEDIA */
|
||||
"class", /* ATTR_CLASS */
|
||||
"style", /* ATTR_STYLE */
|
||||
"width", /* ATTR_WIDTH */
|
||||
"id", /* ATTR_ID */
|
||||
"summary", /* ATTR_SUMMARY */
|
||||
"align", /* ATTR_ALIGN */
|
||||
"colspan", /* ATTR_COLSPAN */
|
||||
};
|
||||
|
||||
static const char *const roffscales[SCALE_MAX] = {
|
||||
"cm", /* SCALE_CM */
|
||||
"in", /* SCALE_IN */
|
||||
"pc", /* SCALE_PC */
|
||||
"pt", /* SCALE_PT */
|
||||
"em", /* SCALE_EM */
|
||||
"em", /* SCALE_MM */
|
||||
"ex", /* SCALE_EN */
|
||||
"ex", /* SCALE_BU */
|
||||
"em", /* SCALE_VS */
|
||||
"ex", /* SCALE_FS */
|
||||
};
|
||||
|
||||
static void bufncat(struct html *, const char *, size_t);
|
||||
static void print_ctag(struct html *, enum htmltag);
|
||||
static int print_encode(struct html *, const char *, int);
|
||||
static void print_metaf(struct html *, enum mandoc_esc);
|
||||
static void print_attr(struct html *, const char *, const char *);
|
||||
static void *ml_alloc(char *, enum htmltype);
|
||||
|
||||
static void *
|
||||
ml_alloc(char *outopts, enum htmltype type)
|
||||
{
|
||||
struct html *h;
|
||||
const char *toks[5];
|
||||
char *v;
|
||||
|
||||
toks[0] = "style";
|
||||
toks[1] = "man";
|
||||
toks[2] = "includes";
|
||||
toks[3] = "fragment";
|
||||
toks[4] = NULL;
|
||||
|
||||
h = mandoc_calloc(1, sizeof(struct html));
|
||||
|
||||
h->type = type;
|
||||
h->tags.head = NULL;
|
||||
h->symtab = mchars_alloc();
|
||||
|
||||
while (outopts && *outopts)
|
||||
switch (getsubopt(&outopts, UNCONST(toks), &v)) {
|
||||
case (0):
|
||||
h->style = v;
|
||||
break;
|
||||
case (1):
|
||||
h->base_man = v;
|
||||
break;
|
||||
case (2):
|
||||
h->base_includes = v;
|
||||
break;
|
||||
case (3):
|
||||
h->oflags |= HTML_FRAGMENT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return(h);
|
||||
}
|
||||
|
||||
void *
|
||||
html_alloc(char *outopts)
|
||||
{
|
||||
|
||||
return(ml_alloc(outopts, HTML_HTML_4_01_STRICT));
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
xhtml_alloc(char *outopts)
|
||||
{
|
||||
|
||||
return(ml_alloc(outopts, HTML_XHTML_1_0_STRICT));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
html_free(void *p)
|
||||
{
|
||||
struct tag *tag;
|
||||
struct html *h;
|
||||
|
||||
h = (struct html *)p;
|
||||
|
||||
while ((tag = h->tags.head) != NULL) {
|
||||
h->tags.head = tag->next;
|
||||
free(tag);
|
||||
}
|
||||
|
||||
if (h->symtab)
|
||||
mchars_free(h->symtab);
|
||||
|
||||
free(h);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
print_gen_head(struct html *h)
|
||||
{
|
||||
struct htmlpair tag[4];
|
||||
|
||||
tag[0].key = ATTR_HTTPEQUIV;
|
||||
tag[0].val = "Content-Type";
|
||||
tag[1].key = ATTR_CONTENT;
|
||||
tag[1].val = "text/html; charset=utf-8";
|
||||
print_otag(h, TAG_META, 2, tag);
|
||||
|
||||
tag[0].key = ATTR_NAME;
|
||||
tag[0].val = "resource-type";
|
||||
tag[1].key = ATTR_CONTENT;
|
||||
tag[1].val = "document";
|
||||
print_otag(h, TAG_META, 2, tag);
|
||||
|
||||
if (h->style) {
|
||||
tag[0].key = ATTR_REL;
|
||||
tag[0].val = "stylesheet";
|
||||
tag[1].key = ATTR_HREF;
|
||||
tag[1].val = h->style;
|
||||
tag[2].key = ATTR_TYPE;
|
||||
tag[2].val = "text/css";
|
||||
tag[3].key = ATTR_MEDIA;
|
||||
tag[3].val = "all";
|
||||
print_otag(h, TAG_LINK, 4, tag);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_metaf(struct html *h, enum mandoc_esc deco)
|
||||
{
|
||||
enum htmlfont font;
|
||||
|
||||
switch (deco) {
|
||||
case (ESCAPE_FONTPREV):
|
||||
font = h->metal;
|
||||
break;
|
||||
case (ESCAPE_FONTITALIC):
|
||||
font = HTMLFONT_ITALIC;
|
||||
break;
|
||||
case (ESCAPE_FONTBOLD):
|
||||
font = HTMLFONT_BOLD;
|
||||
break;
|
||||
case (ESCAPE_FONT):
|
||||
/* FALLTHROUGH */
|
||||
case (ESCAPE_FONTROMAN):
|
||||
font = HTMLFONT_NONE;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
if (h->metaf) {
|
||||
print_tagq(h, h->metaf);
|
||||
h->metaf = NULL;
|
||||
}
|
||||
|
||||
h->metal = h->metac;
|
||||
h->metac = font;
|
||||
|
||||
if (HTMLFONT_NONE != font)
|
||||
h->metaf = HTMLFONT_BOLD == font ?
|
||||
print_otag(h, TAG_B, 0, NULL) :
|
||||
print_otag(h, TAG_I, 0, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
html_strlen(const char *cp)
|
||||
{
|
||||
int ssz, sz;
|
||||
const char *seq, *p;
|
||||
|
||||
/*
|
||||
* Account for escaped sequences within string length
|
||||
* calculations. This follows the logic in term_strlen() as we
|
||||
* must calculate the width of produced strings.
|
||||
* Assume that characters are always width of "1". This is
|
||||
* hacky, but it gets the job done for approximation of widths.
|
||||
*/
|
||||
|
||||
sz = 0;
|
||||
while (NULL != (p = strchr(cp, '\\'))) {
|
||||
sz += (int)(p - cp);
|
||||
++cp;
|
||||
switch (mandoc_escape(&cp, &seq, &ssz)) {
|
||||
case (ESCAPE_ERROR):
|
||||
return(sz);
|
||||
case (ESCAPE_UNICODE):
|
||||
/* FALLTHROUGH */
|
||||
case (ESCAPE_NUMBERED):
|
||||
/* FALLTHROUGH */
|
||||
case (ESCAPE_SPECIAL):
|
||||
sz++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(sz >= 0);
|
||||
return(sz + strlen(cp));
|
||||
}
|
||||
|
||||
static int
|
||||
print_encode(struct html *h, const char *p, int norecurse)
|
||||
{
|
||||
size_t sz;
|
||||
int c, len, nospace;
|
||||
const char *seq;
|
||||
enum mandoc_esc esc;
|
||||
static const char rejs[6] = { '\\', '<', '>', '&', ASCII_HYPH, '\0' };
|
||||
|
||||
nospace = 0;
|
||||
|
||||
while ('\0' != *p) {
|
||||
sz = strcspn(p, rejs);
|
||||
|
||||
fwrite(p, 1, sz, stdout);
|
||||
p += (int)sz;
|
||||
|
||||
if ('\0' == *p)
|
||||
break;
|
||||
|
||||
switch (*p++) {
|
||||
case ('<'):
|
||||
printf("<");
|
||||
continue;
|
||||
case ('>'):
|
||||
printf(">");
|
||||
continue;
|
||||
case ('&'):
|
||||
printf("&");
|
||||
continue;
|
||||
case (ASCII_HYPH):
|
||||
putchar('-');
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
esc = mandoc_escape(&p, &seq, &len);
|
||||
if (ESCAPE_ERROR == esc)
|
||||
break;
|
||||
|
||||
switch (esc) {
|
||||
case (ESCAPE_UNICODE):
|
||||
/* Skip passed "u" header. */
|
||||
c = mchars_num2uc(seq + 1, len - 1);
|
||||
if ('\0' != c)
|
||||
printf("&#x%x;", c);
|
||||
break;
|
||||
case (ESCAPE_NUMBERED):
|
||||
c = mchars_num2char(seq, len);
|
||||
if ('\0' != c)
|
||||
putchar(c);
|
||||
break;
|
||||
case (ESCAPE_SPECIAL):
|
||||
c = mchars_spec2cp(h->symtab, seq, len);
|
||||
if (c > 0)
|
||||
printf("&#%d;", c);
|
||||
else if (-1 == c && 1 == len)
|
||||
putchar((int)*seq);
|
||||
break;
|
||||
case (ESCAPE_FONT):
|
||||
/* FALLTHROUGH */
|
||||
case (ESCAPE_FONTPREV):
|
||||
/* FALLTHROUGH */
|
||||
case (ESCAPE_FONTBOLD):
|
||||
/* FALLTHROUGH */
|
||||
case (ESCAPE_FONTITALIC):
|
||||
/* FALLTHROUGH */
|
||||
case (ESCAPE_FONTROMAN):
|
||||
if (norecurse)
|
||||
break;
|
||||
print_metaf(h, esc);
|
||||
break;
|
||||
case (ESCAPE_NOSPACE):
|
||||
if ('\0' == *p)
|
||||
nospace = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(nospace);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
print_attr(struct html *h, const char *key, const char *val)
|
||||
{
|
||||
printf(" %s=\"", key);
|
||||
(void)print_encode(h, val, 1);
|
||||
putchar('\"');
|
||||
}
|
||||
|
||||
|
||||
struct tag *
|
||||
print_otag(struct html *h, enum htmltag tag,
|
||||
int sz, const struct htmlpair *p)
|
||||
{
|
||||
int i;
|
||||
struct tag *t;
|
||||
|
||||
/* Push this tags onto the stack of open scopes. */
|
||||
|
||||
if ( ! (HTML_NOSTACK & htmltags[tag].flags)) {
|
||||
t = mandoc_malloc(sizeof(struct tag));
|
||||
t->tag = tag;
|
||||
t->next = h->tags.head;
|
||||
h->tags.head = t;
|
||||
} else
|
||||
t = NULL;
|
||||
|
||||
if ( ! (HTML_NOSPACE & h->flags))
|
||||
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(" ");
|
||||
}
|
||||
|
||||
if ( ! (h->flags & HTML_NONOSPACE))
|
||||
h->flags &= ~HTML_NOSPACE;
|
||||
else
|
||||
h->flags |= HTML_NOSPACE;
|
||||
|
||||
/* Print out the tag name and attributes. */
|
||||
|
||||
printf("<%s", htmltags[tag].name);
|
||||
for (i = 0; i < sz; i++)
|
||||
print_attr(h, htmlattrs[p[i].key], p[i].val);
|
||||
|
||||
/* Add non-overridable attributes. */
|
||||
|
||||
if (TAG_HTML == tag && HTML_XHTML_1_0_STRICT == h->type) {
|
||||
print_attr(h, "xmlns", "http://www.w3.org/1999/xhtml");
|
||||
print_attr(h, "xml:lang", "en");
|
||||
print_attr(h, "lang", "en");
|
||||
}
|
||||
|
||||
/* Accommodate for XML "well-formed" singleton escaping. */
|
||||
|
||||
if (HTML_AUTOCLOSE & htmltags[tag].flags)
|
||||
switch (h->type) {
|
||||
case (HTML_XHTML_1_0_STRICT):
|
||||
putchar('/');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
putchar('>');
|
||||
|
||||
h->flags |= HTML_NOSPACE;
|
||||
|
||||
if ((HTML_AUTOCLOSE | HTML_CLRLINE) & htmltags[tag].flags)
|
||||
putchar('\n');
|
||||
|
||||
return(t);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
print_ctag(struct html *h, enum htmltag tag)
|
||||
{
|
||||
|
||||
printf("</%s>", htmltags[tag].name);
|
||||
if (HTML_CLRLINE & htmltags[tag].flags) {
|
||||
h->flags |= HTML_NOSPACE;
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_gen_decls(struct html *h)
|
||||
{
|
||||
const char *doctype;
|
||||
const char *dtd;
|
||||
const char *name;
|
||||
|
||||
switch (h->type) {
|
||||
case (HTML_HTML_4_01_STRICT):
|
||||
name = "HTML";
|
||||
doctype = "-//W3C//DTD HTML 4.01//EN";
|
||||
dtd = "http://www.w3.org/TR/html4/strict.dtd";
|
||||
break;
|
||||
default:
|
||||
puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
name = "html";
|
||||
doctype = "-//W3C//DTD XHTML 1.0 Strict//EN";
|
||||
dtd = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";
|
||||
break;
|
||||
}
|
||||
|
||||
printf("<!DOCTYPE %s PUBLIC \"%s\" \"%s\">\n",
|
||||
name, doctype, dtd);
|
||||
}
|
||||
|
||||
void
|
||||
print_text(struct html *h, const char *word)
|
||||
{
|
||||
|
||||
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(NULL == h->metaf);
|
||||
if (HTMLFONT_NONE != h->metac)
|
||||
h->metaf = HTMLFONT_BOLD == h->metac ?
|
||||
print_otag(h, TAG_B, 0, NULL) :
|
||||
print_otag(h, TAG_I, 0, NULL);
|
||||
|
||||
assert(word);
|
||||
if ( ! print_encode(h, word, 0)) {
|
||||
if ( ! (h->flags & HTML_NONOSPACE))
|
||||
h->flags &= ~HTML_NOSPACE;
|
||||
} else
|
||||
h->flags |= HTML_NOSPACE;
|
||||
|
||||
if (h->metaf) {
|
||||
print_tagq(h, h->metaf);
|
||||
h->metaf = NULL;
|
||||
}
|
||||
|
||||
h->flags &= ~HTML_IGNDELIM;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
print_tagq(struct html *h, const struct tag *until)
|
||||
{
|
||||
struct tag *tag;
|
||||
|
||||
while ((tag = h->tags.head) != NULL) {
|
||||
/*
|
||||
* Remember to close out and nullify the current
|
||||
* meta-font and table, if applicable.
|
||||
*/
|
||||
if (tag == h->metaf)
|
||||
h->metaf = NULL;
|
||||
if (tag == h->tblt)
|
||||
h->tblt = NULL;
|
||||
print_ctag(h, tag->tag);
|
||||
h->tags.head = tag->next;
|
||||
free(tag);
|
||||
if (until && tag == until)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
print_stagq(struct html *h, const struct tag *suntil)
|
||||
{
|
||||
struct tag *tag;
|
||||
|
||||
while ((tag = h->tags.head) != NULL) {
|
||||
if (suntil && tag == suntil)
|
||||
return;
|
||||
/*
|
||||
* Remember to close out and nullify the current
|
||||
* meta-font and table, if applicable.
|
||||
*/
|
||||
if (tag == h->metaf)
|
||||
h->metaf = NULL;
|
||||
if (tag == h->tblt)
|
||||
h->tblt = NULL;
|
||||
print_ctag(h, tag->tag);
|
||||
h->tags.head = tag->next;
|
||||
free(tag);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bufinit(struct html *h)
|
||||
{
|
||||
|
||||
h->buf[0] = '\0';
|
||||
h->buflen = 0;
|
||||
}
|
||||
|
||||
void
|
||||
bufcat_style(struct html *h, const char *key, const char *val)
|
||||
{
|
||||
|
||||
bufcat(h, key);
|
||||
bufcat(h, ":");
|
||||
bufcat(h, val);
|
||||
bufcat(h, ";");
|
||||
}
|
||||
|
||||
void
|
||||
bufcat(struct html *h, const char *p)
|
||||
{
|
||||
|
||||
h->buflen = strlcat(h->buf, p, BUFSIZ);
|
||||
assert(h->buflen < BUFSIZ);
|
||||
}
|
||||
|
||||
void
|
||||
bufcat_fmt(struct html *h, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
(void)vsnprintf(h->buf + (int)h->buflen,
|
||||
BUFSIZ - h->buflen - 1, fmt, ap);
|
||||
va_end(ap);
|
||||
h->buflen = strlen(h->buf);
|
||||
}
|
||||
|
||||
static void
|
||||
bufncat(struct html *h, const char *p, size_t sz)
|
||||
{
|
||||
|
||||
assert(h->buflen + sz + 1 < BUFSIZ);
|
||||
strncat(h->buf, p, sz);
|
||||
h->buflen += sz;
|
||||
}
|
||||
|
||||
void
|
||||
buffmt_includes(struct html *h, const char *name)
|
||||
{
|
||||
const char *p, *pp;
|
||||
|
||||
pp = h->base_includes;
|
||||
|
||||
bufinit(h);
|
||||
while (NULL != (p = strchr(pp, '%'))) {
|
||||
bufncat(h, pp, (size_t)(p - pp));
|
||||
switch (*(p + 1)) {
|
||||
case('I'):
|
||||
bufcat(h, name);
|
||||
break;
|
||||
default:
|
||||
bufncat(h, p, 2);
|
||||
break;
|
||||
}
|
||||
pp = p + 2;
|
||||
}
|
||||
if (pp)
|
||||
bufcat(h, pp);
|
||||
}
|
||||
|
||||
void
|
||||
buffmt_man(struct html *h,
|
||||
const char *name, const char *sec)
|
||||
{
|
||||
const char *p, *pp;
|
||||
|
||||
pp = h->base_man;
|
||||
|
||||
bufinit(h);
|
||||
while (NULL != (p = strchr(pp, '%'))) {
|
||||
bufncat(h, pp, (size_t)(p - pp));
|
||||
switch (*(p + 1)) {
|
||||
case('S'):
|
||||
bufcat(h, sec ? sec : "1");
|
||||
break;
|
||||
case('N'):
|
||||
bufcat_fmt(h, name);
|
||||
break;
|
||||
default:
|
||||
bufncat(h, p, 2);
|
||||
break;
|
||||
}
|
||||
pp = p + 2;
|
||||
}
|
||||
if (pp)
|
||||
bufcat(h, pp);
|
||||
}
|
||||
|
||||
void
|
||||
bufcat_su(struct html *h, const char *p, const struct roffsu *su)
|
||||
{
|
||||
double v;
|
||||
|
||||
v = su->scale;
|
||||
if (SCALE_MM == su->unit && 0.0 == (v /= 100.0))
|
||||
v = 1.0;
|
||||
|
||||
bufcat_fmt(h, "%s: %.2f%s;", p, v, roffscales[su->unit]);
|
||||
}
|
||||
|
||||
void
|
||||
bufcat_id(struct html *h, const char *src)
|
||||
{
|
||||
|
||||
/* Cf. <http://www.w3.org/TR/html4/types.html#h-6.2>. */
|
||||
|
||||
while ('\0' != *src)
|
||||
bufcat_fmt(h, "%.2x", *src++);
|
||||
}
|
164
contrib/mdocml/html.h
Normal file
164
contrib/mdocml/html.h
Normal file
@ -0,0 +1,164 @@
|
||||
/* $Id: html.h,v 1.47 2011/10/05 21:35:17 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 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 HTML_H
|
||||
#define HTML_H
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
enum htmltag {
|
||||
TAG_HTML,
|
||||
TAG_HEAD,
|
||||
TAG_BODY,
|
||||
TAG_META,
|
||||
TAG_TITLE,
|
||||
TAG_DIV,
|
||||
TAG_H1,
|
||||
TAG_H2,
|
||||
TAG_SPAN,
|
||||
TAG_LINK,
|
||||
TAG_BR,
|
||||
TAG_A,
|
||||
TAG_TABLE,
|
||||
TAG_TBODY,
|
||||
TAG_COL,
|
||||
TAG_TR,
|
||||
TAG_TD,
|
||||
TAG_LI,
|
||||
TAG_UL,
|
||||
TAG_OL,
|
||||
TAG_DL,
|
||||
TAG_DT,
|
||||
TAG_DD,
|
||||
TAG_BLOCKQUOTE,
|
||||
TAG_P,
|
||||
TAG_PRE,
|
||||
TAG_B,
|
||||
TAG_I,
|
||||
TAG_CODE,
|
||||
TAG_SMALL,
|
||||
TAG_MAX
|
||||
};
|
||||
|
||||
enum htmlattr {
|
||||
ATTR_HTTPEQUIV,
|
||||
ATTR_CONTENT,
|
||||
ATTR_NAME,
|
||||
ATTR_REL,
|
||||
ATTR_HREF,
|
||||
ATTR_TYPE,
|
||||
ATTR_MEDIA,
|
||||
ATTR_CLASS,
|
||||
ATTR_STYLE,
|
||||
ATTR_WIDTH,
|
||||
ATTR_ID,
|
||||
ATTR_SUMMARY,
|
||||
ATTR_ALIGN,
|
||||
ATTR_COLSPAN,
|
||||
ATTR_MAX
|
||||
};
|
||||
|
||||
enum htmlfont {
|
||||
HTMLFONT_NONE = 0,
|
||||
HTMLFONT_BOLD,
|
||||
HTMLFONT_ITALIC,
|
||||
HTMLFONT_MAX
|
||||
};
|
||||
|
||||
struct tag {
|
||||
struct tag *next;
|
||||
enum htmltag tag;
|
||||
};
|
||||
|
||||
struct tagq {
|
||||
struct tag *head;
|
||||
};
|
||||
|
||||
struct htmlpair {
|
||||
enum htmlattr key;
|
||||
const char *val;
|
||||
};
|
||||
|
||||
#define PAIR_INIT(p, t, v) \
|
||||
do { \
|
||||
(p)->key = (t); \
|
||||
(p)->val = (v); \
|
||||
} while (/* CONSTCOND */ 0)
|
||||
|
||||
#define PAIR_ID_INIT(p, v) PAIR_INIT(p, ATTR_ID, v)
|
||||
#define PAIR_CLASS_INIT(p, v) PAIR_INIT(p, ATTR_CLASS, v)
|
||||
#define PAIR_HREF_INIT(p, v) PAIR_INIT(p, ATTR_HREF, v)
|
||||
#define PAIR_STYLE_INIT(p, h) PAIR_INIT(p, ATTR_STYLE, (h)->buf)
|
||||
#define PAIR_SUMMARY_INIT(p, v) PAIR_INIT(p, ATTR_SUMMARY, v)
|
||||
|
||||
enum htmltype {
|
||||
HTML_HTML_4_01_STRICT,
|
||||
HTML_XHTML_1_0_STRICT
|
||||
};
|
||||
|
||||
struct html {
|
||||
int flags;
|
||||
#define HTML_NOSPACE (1 << 0) /* suppress next space */
|
||||
#define HTML_IGNDELIM (1 << 1)
|
||||
#define HTML_KEEP (1 << 2)
|
||||
#define HTML_PREKEEP (1 << 3)
|
||||
#define HTML_NONOSPACE (1 << 4) /* never add spaces */
|
||||
#define HTML_LITERAL (1 << 5) /* literal (e.g., <PRE>) context */
|
||||
struct tagq tags; /* stack of open tags */
|
||||
struct rofftbl tbl; /* current table */
|
||||
struct tag *tblt; /* current open table scope */
|
||||
struct mchars *symtab; /* character-escapes */
|
||||
char *base_man; /* base for manpage href */
|
||||
char *base_includes; /* base for include href */
|
||||
char *style; /* style-sheet URI */
|
||||
char buf[BUFSIZ]; /* see bufcat and friends */
|
||||
size_t buflen;
|
||||
struct tag *metaf; /* current open font scope */
|
||||
enum htmlfont metal; /* last used font */
|
||||
enum htmlfont metac; /* current font mode */
|
||||
enum htmltype type; /* output media type */
|
||||
int oflags; /* output options */
|
||||
#define HTML_FRAGMENT (1 << 0) /* don't emit HTML/HEAD/BODY */
|
||||
};
|
||||
|
||||
void print_gen_decls(struct html *);
|
||||
void print_gen_head(struct html *);
|
||||
struct tag *print_otag(struct html *, enum htmltag,
|
||||
int, const struct htmlpair *);
|
||||
void print_tagq(struct html *, const struct tag *);
|
||||
void print_stagq(struct html *, const struct tag *);
|
||||
void print_text(struct html *, const char *);
|
||||
void print_tblclose(struct html *);
|
||||
void print_tbl(struct html *, const struct tbl_span *);
|
||||
void print_eqn(struct html *, const struct eqn *);
|
||||
|
||||
void bufcat_fmt(struct html *, const char *, ...);
|
||||
void bufcat(struct html *, const char *);
|
||||
void bufcat_id(struct html *, const char *);
|
||||
void bufcat_style(struct html *,
|
||||
const char *, const char *);
|
||||
void bufcat_su(struct html *, const char *,
|
||||
const struct roffsu *);
|
||||
void bufinit(struct html *);
|
||||
void buffmt_man(struct html *,
|
||||
const char *, const char *);
|
||||
void buffmt_includes(struct html *, const char *);
|
||||
|
||||
int html_strlen(const char *);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /*!HTML_H*/
|
39
contrib/mdocml/lib.c
Normal file
39
contrib/mdocml/lib.c
Normal file
@ -0,0 +1,39 @@
|
||||
/* $Id: lib.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "mdoc.h"
|
||||
#include "mandoc.h"
|
||||
#include "libmdoc.h"
|
||||
|
||||
#define LINE(x, y) \
|
||||
if (0 == strcmp(p, x)) return(y);
|
||||
|
||||
const char *
|
||||
mdoc_a2lib(const char *p)
|
||||
{
|
||||
|
||||
#include "lib.in"
|
||||
|
||||
return(NULL);
|
||||
}
|
99
contrib/mdocml/lib.in
Normal file
99
contrib/mdocml/lib.in
Normal file
@ -0,0 +1,99 @@
|
||||
/* $Id: lib.in,v 1.13 2012/01/28 23:46:28 joerg Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* These are all possible .Lb strings. When a new library is added, add
|
||||
* its short-string to the left-hand side and formatted string to the
|
||||
* right-hand side.
|
||||
*
|
||||
* Be sure to escape strings.
|
||||
*/
|
||||
|
||||
LINE("libarchive", "Reading and Writing Streaming Archives Library (libarchive, \\-larchive)")
|
||||
LINE("libarm", "ARM Architecture Library (libarm, \\-larm)")
|
||||
LINE("libarm32", "ARM32 Architecture Library (libarm32, \\-larm32)")
|
||||
LINE("libbluetooth", "Bluetooth Library (libbluetooth, \\-lbluetooth)")
|
||||
LINE("libbsm", "Basic Security Module User Library (libbsm, \\-lbsm)")
|
||||
LINE("libc", "Standard C Library (libc, \\-lc)")
|
||||
LINE("libc_r", "Reentrant C\\~Library (libc_r, \\-lc_r)")
|
||||
LINE("libcalendar", "Calendar Arithmetic Library (libcalendar, \\-lcalendar)")
|
||||
LINE("libcam", "Common Access Method User Library (libcam, \\-lcam)")
|
||||
LINE("libcdk", "Curses Development Kit Library (libcdk, \\-lcdk)")
|
||||
LINE("libcipher", "FreeSec Crypt Library (libcipher, \\-lcipher)")
|
||||
LINE("libcompat", "Compatibility Library (libcompat, \\-lcompat)")
|
||||
LINE("libcrypt", "Crypt Library (libcrypt, \\-lcrypt)")
|
||||
LINE("libcurses", "Curses Library (libcurses, \\-lcurses)")
|
||||
LINE("libdevinfo", "Device and Resource Information Utility Library (libdevinfo, \\-ldevinfo)")
|
||||
LINE("libdevstat", "Device Statistics Library (libdevstat, \\-ldevstat)")
|
||||
LINE("libdisk", "Interface to Slice and Partition Labels Library (libdisk, \\-ldisk)")
|
||||
LINE("libdwarf", "DWARF Access Library (libdwarf, \\-ldwarf)")
|
||||
LINE("libedit", "Command Line Editor Library (libedit, \\-ledit)")
|
||||
LINE("libelf", "ELF Access Library (libelf, \\-lelf)")
|
||||
LINE("libevent", "Event Notification Library (libevent, \\-levent)")
|
||||
LINE("libfetch", "File Transfer Library for URLs (libfetch, \\-lfetch)")
|
||||
LINE("libform", "Curses Form Library (libform, \\-lform)")
|
||||
LINE("libgeom", "Userland API Library for kernel GEOM subsystem (libgeom, \\-lgeom)")
|
||||
LINE("libgpib", "General-Purpose Instrument Bus (GPIB) library (libgpib, \\-lgpib)")
|
||||
LINE("libi386", "i386 Architecture Library (libi386, \\-li386)")
|
||||
LINE("libintl", "Internationalized Message Handling Library (libintl, \\-lintl)")
|
||||
LINE("libipsec", "IPsec Policy Control Library (libipsec, \\-lipsec)")
|
||||
LINE("libipx", "IPX Address Conversion Support Library (libipx, \\-lipx)")
|
||||
LINE("libiscsi", "iSCSI protocol library (libiscsi, \\-liscsi)")
|
||||
LINE("libisns", "Internet Storage Name Service Library (libisns, \\-lisns)")
|
||||
LINE("libjail", "Jail Library (libjail, \\-ljail)")
|
||||
LINE("libkiconv", "Kernel side iconv library (libkiconv, \\-lkiconv)")
|
||||
LINE("libkse", "N:M Threading Library (libkse, \\-lkse)")
|
||||
LINE("libkvm", "Kernel Data Access Library (libkvm, \\-lkvm)")
|
||||
LINE("libm", "Math Library (libm, \\-lm)")
|
||||
LINE("libm68k", "m68k Architecture Library (libm68k, \\-lm68k)")
|
||||
LINE("libmagic", "Magic Number Recognition Library (libmagic, \\-lmagic)")
|
||||
LINE("libmd", "Message Digest (MD4, MD5, etc.) Support Library (libmd, \\-lmd)")
|
||||
LINE("libmemstat", "Kernel Memory Allocator Statistics Library (libmemstat, \\-lmemstat)")
|
||||
LINE("libmenu", "Curses Menu Library (libmenu, \\-lmenu)")
|
||||
LINE("libnetgraph", "Netgraph User Library (libnetgraph, \\-lnetgraph)")
|
||||
LINE("libnetpgp", "Netpgp signing, verification, encryption and decryption (libnetpgp, \\-lnetpgp)")
|
||||
LINE("libossaudio", "OSS Audio Emulation Library (libossaudio, \\-lossaudio)")
|
||||
LINE("libpam", "Pluggable Authentication Module Library (libpam, \\-lpam)")
|
||||
LINE("libpcap", "Capture Library (libpcap, \\-lpcap)")
|
||||
LINE("libpci", "PCI Bus Access Library (libpci, \\-lpci)")
|
||||
LINE("libpmc", "Performance Counters Library (libpmc, \\-lpmc)")
|
||||
LINE("libposix", "POSIX Compatibility Library (libposix, \\-lposix)")
|
||||
LINE("libppath", "Property-List Paths Library (libppath, \\-lppath)")
|
||||
LINE("libprop", "Property Container Object Library (libprop, \\-lprop)")
|
||||
LINE("libpthread", "POSIX Threads Library (libpthread, \\-lpthread)")
|
||||
LINE("libpuffs", "puffs Convenience Library (libpuffs, \\-lpuffs)")
|
||||
LINE("libquota", "Disk Quota Access and Control Library (libquota, \\-lquota)")
|
||||
LINE("librefuse", "File System in Userspace Convenience Library (librefuse, \\-lrefuse)")
|
||||
LINE("libresolv", "DNS Resolver Library (libresolv, \\-lresolv)")
|
||||
LINE("librpcsec_gss", "RPC GSS-API Authentication Library (librpcsec_gss, \\-lrpcsec_gss)")
|
||||
LINE("librpcsvc", "RPC Service Library (librpcsvc, \\-lrpcsvc)")
|
||||
LINE("librt", "POSIX Real\\-time Library (librt, \\-lrt)")
|
||||
LINE("libsaslc", "Simple Authentication and Security Layer client library (libsaslc, \\-lsaslc)")
|
||||
LINE("libsdp", "Bluetooth Service Discovery Protocol User Library (libsdp, \\-lsdp)")
|
||||
LINE("libssp", "Buffer Overflow Protection Library (libssp, \\-lssp)")
|
||||
LINE("libSystem", "System Library (libSystem, \\-lSystem)")
|
||||
LINE("libtermcap", "Termcap Access Library (libtermcap, \\-ltermcap)")
|
||||
LINE("libterminfo", "Terminal Information Library (libterminfo, \\-lterminfo)")
|
||||
LINE("libthr", "1:1 Threading Library (libthr, \\-lthr)")
|
||||
LINE("libufs", "UFS File System Access Library (libufs, \\-lufs)")
|
||||
LINE("libugidfw", "File System Firewall Interface Library (libugidfw, \\-lugidfw)")
|
||||
LINE("libulog", "User Login Record Library (libulog, \\-lulog)")
|
||||
LINE("libusbhid", "USB Human Interface Devices Library (libusbhid, \\-lusbhid)")
|
||||
LINE("libutil", "System Utilities Library (libutil, \\-lutil)")
|
||||
LINE("libvgl", "Video Graphics Library (libvgl, \\-lvgl)")
|
||||
LINE("libx86_64", "x86_64 Architecture Library (libx86_64, \\-lx86_64)")
|
||||
LINE("libz", "Compression Library (libz, \\-lz)")
|
85
contrib/mdocml/libman.h
Normal file
85
contrib/mdocml/libman.h
Normal file
@ -0,0 +1,85 @@
|
||||
/* $Id: libman.h,v 1.55 2011/11/07 01:24:40 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 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 LIBMAN_H
|
||||
#define LIBMAN_H
|
||||
|
||||
enum man_next {
|
||||
MAN_NEXT_SIBLING = 0,
|
||||
MAN_NEXT_CHILD
|
||||
};
|
||||
|
||||
struct man {
|
||||
struct mparse *parse; /* parse pointer */
|
||||
int flags; /* parse flags */
|
||||
#define MAN_HALT (1 << 0) /* badness happened: die */
|
||||
#define MAN_ELINE (1 << 1) /* Next-line element scope. */
|
||||
#define MAN_BLINE (1 << 2) /* Next-line block scope. */
|
||||
#define MAN_ILINE (1 << 3) /* Ignored in next-line scope. */
|
||||
#define MAN_LITERAL (1 << 4) /* Literal input. */
|
||||
#define MAN_BPLINE (1 << 5)
|
||||
#define MAN_NEWLINE (1 << 6) /* first macro/text in a line */
|
||||
enum man_next next; /* where to put the next node */
|
||||
struct man_node *last; /* the last parsed node */
|
||||
struct man_node *first; /* the first parsed node */
|
||||
struct man_meta meta; /* document meta-data */
|
||||
struct roff *roff;
|
||||
};
|
||||
|
||||
#define MACRO_PROT_ARGS struct man *m, \
|
||||
enum mant tok, \
|
||||
int line, \
|
||||
int ppos, \
|
||||
int *pos, \
|
||||
char *buf
|
||||
|
||||
struct man_macro {
|
||||
int (*fp)(MACRO_PROT_ARGS);
|
||||
int flags;
|
||||
#define MAN_SCOPED (1 << 0)
|
||||
#define MAN_EXPLICIT (1 << 1) /* See blk_imp(). */
|
||||
#define MAN_FSCOPED (1 << 2) /* See blk_imp(). */
|
||||
#define MAN_NSCOPED (1 << 3) /* See in_line_eoln(). */
|
||||
#define MAN_NOCLOSE (1 << 4) /* See blk_exp(). */
|
||||
#define MAN_BSCOPE (1 << 5) /* Break BLINE scope. */
|
||||
};
|
||||
|
||||
extern const struct man_macro *const man_macros;
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define man_pmsg(m, l, p, t) \
|
||||
mandoc_msg((t), (m)->parse, (l), (p), NULL)
|
||||
#define man_nmsg(m, n, t) \
|
||||
mandoc_msg((t), (m)->parse, (n)->line, (n)->pos, NULL)
|
||||
int man_word_alloc(struct man *, int, int, const char *);
|
||||
int man_block_alloc(struct man *, int, int, enum mant);
|
||||
int man_head_alloc(struct man *, int, int, enum mant);
|
||||
int man_tail_alloc(struct man *, int, int, enum mant);
|
||||
int man_body_alloc(struct man *, int, int, enum mant);
|
||||
int man_elem_alloc(struct man *, int, int, enum mant);
|
||||
void man_node_delete(struct man *, struct man_node *);
|
||||
void man_hash_init(void);
|
||||
enum mant man_hash_find(const char *);
|
||||
int man_macroend(struct man *);
|
||||
int man_valid_post(struct man *);
|
||||
int man_valid_pre(struct man *, struct man_node *);
|
||||
int man_unscope(struct man *,
|
||||
const struct man_node *, enum mandocerr);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /*!LIBMAN_H*/
|
92
contrib/mdocml/libmandoc.h
Normal file
92
contrib/mdocml/libmandoc.h
Normal file
@ -0,0 +1,92 @@
|
||||
/* $Id: libmandoc.h,v 1.29 2011/12/02 01:37:14 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 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 LIBMANDOC_H
|
||||
#define LIBMANDOC_H
|
||||
|
||||
enum rofferr {
|
||||
ROFF_CONT, /* continue processing line */
|
||||
ROFF_RERUN, /* re-run roff interpreter with offset */
|
||||
ROFF_APPEND, /* re-run main parser, appending next line */
|
||||
ROFF_REPARSE, /* re-run main parser on the result */
|
||||
ROFF_SO, /* include another file */
|
||||
ROFF_IGN, /* ignore current line */
|
||||
ROFF_TBL, /* a table row was successfully parsed */
|
||||
ROFF_EQN, /* an equation was successfully parsed */
|
||||
ROFF_ERR /* badness: puke and stop */
|
||||
};
|
||||
|
||||
enum regs {
|
||||
REG_nS = 0, /* nS register */
|
||||
REG__MAX
|
||||
};
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
struct roff;
|
||||
struct mdoc;
|
||||
struct man;
|
||||
|
||||
void mandoc_msg(enum mandocerr, struct mparse *,
|
||||
int, int, const char *);
|
||||
void mandoc_vmsg(enum mandocerr, struct mparse *,
|
||||
int, int, const char *, ...);
|
||||
char *mandoc_getarg(struct mparse *, char **, int, int *);
|
||||
char *mandoc_normdate(struct mparse *, char *, int, int);
|
||||
int mandoc_eos(const char *, size_t, int);
|
||||
int mandoc_getcontrol(const char *, int *);
|
||||
int mandoc_strntoi(const char *, size_t, int);
|
||||
const char *mandoc_a2msec(const char*);
|
||||
|
||||
void mdoc_free(struct mdoc *);
|
||||
struct mdoc *mdoc_alloc(struct roff *, struct mparse *);
|
||||
void mdoc_reset(struct mdoc *);
|
||||
int mdoc_parseln(struct mdoc *, int, char *, int);
|
||||
int mdoc_endparse(struct mdoc *);
|
||||
int mdoc_addspan(struct mdoc *, const struct tbl_span *);
|
||||
int mdoc_addeqn(struct mdoc *, const struct eqn *);
|
||||
|
||||
void man_free(struct man *);
|
||||
struct man *man_alloc(struct roff *, struct mparse *);
|
||||
void man_reset(struct man *);
|
||||
int man_parseln(struct man *, int, char *, int);
|
||||
int man_endparse(struct man *);
|
||||
int man_addspan(struct man *, const struct tbl_span *);
|
||||
int man_addeqn(struct man *, const struct eqn *);
|
||||
|
||||
void roff_free(struct roff *);
|
||||
struct roff *roff_alloc(struct mparse *);
|
||||
void roff_reset(struct roff *);
|
||||
enum rofferr roff_parseln(struct roff *, int,
|
||||
char **, size_t *, int, int *);
|
||||
void roff_endparse(struct roff *);
|
||||
int roff_regisset(const struct roff *, enum regs);
|
||||
unsigned int roff_regget(const struct roff *, enum regs);
|
||||
void roff_regunset(struct roff *, enum regs);
|
||||
char *roff_strdup(const struct roff *, const char *);
|
||||
#if 0
|
||||
char roff_eqndelim(const struct roff *);
|
||||
void roff_openeqn(struct roff *, const char *,
|
||||
int, int, const char *);
|
||||
int roff_closeeqn(struct roff *);
|
||||
#endif
|
||||
|
||||
const struct tbl_span *roff_span(const struct roff *);
|
||||
const struct eqn *roff_eqn(const struct roff *);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /*!LIBMANDOC_H*/
|
141
contrib/mdocml/libmdoc.h
Normal file
141
contrib/mdocml/libmdoc.h
Normal file
@ -0,0 +1,141 @@
|
||||
/* $Id: libmdoc.h,v 1.78 2011/12/02 01:37:14 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 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 LIBMDOC_H
|
||||
#define LIBMDOC_H
|
||||
|
||||
enum mdoc_next {
|
||||
MDOC_NEXT_SIBLING = 0,
|
||||
MDOC_NEXT_CHILD
|
||||
};
|
||||
|
||||
struct mdoc {
|
||||
struct mparse *parse; /* parse pointer */
|
||||
int flags; /* parse flags */
|
||||
#define MDOC_HALT (1 << 0) /* error in parse: halt */
|
||||
#define MDOC_LITERAL (1 << 1) /* in a literal scope */
|
||||
#define MDOC_PBODY (1 << 2) /* in the document body */
|
||||
#define MDOC_NEWLINE (1 << 3) /* first macro/text in a line */
|
||||
#define MDOC_PHRASELIT (1 << 4) /* literal within a partila phrase */
|
||||
#define MDOC_PPHRASE (1 << 5) /* within a partial phrase */
|
||||
#define MDOC_FREECOL (1 << 6) /* `It' invocation should close */
|
||||
#define MDOC_SYNOPSIS (1 << 7) /* SYNOPSIS-style formatting */
|
||||
enum mdoc_next next; /* where to put the next node */
|
||||
struct mdoc_node *last; /* the last node parsed */
|
||||
struct mdoc_node *first; /* the first node parsed */
|
||||
struct mdoc_meta meta; /* document meta-data */
|
||||
enum mdoc_sec lastnamed;
|
||||
enum mdoc_sec lastsec;
|
||||
struct roff *roff;
|
||||
};
|
||||
|
||||
#define MACRO_PROT_ARGS struct mdoc *m, \
|
||||
enum mdoct tok, \
|
||||
int line, \
|
||||
int ppos, \
|
||||
int *pos, \
|
||||
char *buf
|
||||
|
||||
struct mdoc_macro {
|
||||
int (*fp)(MACRO_PROT_ARGS);
|
||||
int flags;
|
||||
#define MDOC_CALLABLE (1 << 0)
|
||||
#define MDOC_PARSED (1 << 1)
|
||||
#define MDOC_EXPLICIT (1 << 2)
|
||||
#define MDOC_PROLOGUE (1 << 3)
|
||||
#define MDOC_IGNDELIM (1 << 4)
|
||||
/* Reserved words in arguments treated as text. */
|
||||
};
|
||||
|
||||
enum margserr {
|
||||
ARGS_ERROR,
|
||||
ARGS_EOLN, /* end-of-line */
|
||||
ARGS_WORD, /* normal word */
|
||||
ARGS_PUNCT, /* series of punctuation */
|
||||
ARGS_QWORD, /* quoted word */
|
||||
ARGS_PHRASE, /* Ta'd phrase (-column) */
|
||||
ARGS_PPHRASE, /* tabbed phrase (-column) */
|
||||
ARGS_PEND /* last phrase (-column) */
|
||||
};
|
||||
|
||||
enum margverr {
|
||||
ARGV_ERROR,
|
||||
ARGV_EOLN, /* end of line */
|
||||
ARGV_ARG, /* valid argument */
|
||||
ARGV_WORD /* normal word (or bad argument---same thing) */
|
||||
};
|
||||
|
||||
/*
|
||||
* A punctuation delimiter is opening, closing, or "middle mark"
|
||||
* punctuation. These govern spacing.
|
||||
* Opening punctuation (e.g., the opening parenthesis) suppresses the
|
||||
* following space; closing punctuation (e.g., the closing parenthesis)
|
||||
* suppresses the leading space; middle punctuation (e.g., the vertical
|
||||
* bar) can do either. The middle punctuation delimiter bends the rules
|
||||
* depending on usage.
|
||||
*/
|
||||
enum mdelim {
|
||||
DELIM_NONE = 0,
|
||||
DELIM_OPEN,
|
||||
DELIM_MIDDLE,
|
||||
DELIM_CLOSE,
|
||||
DELIM_MAX
|
||||
};
|
||||
|
||||
extern const struct mdoc_macro *const mdoc_macros;
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define mdoc_pmsg(m, l, p, t) \
|
||||
mandoc_msg((t), (m)->parse, (l), (p), NULL)
|
||||
#define mdoc_nmsg(m, n, t) \
|
||||
mandoc_msg((t), (m)->parse, (n)->line, (n)->pos, NULL)
|
||||
int mdoc_macro(MACRO_PROT_ARGS);
|
||||
int mdoc_word_alloc(struct mdoc *,
|
||||
int, int, const char *);
|
||||
int mdoc_elem_alloc(struct mdoc *, int, int,
|
||||
enum mdoct, struct mdoc_arg *);
|
||||
int mdoc_block_alloc(struct mdoc *, int, int,
|
||||
enum mdoct, struct mdoc_arg *);
|
||||
int mdoc_head_alloc(struct mdoc *, int, int, enum mdoct);
|
||||
int mdoc_tail_alloc(struct mdoc *, int, int, enum mdoct);
|
||||
int mdoc_body_alloc(struct mdoc *, int, int, enum mdoct);
|
||||
int mdoc_endbody_alloc(struct mdoc *m, int line, int pos,
|
||||
enum mdoct tok, struct mdoc_node *body,
|
||||
enum mdoc_endbody end);
|
||||
void mdoc_node_delete(struct mdoc *, struct mdoc_node *);
|
||||
void mdoc_hash_init(void);
|
||||
enum mdoct mdoc_hash_find(const char *);
|
||||
const char *mdoc_a2att(const char *);
|
||||
const char *mdoc_a2lib(const char *);
|
||||
const char *mdoc_a2st(const char *);
|
||||
const char *mdoc_a2arch(const char *);
|
||||
const char *mdoc_a2vol(const char *);
|
||||
int mdoc_valid_pre(struct mdoc *, struct mdoc_node *);
|
||||
int mdoc_valid_post(struct mdoc *);
|
||||
enum margverr mdoc_argv(struct mdoc *, int, enum mdoct,
|
||||
struct mdoc_arg **, int *, char *);
|
||||
void mdoc_argv_free(struct mdoc_arg *);
|
||||
enum margserr mdoc_args(struct mdoc *, int,
|
||||
int *, char *, enum mdoct, char **);
|
||||
enum margserr mdoc_zargs(struct mdoc *, int,
|
||||
int *, char *, char **);
|
||||
int mdoc_macroend(struct mdoc *);
|
||||
enum mdelim mdoc_isdelim(const char *);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /*!LIBMDOC_H*/
|
84
contrib/mdocml/libroff.h
Normal file
84
contrib/mdocml/libroff.h
Normal file
@ -0,0 +1,84 @@
|
||||
/* $Id: libroff.h,v 1.27 2011/07/25 15:37:00 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 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 LIBROFF_H
|
||||
#define LIBROFF_H
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
enum tbl_part {
|
||||
TBL_PART_OPTS, /* in options (first line) */
|
||||
TBL_PART_LAYOUT, /* describing layout */
|
||||
TBL_PART_DATA, /* creating data rows */
|
||||
TBL_PART_CDATA /* continue previous row */
|
||||
};
|
||||
|
||||
struct tbl_node {
|
||||
struct mparse *parse; /* parse point */
|
||||
int pos; /* invocation column */
|
||||
int line; /* invocation line */
|
||||
enum tbl_part part;
|
||||
struct tbl opts;
|
||||
struct tbl_row *first_row;
|
||||
struct tbl_row *last_row;
|
||||
struct tbl_span *first_span;
|
||||
struct tbl_span *current_span;
|
||||
struct tbl_span *last_span;
|
||||
struct tbl_head *first_head;
|
||||
struct tbl_head *last_head;
|
||||
struct tbl_node *next;
|
||||
};
|
||||
|
||||
struct eqn_node {
|
||||
struct eqn_def *defs;
|
||||
size_t defsz;
|
||||
char *data;
|
||||
size_t rew;
|
||||
size_t cur;
|
||||
size_t sz;
|
||||
int gsize;
|
||||
struct eqn eqn;
|
||||
struct mparse *parse;
|
||||
struct eqn_node *next;
|
||||
};
|
||||
|
||||
struct eqn_def {
|
||||
char *key;
|
||||
size_t keysz;
|
||||
char *val;
|
||||
size_t valsz;
|
||||
};
|
||||
|
||||
struct tbl_node *tbl_alloc(int, int, struct mparse *);
|
||||
void tbl_restart(int, int, struct tbl_node *);
|
||||
void tbl_free(struct tbl_node *);
|
||||
void tbl_reset(struct tbl_node *);
|
||||
enum rofferr tbl_read(struct tbl_node *, int, const char *, int);
|
||||
int tbl_option(struct tbl_node *, int, const char *);
|
||||
int tbl_layout(struct tbl_node *, int, const char *);
|
||||
int tbl_data(struct tbl_node *, int, const char *);
|
||||
int tbl_cdata(struct tbl_node *, int, const char *);
|
||||
const struct tbl_span *tbl_span(struct tbl_node *);
|
||||
void tbl_end(struct tbl_node **);
|
||||
struct eqn_node *eqn_alloc(const char *, int, int, struct mparse *);
|
||||
enum rofferr eqn_end(struct eqn_node **);
|
||||
void eqn_free(struct eqn_node *);
|
||||
enum rofferr eqn_read(struct eqn_node **, int,
|
||||
const char *, int, int *);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /*LIBROFF_H*/
|
401
contrib/mdocml/main.c
Normal file
401
contrib/mdocml/main.c
Normal file
@ -0,0 +1,401 @@
|
||||
/* $Id: main.c,v 1.165 2011/10/06 22:29:12 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2010, 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "main.h"
|
||||
#include "mdoc.h"
|
||||
#include "man.h"
|
||||
|
||||
#if !defined(__GNUC__) || (__GNUC__ < 2)
|
||||
# if !defined(lint)
|
||||
# define __attribute__(x)
|
||||
# endif
|
||||
#endif /* !defined(__GNUC__) || (__GNUC__ < 2) */
|
||||
|
||||
typedef void (*out_mdoc)(void *, const struct mdoc *);
|
||||
typedef void (*out_man)(void *, const struct man *);
|
||||
typedef void (*out_free)(void *);
|
||||
|
||||
enum outt {
|
||||
OUTT_ASCII = 0, /* -Tascii */
|
||||
OUTT_LOCALE, /* -Tlocale */
|
||||
OUTT_UTF8, /* -Tutf8 */
|
||||
OUTT_TREE, /* -Ttree */
|
||||
OUTT_MAN, /* -Tman */
|
||||
OUTT_HTML, /* -Thtml */
|
||||
OUTT_XHTML, /* -Txhtml */
|
||||
OUTT_LINT, /* -Tlint */
|
||||
OUTT_PS, /* -Tps */
|
||||
OUTT_PDF /* -Tpdf */
|
||||
};
|
||||
|
||||
struct curparse {
|
||||
struct mparse *mp;
|
||||
enum mandoclevel wlevel; /* ignore messages below this */
|
||||
int wstop; /* stop after a file with a warning */
|
||||
enum outt outtype; /* which output to use */
|
||||
out_mdoc outmdoc; /* mdoc output ptr */
|
||||
out_man outman; /* man output ptr */
|
||||
out_free outfree; /* free output ptr */
|
||||
void *outdata; /* data for output */
|
||||
char outopts[BUFSIZ]; /* buf of output opts */
|
||||
};
|
||||
|
||||
static int moptions(enum mparset *, char *);
|
||||
static void mmsg(enum mandocerr, enum mandoclevel,
|
||||
const char *, int, int, const char *);
|
||||
static void parse(struct curparse *, int,
|
||||
const char *, enum mandoclevel *);
|
||||
static int toptions(struct curparse *, char *);
|
||||
static void usage(void) __attribute__((noreturn));
|
||||
static void version(void) __attribute__((noreturn));
|
||||
static int woptions(struct curparse *, char *);
|
||||
|
||||
static const char *progname;
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
struct curparse curp;
|
||||
enum mparset type;
|
||||
enum mandoclevel rc;
|
||||
|
||||
progname = strrchr(argv[0], '/');
|
||||
if (progname == NULL)
|
||||
progname = argv[0];
|
||||
else
|
||||
++progname;
|
||||
|
||||
memset(&curp, 0, sizeof(struct curparse));
|
||||
|
||||
type = MPARSE_AUTO;
|
||||
curp.outtype = OUTT_ASCII;
|
||||
curp.wlevel = MANDOCLEVEL_FATAL;
|
||||
|
||||
/* LINTED */
|
||||
while (-1 != (c = getopt(argc, argv, "m:O:T:VW:")))
|
||||
switch (c) {
|
||||
case ('m'):
|
||||
if ( ! moptions(&type, optarg))
|
||||
return((int)MANDOCLEVEL_BADARG);
|
||||
break;
|
||||
case ('O'):
|
||||
(void)strlcat(curp.outopts, optarg, BUFSIZ);
|
||||
(void)strlcat(curp.outopts, ",", BUFSIZ);
|
||||
break;
|
||||
case ('T'):
|
||||
if ( ! toptions(&curp, optarg))
|
||||
return((int)MANDOCLEVEL_BADARG);
|
||||
break;
|
||||
case ('W'):
|
||||
if ( ! woptions(&curp, optarg))
|
||||
return((int)MANDOCLEVEL_BADARG);
|
||||
break;
|
||||
case ('V'):
|
||||
version();
|
||||
/* NOTREACHED */
|
||||
default:
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
curp.mp = mparse_alloc(type, curp.wlevel, mmsg, &curp);
|
||||
|
||||
/*
|
||||
* Conditionally start up the lookaside buffer before parsing.
|
||||
*/
|
||||
if (OUTT_MAN == curp.outtype)
|
||||
mparse_keep(curp.mp);
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
rc = MANDOCLEVEL_OK;
|
||||
|
||||
if (NULL == *argv)
|
||||
parse(&curp, STDIN_FILENO, "<stdin>", &rc);
|
||||
|
||||
while (*argv) {
|
||||
parse(&curp, -1, *argv, &rc);
|
||||
if (MANDOCLEVEL_OK != rc && curp.wstop)
|
||||
break;
|
||||
++argv;
|
||||
}
|
||||
|
||||
if (curp.outfree)
|
||||
(*curp.outfree)(curp.outdata);
|
||||
if (curp.mp)
|
||||
mparse_free(curp.mp);
|
||||
|
||||
return((int)rc);
|
||||
}
|
||||
|
||||
static void
|
||||
version(void)
|
||||
{
|
||||
|
||||
printf("%s %s\n", progname, VERSION);
|
||||
exit((int)MANDOCLEVEL_OK);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
|
||||
fprintf(stderr, "usage: %s "
|
||||
"[-V] "
|
||||
"[-foption] "
|
||||
"[-mformat] "
|
||||
"[-Ooption] "
|
||||
"[-Toutput] "
|
||||
"[-Wlevel] "
|
||||
"[file...]\n",
|
||||
progname);
|
||||
|
||||
exit((int)MANDOCLEVEL_BADARG);
|
||||
}
|
||||
|
||||
static void
|
||||
parse(struct curparse *curp, int fd,
|
||||
const char *file, enum mandoclevel *level)
|
||||
{
|
||||
enum mandoclevel rc;
|
||||
struct mdoc *mdoc;
|
||||
struct man *man;
|
||||
|
||||
/* Begin by parsing the file itself. */
|
||||
|
||||
assert(file);
|
||||
assert(fd >= -1);
|
||||
|
||||
rc = mparse_readfd(curp->mp, fd, file);
|
||||
|
||||
/* Stop immediately if the parse has failed. */
|
||||
|
||||
if (MANDOCLEVEL_FATAL <= rc)
|
||||
goto cleanup;
|
||||
|
||||
/*
|
||||
* With -Wstop and warnings or errors of at least the requested
|
||||
* level, do not produce output.
|
||||
*/
|
||||
|
||||
if (MANDOCLEVEL_OK != rc && curp->wstop)
|
||||
goto cleanup;
|
||||
|
||||
/* If unset, allocate output dev now (if applicable). */
|
||||
|
||||
if ( ! (curp->outman && curp->outmdoc)) {
|
||||
switch (curp->outtype) {
|
||||
case (OUTT_XHTML):
|
||||
curp->outdata = xhtml_alloc(curp->outopts);
|
||||
curp->outfree = html_free;
|
||||
break;
|
||||
case (OUTT_HTML):
|
||||
curp->outdata = html_alloc(curp->outopts);
|
||||
curp->outfree = html_free;
|
||||
break;
|
||||
case (OUTT_UTF8):
|
||||
curp->outdata = utf8_alloc(curp->outopts);
|
||||
curp->outfree = ascii_free;
|
||||
break;
|
||||
case (OUTT_LOCALE):
|
||||
curp->outdata = locale_alloc(curp->outopts);
|
||||
curp->outfree = ascii_free;
|
||||
break;
|
||||
case (OUTT_ASCII):
|
||||
curp->outdata = ascii_alloc(curp->outopts);
|
||||
curp->outfree = ascii_free;
|
||||
break;
|
||||
case (OUTT_PDF):
|
||||
curp->outdata = pdf_alloc(curp->outopts);
|
||||
curp->outfree = pspdf_free;
|
||||
break;
|
||||
case (OUTT_PS):
|
||||
curp->outdata = ps_alloc(curp->outopts);
|
||||
curp->outfree = pspdf_free;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (curp->outtype) {
|
||||
case (OUTT_HTML):
|
||||
/* FALLTHROUGH */
|
||||
case (OUTT_XHTML):
|
||||
curp->outman = html_man;
|
||||
curp->outmdoc = html_mdoc;
|
||||
break;
|
||||
case (OUTT_TREE):
|
||||
curp->outman = tree_man;
|
||||
curp->outmdoc = tree_mdoc;
|
||||
break;
|
||||
case (OUTT_MAN):
|
||||
curp->outmdoc = man_mdoc;
|
||||
curp->outman = man_man;
|
||||
break;
|
||||
case (OUTT_PDF):
|
||||
/* FALLTHROUGH */
|
||||
case (OUTT_ASCII):
|
||||
/* FALLTHROUGH */
|
||||
case (OUTT_UTF8):
|
||||
/* FALLTHROUGH */
|
||||
case (OUTT_LOCALE):
|
||||
/* FALLTHROUGH */
|
||||
case (OUTT_PS):
|
||||
curp->outman = terminal_man;
|
||||
curp->outmdoc = terminal_mdoc;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mparse_result(curp->mp, &mdoc, &man);
|
||||
|
||||
/* Execute the out device, if it exists. */
|
||||
|
||||
if (man && curp->outman)
|
||||
(*curp->outman)(curp->outdata, man);
|
||||
if (mdoc && curp->outmdoc)
|
||||
(*curp->outmdoc)(curp->outdata, mdoc);
|
||||
|
||||
cleanup:
|
||||
|
||||
mparse_reset(curp->mp);
|
||||
|
||||
if (*level < rc)
|
||||
*level = rc;
|
||||
}
|
||||
|
||||
static int
|
||||
moptions(enum mparset *tflags, char *arg)
|
||||
{
|
||||
|
||||
if (0 == strcmp(arg, "doc"))
|
||||
*tflags = MPARSE_MDOC;
|
||||
else if (0 == strcmp(arg, "andoc"))
|
||||
*tflags = MPARSE_AUTO;
|
||||
else if (0 == strcmp(arg, "an"))
|
||||
*tflags = MPARSE_MAN;
|
||||
else {
|
||||
fprintf(stderr, "%s: Bad argument\n", arg);
|
||||
return(0);
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int
|
||||
toptions(struct curparse *curp, char *arg)
|
||||
{
|
||||
|
||||
if (0 == strcmp(arg, "ascii"))
|
||||
curp->outtype = OUTT_ASCII;
|
||||
else if (0 == strcmp(arg, "lint")) {
|
||||
curp->outtype = OUTT_LINT;
|
||||
curp->wlevel = MANDOCLEVEL_WARNING;
|
||||
} else if (0 == strcmp(arg, "tree"))
|
||||
curp->outtype = OUTT_TREE;
|
||||
else if (0 == strcmp(arg, "man"))
|
||||
curp->outtype = OUTT_MAN;
|
||||
else if (0 == strcmp(arg, "html"))
|
||||
curp->outtype = OUTT_HTML;
|
||||
else if (0 == strcmp(arg, "utf8"))
|
||||
curp->outtype = OUTT_UTF8;
|
||||
else if (0 == strcmp(arg, "locale"))
|
||||
curp->outtype = OUTT_LOCALE;
|
||||
else if (0 == strcmp(arg, "xhtml"))
|
||||
curp->outtype = OUTT_XHTML;
|
||||
else if (0 == strcmp(arg, "ps"))
|
||||
curp->outtype = OUTT_PS;
|
||||
else if (0 == strcmp(arg, "pdf"))
|
||||
curp->outtype = OUTT_PDF;
|
||||
else {
|
||||
fprintf(stderr, "%s: Bad argument\n", arg);
|
||||
return(0);
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int
|
||||
woptions(struct curparse *curp, char *arg)
|
||||
{
|
||||
char *v, *o;
|
||||
const char *toks[6];
|
||||
|
||||
toks[0] = "stop";
|
||||
toks[1] = "all";
|
||||
toks[2] = "warning";
|
||||
toks[3] = "error";
|
||||
toks[4] = "fatal";
|
||||
toks[5] = NULL;
|
||||
|
||||
while (*arg) {
|
||||
o = arg;
|
||||
switch (getsubopt(&arg, UNCONST(toks), &v)) {
|
||||
case (0):
|
||||
curp->wstop = 1;
|
||||
break;
|
||||
case (1):
|
||||
/* FALLTHROUGH */
|
||||
case (2):
|
||||
curp->wlevel = MANDOCLEVEL_WARNING;
|
||||
break;
|
||||
case (3):
|
||||
curp->wlevel = MANDOCLEVEL_ERROR;
|
||||
break;
|
||||
case (4):
|
||||
curp->wlevel = MANDOCLEVEL_FATAL;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "-W%s: Bad argument\n", o);
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
static void
|
||||
mmsg(enum mandocerr t, enum mandoclevel lvl,
|
||||
const char *file, int line, int col, const char *msg)
|
||||
{
|
||||
|
||||
fprintf(stderr, "%s:%d:%d: %s: %s",
|
||||
file, line, col + 1,
|
||||
mparse_strlevel(lvl),
|
||||
mparse_strerror(t));
|
||||
|
||||
if (msg)
|
||||
fprintf(stderr, ": %s", msg);
|
||||
|
||||
fputc('\n', stderr);
|
||||
}
|
61
contrib/mdocml/main.h
Normal file
61
contrib/mdocml/main.h
Normal file
@ -0,0 +1,61 @@
|
||||
/* $Id: main.h,v 1.15 2011/10/06 22:29:12 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 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 MAIN_H
|
||||
#define MAIN_H
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
struct mdoc;
|
||||
struct man;
|
||||
|
||||
#define UNCONST(a) ((void *)(uintptr_t)(const void *)(a))
|
||||
|
||||
|
||||
/*
|
||||
* Definitions for main.c-visible output device functions, e.g., -Thtml
|
||||
* and -Tascii. Note that ascii_alloc() is named as such in
|
||||
* anticipation of latin1_alloc() and so on, all of which map into the
|
||||
* terminal output routines with different character settings.
|
||||
*/
|
||||
|
||||
void *html_alloc(char *);
|
||||
void *xhtml_alloc(char *);
|
||||
void html_mdoc(void *, const struct mdoc *);
|
||||
void html_man(void *, const struct man *);
|
||||
void html_free(void *);
|
||||
|
||||
void tree_mdoc(void *, const struct mdoc *);
|
||||
void tree_man(void *, const struct man *);
|
||||
|
||||
void man_mdoc(void *, const struct mdoc *);
|
||||
void man_man(void *, const struct man *);
|
||||
|
||||
void *locale_alloc(char *);
|
||||
void *utf8_alloc(char *);
|
||||
void *ascii_alloc(char *);
|
||||
void ascii_free(void *);
|
||||
|
||||
void *pdf_alloc(char *);
|
||||
void *ps_alloc(char *);
|
||||
void pspdf_free(void *);
|
||||
|
||||
void terminal_mdoc(void *, const struct mdoc *);
|
||||
void terminal_man(void *, const struct man *);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /*!MAIN_H*/
|
913
contrib/mdocml/man.7
Normal file
913
contrib/mdocml/man.7
Normal file
@ -0,0 +1,913 @@
|
||||
.\" $Id: man.7,v 1.113 2012/01/03 15:16:24 kristaps Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
.\" 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.
|
||||
.\"
|
||||
.Dd $Mdocdate: January 3 2012 $
|
||||
.Dt MAN 7
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm man
|
||||
.Nd legacy formatting language for manual pages
|
||||
.Sh DESCRIPTION
|
||||
Traditionally, the
|
||||
.Nm man
|
||||
language has been used to write
|
||||
.Ux
|
||||
manuals for the
|
||||
.Xr man 1
|
||||
utility.
|
||||
It supports limited control of presentational details like fonts,
|
||||
indentation and spacing.
|
||||
This reference document describes the structure of manual pages
|
||||
and the syntax and usage of the man language.
|
||||
.Pp
|
||||
.Bf -emphasis
|
||||
Do not use
|
||||
.Nm
|
||||
to write your manuals:
|
||||
.Ef
|
||||
It lacks support for semantic markup.
|
||||
Use the
|
||||
.Xr mdoc 7
|
||||
language, instead.
|
||||
.Pp
|
||||
In a
|
||||
.Nm
|
||||
document, lines beginning with the control character
|
||||
.Sq \&.
|
||||
are called
|
||||
.Dq macro lines .
|
||||
The first word is the macro name.
|
||||
It usually consists of two capital letters.
|
||||
For a list of available macros, see
|
||||
.Sx MACRO OVERVIEW .
|
||||
The words following the macro name are arguments to the macro.
|
||||
.Pp
|
||||
Lines not beginning with the control character are called
|
||||
.Dq text lines .
|
||||
They provide free-form text to be printed; the formatting of the text
|
||||
depends on the respective processing context:
|
||||
.Bd -literal -offset indent
|
||||
\&.SH Macro lines change control state.
|
||||
Text lines are interpreted within the current state.
|
||||
.Ed
|
||||
.Pp
|
||||
Many aspects of the basic syntax of the
|
||||
.Nm
|
||||
language are based on the
|
||||
.Xr roff 7
|
||||
language; see the
|
||||
.Em LANGUAGE SYNTAX
|
||||
and
|
||||
.Em MACRO SYNTAX
|
||||
sections in the
|
||||
.Xr roff 7
|
||||
manual for details, in particular regarding
|
||||
comments, escape sequences, whitespace, and quoting.
|
||||
.Sh MANUAL STRUCTURE
|
||||
Each
|
||||
.Nm
|
||||
document must contain the
|
||||
.Sx \&TH
|
||||
macro describing the document's section and title.
|
||||
It may occur anywhere in the document, although conventionally it
|
||||
appears as the first macro.
|
||||
.Pp
|
||||
Beyond
|
||||
.Sx \&TH ,
|
||||
at least one macro or text line must appear in the document.
|
||||
.Pp
|
||||
The following is a well-formed skeleton
|
||||
.Nm
|
||||
file for a utility
|
||||
.Qq progname :
|
||||
.Bd -literal -offset indent
|
||||
\&.TH PROGNAME 1 2009-10-10
|
||||
\&.SH NAME
|
||||
\efBprogname\efR \e(en a description goes here
|
||||
\&.\e\(dq .SH LIBRARY
|
||||
\&.\e\(dq For sections 2 & 3 only.
|
||||
\&.\e\(dq Not used in OpenBSD.
|
||||
\&.SH SYNOPSIS
|
||||
\efBprogname\efR [\efB\e-options\efR] arguments...
|
||||
\&.SH DESCRIPTION
|
||||
The \efBfoo\efR utility processes files...
|
||||
\&.\e\(dq .SH IMPLEMENTATION NOTES
|
||||
\&.\e\(dq Not used in OpenBSD.
|
||||
\&.\e\(dq .SH RETURN VALUES
|
||||
\&.\e\(dq For sections 2, 3, & 9 only.
|
||||
\&.\e\(dq .SH ENVIRONMENT
|
||||
\&.\e\(dq For sections 1, 6, 7, & 8 only.
|
||||
\&.\e\(dq .SH FILES
|
||||
\&.\e\(dq .SH EXIT STATUS
|
||||
\&.\e\(dq For sections 1, 6, & 8 only.
|
||||
\&.\e\(dq .SH EXAMPLES
|
||||
\&.\e\(dq .SH DIAGNOSTICS
|
||||
\&.\e\(dq For sections 1, 4, 6, 7, & 8 only.
|
||||
\&.\e\(dq .SH ERRORS
|
||||
\&.\e\(dq For sections 2, 3, & 9 only.
|
||||
\&.\e\(dq .SH SEE ALSO
|
||||
\&.\e\(dq .BR foo ( 1 )
|
||||
\&.\e\(dq .SH STANDARDS
|
||||
\&.\e\(dq .SH HISTORY
|
||||
\&.\e\(dq .SH AUTHORS
|
||||
\&.\e\(dq .SH CAVEATS
|
||||
\&.\e\(dq .SH BUGS
|
||||
\&.\e\(dq .SH SECURITY CONSIDERATIONS
|
||||
\&.\e\(dq Not used in OpenBSD.
|
||||
.Ed
|
||||
.Pp
|
||||
The sections in a
|
||||
.Nm
|
||||
document are conventionally ordered as they appear above.
|
||||
Sections should be composed as follows:
|
||||
.Bl -ohang -offset indent
|
||||
.It Em NAME
|
||||
The name(s) and a short description of the documented material.
|
||||
The syntax for this is generally as follows:
|
||||
.Pp
|
||||
.D1 \efBname\efR \e(en description
|
||||
.It Em LIBRARY
|
||||
The name of the library containing the documented material, which is
|
||||
assumed to be a function in a section 2 or 3 manual.
|
||||
For functions in the C library, this may be as follows:
|
||||
.Pp
|
||||
.D1 Standard C Library (libc, -lc)
|
||||
.It Em SYNOPSIS
|
||||
Documents the utility invocation syntax, function call syntax, or device
|
||||
configuration.
|
||||
.Pp
|
||||
For the first, utilities (sections 1, 6, and 8), this is
|
||||
generally structured as follows:
|
||||
.Pp
|
||||
.D1 \efBname\efR [-\efBab\efR] [-\efBc\efR\efIarg\efR] \efBpath\efR...
|
||||
.Pp
|
||||
For the second, function calls (sections 2, 3, 9):
|
||||
.Pp
|
||||
.D1 \&.B char *name(char *\efIarg\efR);
|
||||
.Pp
|
||||
And for the third, configurations (section 4):
|
||||
.Pp
|
||||
.D1 \&.B name* at cardbus ? function ?
|
||||
.Pp
|
||||
Manuals not in these sections generally don't need a
|
||||
.Em SYNOPSIS .
|
||||
.It Em DESCRIPTION
|
||||
This expands upon the brief, one-line description in
|
||||
.Em NAME .
|
||||
It usually contains a break-down of the options (if documenting a
|
||||
command).
|
||||
.It Em IMPLEMENTATION NOTES
|
||||
Implementation-specific notes should be kept here.
|
||||
This is useful when implementing standard functions that may have side
|
||||
effects or notable algorithmic implications.
|
||||
.It Em RETURN VALUES
|
||||
This section documents the return values of functions in sections 2, 3, and 9.
|
||||
.It Em ENVIRONMENT
|
||||
Documents any usages of environment variables, e.g.,
|
||||
.Xr environ 7 .
|
||||
.It Em FILES
|
||||
Documents files used.
|
||||
It's helpful to document both the file name and a short description of how
|
||||
the file is used (created, modified, etc.).
|
||||
.It Em EXIT STATUS
|
||||
This section documents the command exit status for
|
||||
section 1, 6, and 8 utilities.
|
||||
Historically, this information was described in
|
||||
.Em DIAGNOSTICS ,
|
||||
a practise that is now discouraged.
|
||||
.It Em EXAMPLES
|
||||
Example usages.
|
||||
This often contains snippets of well-formed,
|
||||
well-tested invocations.
|
||||
Make sure that examples work properly!
|
||||
.It Em DIAGNOSTICS
|
||||
Documents error conditions.
|
||||
This is most useful in section 4 manuals.
|
||||
Historically, this section was used in place of
|
||||
.Em EXIT STATUS
|
||||
for manuals in sections 1, 6, and 8; however, this practise is
|
||||
discouraged.
|
||||
.It Em ERRORS
|
||||
Documents error handling in sections 2, 3, and 9.
|
||||
.It Em SEE ALSO
|
||||
References other manuals with related topics.
|
||||
This section should exist for most manuals.
|
||||
.Pp
|
||||
.D1 \&.BR bar \&( 1 \&),
|
||||
.Pp
|
||||
Cross-references should conventionally be ordered
|
||||
first by section, then alphabetically.
|
||||
.It Em STANDARDS
|
||||
References any standards implemented or used, such as
|
||||
.Pp
|
||||
.D1 IEEE Std 1003.2 (\e(lqPOSIX.2\e(rq)
|
||||
.Pp
|
||||
If not adhering to any standards, the
|
||||
.Em HISTORY
|
||||
section should be used.
|
||||
.It Em HISTORY
|
||||
A brief history of the subject, including where support first appeared.
|
||||
.It Em AUTHORS
|
||||
Credits to the person or persons who wrote the code and/or documentation.
|
||||
Authors should generally be noted by both name and email address.
|
||||
.It Em CAVEATS
|
||||
Common misuses and misunderstandings should be explained
|
||||
in this section.
|
||||
.It Em BUGS
|
||||
Known bugs, limitations, and work-arounds should be described
|
||||
in this section.
|
||||
.It Em SECURITY CONSIDERATIONS
|
||||
Documents any security precautions that operators should consider.
|
||||
.El
|
||||
.Sh MACRO OVERVIEW
|
||||
This overview is sorted such that macros of similar purpose are listed
|
||||
together, to help find the best macro for any given purpose.
|
||||
Deprecated macros are not included in the overview, but can be found
|
||||
in the alphabetical reference below.
|
||||
.Ss Page header and footer meta-data
|
||||
.Bl -column "PP, LP, P" description
|
||||
.It Sx TH Ta set the title: Ar title section date Op Ar source Op Ar volume
|
||||
.It Sx AT Ta display AT&T UNIX version in the page footer (<= 1 argument)
|
||||
.It Sx UC Ta display BSD version in the page footer (<= 1 argument)
|
||||
.El
|
||||
.Ss Sections and paragraphs
|
||||
.Bl -column "PP, LP, P" description
|
||||
.It Sx SH Ta section header (one line)
|
||||
.It Sx SS Ta subsection header (one line)
|
||||
.It Sx PP , LP , P Ta start an undecorated paragraph (no arguments)
|
||||
.It Sx RS , RE Ta reset the left margin: Op Ar width
|
||||
.It Sx IP Ta indented paragraph: Op Ar head Op Ar width
|
||||
.It Sx TP Ta tagged paragraph: Op Ar width
|
||||
.It Sx HP Ta hanged paragraph: Op Ar width
|
||||
.It Sx \&br Ta force output line break in text mode (no arguments)
|
||||
.It Sx \&sp Ta force vertical space: Op Ar height
|
||||
.It Sx fi , nf Ta fill mode and no-fill mode (no arguments)
|
||||
.It Sx in Ta additional indent: Op Ar width
|
||||
.El
|
||||
.Ss Physical markup
|
||||
.Bl -column "PP, LP, P" description
|
||||
.It Sx B Ta boldface font
|
||||
.It Sx I Ta italic font
|
||||
.It Sx R Ta roman (default) font
|
||||
.It Sx SB Ta small boldface font
|
||||
.It Sx SM Ta small roman font
|
||||
.It Sx BI Ta alternate between boldface and italic fonts
|
||||
.It Sx BR Ta alternate between boldface and roman fonts
|
||||
.It Sx IB Ta alternate between italic and boldface fonts
|
||||
.It Sx IR Ta alternate between italic and roman fonts
|
||||
.It Sx RB Ta alternate between roman and boldface fonts
|
||||
.It Sx RI Ta alternate between roman and italic fonts
|
||||
.El
|
||||
.Ss Semantic markup
|
||||
.Bl -column "PP, LP, P" description
|
||||
.It Sx OP Ta optional arguments
|
||||
.El
|
||||
.Sh MACRO REFERENCE
|
||||
This section is a canonical reference to all macros, arranged
|
||||
alphabetically.
|
||||
For the scoping of individual macros, see
|
||||
.Sx MACRO SYNTAX .
|
||||
.Ss \&AT
|
||||
Sets the volume for the footer for compatibility with man pages from
|
||||
.Tn AT&T UNIX
|
||||
releases.
|
||||
The optional arguments specify which release it is from.
|
||||
.Ss \&B
|
||||
Text is rendered in bold face.
|
||||
.Pp
|
||||
See also
|
||||
.Sx \&I
|
||||
and
|
||||
.Sx \&R .
|
||||
.Ss \&BI
|
||||
Text is rendered alternately in bold face and italic.
|
||||
Thus,
|
||||
.Sq .BI this word and that
|
||||
causes
|
||||
.Sq this
|
||||
and
|
||||
.Sq and
|
||||
to render in bold face, while
|
||||
.Sq word
|
||||
and
|
||||
.Sq that
|
||||
render in italics.
|
||||
Whitespace between arguments is omitted in output.
|
||||
.Pp
|
||||
Examples:
|
||||
.Pp
|
||||
.Dl \&.BI bold italic bold italic
|
||||
.Pp
|
||||
The output of this example will be emboldened
|
||||
.Dq bold
|
||||
and italicised
|
||||
.Dq italic ,
|
||||
with spaces stripped between arguments.
|
||||
.Pp
|
||||
See also
|
||||
.Sx \&IB ,
|
||||
.Sx \&BR ,
|
||||
.Sx \&RB ,
|
||||
.Sx \&RI ,
|
||||
and
|
||||
.Sx \&IR .
|
||||
.Ss \&BR
|
||||
Text is rendered alternately in bold face and roman (the default font).
|
||||
Whitespace between arguments is omitted in output.
|
||||
.Pp
|
||||
See
|
||||
.Sx \&BI
|
||||
for an equivalent example.
|
||||
.Pp
|
||||
See also
|
||||
.Sx \&BI ,
|
||||
.Sx \&IB ,
|
||||
.Sx \&RB ,
|
||||
.Sx \&RI ,
|
||||
and
|
||||
.Sx \&IR .
|
||||
.Ss \&DT
|
||||
Has no effect.
|
||||
Included for compatibility.
|
||||
.Ss \&HP
|
||||
Begin a paragraph whose initial output line is left-justified, but
|
||||
subsequent output lines are indented, with the following syntax:
|
||||
.Bd -filled -offset indent
|
||||
.Pf \. Sx \&HP
|
||||
.Op Cm width
|
||||
.Ed
|
||||
.Pp
|
||||
The
|
||||
.Cm width
|
||||
argument must conform to
|
||||
.Sx Scaling Widths .
|
||||
If specified, it's saved for later paragraph left-margins; if unspecified, the
|
||||
saved or default width is used.
|
||||
.Pp
|
||||
See also
|
||||
.Sx \&IP ,
|
||||
.Sx \&LP ,
|
||||
.Sx \&P ,
|
||||
.Sx \&PP ,
|
||||
and
|
||||
.Sx \&TP .
|
||||
.Ss \&I
|
||||
Text is rendered in italics.
|
||||
.Pp
|
||||
See also
|
||||
.Sx \&B
|
||||
and
|
||||
.Sx \&R .
|
||||
.Ss \&IB
|
||||
Text is rendered alternately in italics and bold face.
|
||||
Whitespace between arguments is omitted in output.
|
||||
.Pp
|
||||
See
|
||||
.Sx \&BI
|
||||
for an equivalent example.
|
||||
.Pp
|
||||
See also
|
||||
.Sx \&BI ,
|
||||
.Sx \&BR ,
|
||||
.Sx \&RB ,
|
||||
.Sx \&RI ,
|
||||
and
|
||||
.Sx \&IR .
|
||||
.Ss \&IP
|
||||
Begin an indented paragraph with the following syntax:
|
||||
.Bd -filled -offset indent
|
||||
.Pf \. Sx \&IP
|
||||
.Op Cm head Op Cm width
|
||||
.Ed
|
||||
.Pp
|
||||
The
|
||||
.Cm width
|
||||
argument defines the width of the left margin and is defined by
|
||||
.Sx Scaling Widths .
|
||||
It's saved for later paragraph left-margins; if unspecified, the saved or
|
||||
default width is used.
|
||||
.Pp
|
||||
The
|
||||
.Cm head
|
||||
argument is used as a leading term, flushed to the left margin.
|
||||
This is useful for bulleted paragraphs and so on.
|
||||
.Pp
|
||||
See also
|
||||
.Sx \&HP ,
|
||||
.Sx \&LP ,
|
||||
.Sx \&P ,
|
||||
.Sx \&PP ,
|
||||
and
|
||||
.Sx \&TP .
|
||||
.Ss \&IR
|
||||
Text is rendered alternately in italics and roman (the default font).
|
||||
Whitespace between arguments is omitted in output.
|
||||
.Pp
|
||||
See
|
||||
.Sx \&BI
|
||||
for an equivalent example.
|
||||
.Pp
|
||||
See also
|
||||
.Sx \&BI ,
|
||||
.Sx \&IB ,
|
||||
.Sx \&BR ,
|
||||
.Sx \&RB ,
|
||||
and
|
||||
.Sx \&RI .
|
||||
.Ss \&LP
|
||||
Begin an undecorated paragraph.
|
||||
The scope of a paragraph is closed by a subsequent paragraph,
|
||||
sub-section, section, or end of file.
|
||||
The saved paragraph left-margin width is reset to the default.
|
||||
.Pp
|
||||
See also
|
||||
.Sx \&HP ,
|
||||
.Sx \&IP ,
|
||||
.Sx \&P ,
|
||||
.Sx \&PP ,
|
||||
and
|
||||
.Sx \&TP .
|
||||
.Ss \&OP
|
||||
Optional command-line argument.
|
||||
This has the following syntax:
|
||||
.Bd -filled -offset indent
|
||||
.Pf \. Sx \&OP
|
||||
.Cm key Op Cm value
|
||||
.Ed
|
||||
.Pp
|
||||
The
|
||||
.Cm key
|
||||
is usually a command-line flag and
|
||||
.Cm value
|
||||
its argument.
|
||||
.Ss \&P
|
||||
Synonym for
|
||||
.Sx \&LP .
|
||||
.Pp
|
||||
See also
|
||||
.Sx \&HP ,
|
||||
.Sx \&IP ,
|
||||
.Sx \&LP ,
|
||||
.Sx \&PP ,
|
||||
and
|
||||
.Sx \&TP .
|
||||
.Ss \&PP
|
||||
Synonym for
|
||||
.Sx \&LP .
|
||||
.Pp
|
||||
See also
|
||||
.Sx \&HP ,
|
||||
.Sx \&IP ,
|
||||
.Sx \&LP ,
|
||||
.Sx \&P ,
|
||||
and
|
||||
.Sx \&TP .
|
||||
.Ss \&R
|
||||
Text is rendered in roman (the default font).
|
||||
.Pp
|
||||
See also
|
||||
.Sx \&I
|
||||
and
|
||||
.Sx \&B .
|
||||
.Ss \&RB
|
||||
Text is rendered alternately in roman (the default font) and bold face.
|
||||
Whitespace between arguments is omitted in output.
|
||||
.Pp
|
||||
See
|
||||
.Sx \&BI
|
||||
for an equivalent example.
|
||||
.Pp
|
||||
See also
|
||||
.Sx \&BI ,
|
||||
.Sx \&IB ,
|
||||
.Sx \&BR ,
|
||||
.Sx \&RI ,
|
||||
and
|
||||
.Sx \&IR .
|
||||
.Ss \&RE
|
||||
Explicitly close out the scope of a prior
|
||||
.Sx \&RS .
|
||||
The default left margin is restored to the state of the original
|
||||
.Sx \&RS
|
||||
invocation.
|
||||
.Ss \&RI
|
||||
Text is rendered alternately in roman (the default font) and italics.
|
||||
Whitespace between arguments is omitted in output.
|
||||
.Pp
|
||||
See
|
||||
.Sx \&BI
|
||||
for an equivalent example.
|
||||
.Pp
|
||||
See also
|
||||
.Sx \&BI ,
|
||||
.Sx \&IB ,
|
||||
.Sx \&BR ,
|
||||
.Sx \&RB ,
|
||||
and
|
||||
.Sx \&IR .
|
||||
.Ss \&RS
|
||||
Temporarily reset the default left margin.
|
||||
This has the following syntax:
|
||||
.Bd -filled -offset indent
|
||||
.Pf \. Sx \&RS
|
||||
.Op Cm width
|
||||
.Ed
|
||||
.Pp
|
||||
The
|
||||
.Cm width
|
||||
argument must conform to
|
||||
.Sx Scaling Widths .
|
||||
If not specified, the saved or default width is used.
|
||||
.Pp
|
||||
See also
|
||||
.Sx \&RE .
|
||||
.Ss \&SB
|
||||
Text is rendered in small size (one point smaller than the default font)
|
||||
bold face.
|
||||
.Ss \&SH
|
||||
Begin a section.
|
||||
The scope of a section is only closed by another section or the end of
|
||||
file.
|
||||
The paragraph left-margin width is reset to the default.
|
||||
.Ss \&SM
|
||||
Text is rendered in small size (one point smaller than the default
|
||||
font).
|
||||
.Ss \&SS
|
||||
Begin a sub-section.
|
||||
The scope of a sub-section is closed by a subsequent sub-section,
|
||||
section, or end of file.
|
||||
The paragraph left-margin width is reset to the default.
|
||||
.Ss \&TH
|
||||
Sets the title of the manual page with the following syntax:
|
||||
.Bd -filled -offset indent
|
||||
.Pf \. Sx \&TH
|
||||
.Ar title section date
|
||||
.Op Ar source Op Ar volume
|
||||
.Ed
|
||||
.Pp
|
||||
Conventionally, the document
|
||||
.Ar title
|
||||
is given in all caps.
|
||||
The recommended
|
||||
.Ar date
|
||||
format is
|
||||
.Sy YYYY-MM-DD
|
||||
as specified in the ISO-8601 standard;
|
||||
if the argument does not conform, it is printed verbatim.
|
||||
If the
|
||||
.Ar date
|
||||
is empty or not specified, the current date is used.
|
||||
The optional
|
||||
.Ar source
|
||||
string specifies the organisation providing the utility.
|
||||
The
|
||||
.Ar volume
|
||||
string replaces the default rendered volume, which is dictated by the
|
||||
manual section.
|
||||
.Pp
|
||||
Examples:
|
||||
.Pp
|
||||
.Dl \&.TH CVS 5 "1992-02-12" GNU
|
||||
.Ss \&TP
|
||||
Begin a paragraph where the head, if exceeding the indentation width, is
|
||||
followed by a newline; if not, the body follows on the same line after a
|
||||
buffer to the indentation width.
|
||||
Subsequent output lines are indented.
|
||||
The syntax is as follows:
|
||||
.Bd -filled -offset indent
|
||||
.Pf \. Sx \&TP
|
||||
.Op Cm width
|
||||
.Ed
|
||||
.Pp
|
||||
The
|
||||
.Cm width
|
||||
argument must conform to
|
||||
.Sx Scaling Widths .
|
||||
If specified, it's saved for later paragraph left-margins; if
|
||||
unspecified, the saved or default width is used.
|
||||
.Pp
|
||||
See also
|
||||
.Sx \&HP ,
|
||||
.Sx \&IP ,
|
||||
.Sx \&LP ,
|
||||
.Sx \&P ,
|
||||
and
|
||||
.Sx \&PP .
|
||||
.Ss \&UC
|
||||
Sets the volume for the footer for compatibility with man pages from
|
||||
BSD releases.
|
||||
The optional first argument specifies which release it is from.
|
||||
.Ss \&br
|
||||
Breaks the current line.
|
||||
Consecutive invocations have no further effect.
|
||||
.Pp
|
||||
See also
|
||||
.Sx \&sp .
|
||||
.Ss \&fi
|
||||
End literal mode begun by
|
||||
.Sx \&nf .
|
||||
.Ss \&ft
|
||||
Change the current font mode.
|
||||
See
|
||||
.Sx Text Decoration
|
||||
for a listing of available font modes.
|
||||
.Ss \&in
|
||||
Indent relative to the current indentation:
|
||||
.Pp
|
||||
.D1 Pf \. Sx \&in Op Cm width
|
||||
.Pp
|
||||
If
|
||||
.Cm width
|
||||
is signed, the new offset is relative.
|
||||
Otherwise, it is absolute.
|
||||
This value is reset upon the next paragraph, section, or sub-section.
|
||||
.Ss \&na
|
||||
Don't align to the right margin.
|
||||
.Ss \&nf
|
||||
Begin literal mode: all subsequent free-form lines have their end of
|
||||
line boundaries preserved.
|
||||
May be ended by
|
||||
.Sx \&fi .
|
||||
Literal mode is implicitly ended by
|
||||
.Sx \&SH
|
||||
or
|
||||
.Sx \&SS .
|
||||
.Ss \&sp
|
||||
Insert vertical spaces into output with the following syntax:
|
||||
.Bd -filled -offset indent
|
||||
.Pf \. Sx \&sp
|
||||
.Op Cm height
|
||||
.Ed
|
||||
.Pp
|
||||
Insert
|
||||
.Cm height
|
||||
spaces, which must conform to
|
||||
.Sx Scaling Widths .
|
||||
If 0, this is equivalent to the
|
||||
.Sx \&br
|
||||
macro.
|
||||
Defaults to 1, if unspecified.
|
||||
.Pp
|
||||
See also
|
||||
.Sx \&br .
|
||||
.Sh MACRO SYNTAX
|
||||
The
|
||||
.Nm
|
||||
macros are classified by scope: line scope or block scope.
|
||||
Line macros are only scoped to the current line (and, in some
|
||||
situations, the subsequent line).
|
||||
Block macros are scoped to the current line and subsequent lines until
|
||||
closed by another block macro.
|
||||
.Ss Line Macros
|
||||
Line macros are generally scoped to the current line, with the body
|
||||
consisting of zero or more arguments.
|
||||
If a macro is scoped to the next line and the line arguments are empty,
|
||||
the next line, which must be text, is used instead.
|
||||
Thus:
|
||||
.Bd -literal -offset indent
|
||||
\&.I
|
||||
foo
|
||||
.Ed
|
||||
.Pp
|
||||
is equivalent to
|
||||
.Sq \&.I foo .
|
||||
If next-line macros are invoked consecutively, only the last is used.
|
||||
If a next-line macro is followed by a non-next-line macro, an error is
|
||||
raised, except for
|
||||
.Sx \&br ,
|
||||
.Sx \&sp ,
|
||||
and
|
||||
.Sx \&na .
|
||||
.Pp
|
||||
The syntax is as follows:
|
||||
.Bd -literal -offset indent
|
||||
\&.YO \(lBbody...\(rB
|
||||
\(lBbody...\(rB
|
||||
.Ed
|
||||
.Bl -column "MacroX" "ArgumentsX" "ScopeXXXXX" "CompatX" -offset indent
|
||||
.It Em Macro Ta Em Arguments Ta Em Scope Ta Em Notes
|
||||
.It Sx \&AT Ta <=1 Ta current Ta \&
|
||||
.It Sx \&B Ta n Ta next-line Ta \&
|
||||
.It Sx \&BI Ta n Ta current Ta \&
|
||||
.It Sx \&BR Ta n Ta current Ta \&
|
||||
.It Sx \&DT Ta 0 Ta current Ta \&
|
||||
.It Sx \&I Ta n Ta next-line Ta \&
|
||||
.It Sx \&IB Ta n Ta current Ta \&
|
||||
.It Sx \&IR Ta n Ta current Ta \&
|
||||
.It Sx \&OP Ta 0, 1 Ta current Ta compat
|
||||
.It Sx \&R Ta n Ta next-line Ta \&
|
||||
.It Sx \&RB Ta n Ta current Ta \&
|
||||
.It Sx \&RI Ta n Ta current Ta \&
|
||||
.It Sx \&SB Ta n Ta next-line Ta \&
|
||||
.It Sx \&SM Ta n Ta next-line Ta \&
|
||||
.It Sx \&TH Ta >1, <6 Ta current Ta \&
|
||||
.It Sx \&UC Ta <=1 Ta current Ta \&
|
||||
.It Sx \&br Ta 0 Ta current Ta compat
|
||||
.It Sx \&fi Ta 0 Ta current Ta compat
|
||||
.It Sx \&ft Ta 1 Ta current Ta compat
|
||||
.It Sx \&in Ta 1 Ta current Ta compat
|
||||
.It Sx \&na Ta 0 Ta current Ta compat
|
||||
.It Sx \&nf Ta 0 Ta current Ta compat
|
||||
.It Sx \&sp Ta 1 Ta current Ta compat
|
||||
.El
|
||||
.Pp
|
||||
Macros marked as
|
||||
.Qq compat
|
||||
are included for compatibility with the significant corpus of existing
|
||||
manuals that mix dialects of roff.
|
||||
These macros should not be used for portable
|
||||
.Nm
|
||||
manuals.
|
||||
.Ss Block Macros
|
||||
Block macros comprise a head and body.
|
||||
As with in-line macros, the head is scoped to the current line and, in
|
||||
one circumstance, the next line (the next-line stipulations as in
|
||||
.Sx Line Macros
|
||||
apply here as well).
|
||||
.Pp
|
||||
The syntax is as follows:
|
||||
.Bd -literal -offset indent
|
||||
\&.YO \(lBhead...\(rB
|
||||
\(lBhead...\(rB
|
||||
\(lBbody...\(rB
|
||||
.Ed
|
||||
.Pp
|
||||
The closure of body scope may be to the section, where a macro is closed
|
||||
by
|
||||
.Sx \&SH ;
|
||||
sub-section, closed by a section or
|
||||
.Sx \&SS ;
|
||||
part, closed by a section, sub-section, or
|
||||
.Sx \&RE ;
|
||||
or paragraph, closed by a section, sub-section, part,
|
||||
.Sx \&HP ,
|
||||
.Sx \&IP ,
|
||||
.Sx \&LP ,
|
||||
.Sx \&P ,
|
||||
.Sx \&PP ,
|
||||
or
|
||||
.Sx \&TP .
|
||||
No closure refers to an explicit block closing macro.
|
||||
.Pp
|
||||
As a rule, block macros may not be nested; thus, calling a block macro
|
||||
while another block macro scope is open, and the open scope is not
|
||||
implicitly closed, is syntactically incorrect.
|
||||
.Bl -column "MacroX" "ArgumentsX" "Head ScopeX" "sub-sectionX" "compatX" -offset indent
|
||||
.It Em Macro Ta Em Arguments Ta Em Head Scope Ta Em Body Scope Ta Em Notes
|
||||
.It Sx \&HP Ta <2 Ta current Ta paragraph Ta \&
|
||||
.It Sx \&IP Ta <3 Ta current Ta paragraph Ta \&
|
||||
.It Sx \&LP Ta 0 Ta current Ta paragraph Ta \&
|
||||
.It Sx \&P Ta 0 Ta current Ta paragraph Ta \&
|
||||
.It Sx \&PP Ta 0 Ta current Ta paragraph Ta \&
|
||||
.It Sx \&RE Ta 0 Ta current Ta none Ta compat
|
||||
.It Sx \&RS Ta 1 Ta current Ta part Ta compat
|
||||
.It Sx \&SH Ta >0 Ta next-line Ta section Ta \&
|
||||
.It Sx \&SS Ta >0 Ta next-line Ta sub-section Ta \&
|
||||
.It Sx \&TP Ta n Ta next-line Ta paragraph Ta \&
|
||||
.El
|
||||
.Pp
|
||||
Macros marked
|
||||
.Qq compat
|
||||
are as mentioned in
|
||||
.Sx Line Macros .
|
||||
.Pp
|
||||
If a block macro is next-line scoped, it may only be followed by in-line
|
||||
macros for decorating text.
|
||||
.Ss Font handling
|
||||
In
|
||||
.Nm
|
||||
documents, both
|
||||
.Sx Physical markup
|
||||
macros and
|
||||
.Xr roff 7
|
||||
.Ql \ef
|
||||
font escape sequences can be used to choose fonts.
|
||||
In text lines, the effect of manual font selection by escape sequences
|
||||
only lasts until the next macro invocation; in macro lines, it only lasts
|
||||
until the end of the macro scope.
|
||||
Note that macros like
|
||||
.Sx \&BR
|
||||
open and close a font scope for each argument.
|
||||
.Sh COMPATIBILITY
|
||||
This section documents areas of questionable portability between
|
||||
implementations of the
|
||||
.Nm
|
||||
language.
|
||||
.Pp
|
||||
.Bl -dash -compact
|
||||
.It
|
||||
Do not depend on
|
||||
.Sx \&SH
|
||||
or
|
||||
.Sx \&SS
|
||||
to close out a literal context opened with
|
||||
.Sx \&nf .
|
||||
This behaviour may not be portable.
|
||||
.It
|
||||
In quoted literals, GNU troff allowed pair-wise double-quotes to produce
|
||||
a standalone double-quote in formatted output.
|
||||
It is not known whether this behaviour is exhibited by other formatters.
|
||||
.It
|
||||
troff suppresses a newline before
|
||||
.Sq \(aq
|
||||
macro output; in mandoc, it is an alias for the standard
|
||||
.Sq \&.
|
||||
control character.
|
||||
.It
|
||||
The
|
||||
.Sq \eh
|
||||
.Pq horizontal position ,
|
||||
.Sq \ev
|
||||
.Pq vertical position ,
|
||||
.Sq \em
|
||||
.Pq text colour ,
|
||||
.Sq \eM
|
||||
.Pq text filling colour ,
|
||||
.Sq \ez
|
||||
.Pq zero-length character ,
|
||||
.Sq \ew
|
||||
.Pq string length ,
|
||||
.Sq \ek
|
||||
.Pq horizontal position marker ,
|
||||
.Sq \eo
|
||||
.Pq text overstrike ,
|
||||
and
|
||||
.Sq \es
|
||||
.Pq text size
|
||||
escape sequences are all discarded in mandoc.
|
||||
.It
|
||||
The
|
||||
.Sq \ef
|
||||
scaling unit is accepted by mandoc, but rendered as the default unit.
|
||||
.It
|
||||
The
|
||||
.Sx \&sp
|
||||
macro does not accept negative values in mandoc.
|
||||
In GNU troff, this would result in strange behaviour.
|
||||
.It
|
||||
In page header lines, GNU troff versions up to and including 1.21
|
||||
only print
|
||||
.Ar volume
|
||||
names explicitly specified in the
|
||||
.Sx \&TH
|
||||
macro; mandoc and newer groff print the default volume name
|
||||
corresponding to the
|
||||
.Ar section
|
||||
number when no
|
||||
.Ar volume
|
||||
is given, like in
|
||||
.Xr mdoc 7 .
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Sx OP
|
||||
macro is part of the extended
|
||||
.Nm
|
||||
macro set, and may not be portable to non-GNU troff implementations.
|
||||
.Sh SEE ALSO
|
||||
.Xr man 1 ,
|
||||
.Xr mandoc 1 ,
|
||||
.Xr eqn 7 ,
|
||||
.Xr mandoc_char 7 ,
|
||||
.Xr mdoc 7 ,
|
||||
.Xr roff 7 ,
|
||||
.Xr tbl 7
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
language first appeared as a macro package for the roff typesetting
|
||||
system in
|
||||
.At v7 .
|
||||
It was later rewritten by James Clark as a macro package for groff.
|
||||
Eric S. Raymond wrote the extended
|
||||
.Nm
|
||||
macros for groff in 2007.
|
||||
The stand-alone implementation that is part of the
|
||||
.Xr mandoc 1
|
||||
utility written by Kristaps Dzonsons appeared in
|
||||
.Ox 4.6 .
|
||||
.Sh AUTHORS
|
||||
This
|
||||
.Nm
|
||||
reference was written by
|
||||
.An Kristaps Dzonsons ,
|
||||
.Mt kristaps@bsd.lv .
|
||||
.Sh CAVEATS
|
||||
Do not use this language.
|
||||
Use
|
||||
.Xr mdoc 7 ,
|
||||
instead.
|
690
contrib/mdocml/man.c
Normal file
690
contrib/mdocml/man.c
Normal file
@ -0,0 +1,690 @@
|
||||
/* $Id: man.c,v 1.115 2012/01/03 15:16:24 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "man.h"
|
||||
#include "mandoc.h"
|
||||
#include "libman.h"
|
||||
#include "libmandoc.h"
|
||||
|
||||
const char *const __man_macronames[MAN_MAX] = {
|
||||
"br", "TH", "SH", "SS",
|
||||
"TP", "LP", "PP", "P",
|
||||
"IP", "HP", "SM", "SB",
|
||||
"BI", "IB", "BR", "RB",
|
||||
"R", "B", "I", "IR",
|
||||
"RI", "na", "sp", "nf",
|
||||
"fi", "RE", "RS", "DT",
|
||||
"UC", "PD", "AT", "in",
|
||||
"ft", "OP"
|
||||
};
|
||||
|
||||
const char * const *man_macronames = __man_macronames;
|
||||
|
||||
static struct man_node *man_node_alloc(struct man *, int, int,
|
||||
enum man_type, enum mant);
|
||||
static int man_node_append(struct man *,
|
||||
struct man_node *);
|
||||
static void man_node_free(struct man_node *);
|
||||
static void man_node_unlink(struct man *,
|
||||
struct man_node *);
|
||||
static int man_ptext(struct man *, int, char *, int);
|
||||
static int man_pmacro(struct man *, int, char *, int);
|
||||
static void man_free1(struct man *);
|
||||
static void man_alloc1(struct man *);
|
||||
static int man_descope(struct man *, int, int);
|
||||
|
||||
|
||||
const struct man_node *
|
||||
man_node(const struct man *m)
|
||||
{
|
||||
|
||||
assert( ! (MAN_HALT & m->flags));
|
||||
return(m->first);
|
||||
}
|
||||
|
||||
|
||||
const struct man_meta *
|
||||
man_meta(const struct man *m)
|
||||
{
|
||||
|
||||
assert( ! (MAN_HALT & m->flags));
|
||||
return(&m->meta);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
man_reset(struct man *man)
|
||||
{
|
||||
|
||||
man_free1(man);
|
||||
man_alloc1(man);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
man_free(struct man *man)
|
||||
{
|
||||
|
||||
man_free1(man);
|
||||
free(man);
|
||||
}
|
||||
|
||||
|
||||
struct man *
|
||||
man_alloc(struct roff *roff, struct mparse *parse)
|
||||
{
|
||||
struct man *p;
|
||||
|
||||
p = mandoc_calloc(1, sizeof(struct man));
|
||||
|
||||
man_hash_init();
|
||||
p->parse = parse;
|
||||
p->roff = roff;
|
||||
|
||||
man_alloc1(p);
|
||||
return(p);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
man_endparse(struct man *m)
|
||||
{
|
||||
|
||||
assert( ! (MAN_HALT & m->flags));
|
||||
if (man_macroend(m))
|
||||
return(1);
|
||||
m->flags |= MAN_HALT;
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
man_parseln(struct man *m, int ln, char *buf, int offs)
|
||||
{
|
||||
|
||||
m->flags |= MAN_NEWLINE;
|
||||
|
||||
assert( ! (MAN_HALT & m->flags));
|
||||
|
||||
return (mandoc_getcontrol(buf, &offs) ?
|
||||
man_pmacro(m, ln, buf, offs) :
|
||||
man_ptext(m, ln, buf, offs));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
man_free1(struct man *man)
|
||||
{
|
||||
|
||||
if (man->first)
|
||||
man_node_delete(man, man->first);
|
||||
if (man->meta.title)
|
||||
free(man->meta.title);
|
||||
if (man->meta.source)
|
||||
free(man->meta.source);
|
||||
if (man->meta.date)
|
||||
free(man->meta.date);
|
||||
if (man->meta.vol)
|
||||
free(man->meta.vol);
|
||||
if (man->meta.msec)
|
||||
free(man->meta.msec);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
man_alloc1(struct man *m)
|
||||
{
|
||||
|
||||
memset(&m->meta, 0, sizeof(struct man_meta));
|
||||
m->flags = 0;
|
||||
m->last = mandoc_calloc(1, sizeof(struct man_node));
|
||||
m->first = m->last;
|
||||
m->last->type = MAN_ROOT;
|
||||
m->last->tok = MAN_MAX;
|
||||
m->next = MAN_NEXT_CHILD;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
man_node_append(struct man *man, struct man_node *p)
|
||||
{
|
||||
|
||||
assert(man->last);
|
||||
assert(man->first);
|
||||
assert(MAN_ROOT != p->type);
|
||||
|
||||
switch (man->next) {
|
||||
case (MAN_NEXT_SIBLING):
|
||||
man->last->next = p;
|
||||
p->prev = man->last;
|
||||
p->parent = man->last->parent;
|
||||
break;
|
||||
case (MAN_NEXT_CHILD):
|
||||
man->last->child = p;
|
||||
p->parent = man->last;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
assert(p->parent);
|
||||
p->parent->nchild++;
|
||||
|
||||
if ( ! man_valid_pre(man, p))
|
||||
return(0);
|
||||
|
||||
switch (p->type) {
|
||||
case (MAN_HEAD):
|
||||
assert(MAN_BLOCK == p->parent->type);
|
||||
p->parent->head = p;
|
||||
break;
|
||||
case (MAN_TAIL):
|
||||
assert(MAN_BLOCK == p->parent->type);
|
||||
p->parent->tail = p;
|
||||
break;
|
||||
case (MAN_BODY):
|
||||
assert(MAN_BLOCK == p->parent->type);
|
||||
p->parent->body = p;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
man->last = p;
|
||||
|
||||
switch (p->type) {
|
||||
case (MAN_TBL):
|
||||
/* FALLTHROUGH */
|
||||
case (MAN_TEXT):
|
||||
if ( ! man_valid_post(man))
|
||||
return(0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
static struct man_node *
|
||||
man_node_alloc(struct man *m, int line, int pos,
|
||||
enum man_type type, enum mant tok)
|
||||
{
|
||||
struct man_node *p;
|
||||
|
||||
p = mandoc_calloc(1, sizeof(struct man_node));
|
||||
p->line = line;
|
||||
p->pos = pos;
|
||||
p->type = type;
|
||||
p->tok = tok;
|
||||
|
||||
if (MAN_NEWLINE & m->flags)
|
||||
p->flags |= MAN_LINE;
|
||||
m->flags &= ~MAN_NEWLINE;
|
||||
return(p);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
man_elem_alloc(struct man *m, int line, int pos, enum mant tok)
|
||||
{
|
||||
struct man_node *p;
|
||||
|
||||
p = man_node_alloc(m, line, pos, MAN_ELEM, tok);
|
||||
if ( ! man_node_append(m, p))
|
||||
return(0);
|
||||
m->next = MAN_NEXT_CHILD;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
man_tail_alloc(struct man *m, int line, int pos, enum mant tok)
|
||||
{
|
||||
struct man_node *p;
|
||||
|
||||
p = man_node_alloc(m, line, pos, MAN_TAIL, tok);
|
||||
if ( ! man_node_append(m, p))
|
||||
return(0);
|
||||
m->next = MAN_NEXT_CHILD;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
man_head_alloc(struct man *m, int line, int pos, enum mant tok)
|
||||
{
|
||||
struct man_node *p;
|
||||
|
||||
p = man_node_alloc(m, line, pos, MAN_HEAD, tok);
|
||||
if ( ! man_node_append(m, p))
|
||||
return(0);
|
||||
m->next = MAN_NEXT_CHILD;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
man_body_alloc(struct man *m, int line, int pos, enum mant tok)
|
||||
{
|
||||
struct man_node *p;
|
||||
|
||||
p = man_node_alloc(m, line, pos, MAN_BODY, tok);
|
||||
if ( ! man_node_append(m, p))
|
||||
return(0);
|
||||
m->next = MAN_NEXT_CHILD;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
man_block_alloc(struct man *m, int line, int pos, enum mant tok)
|
||||
{
|
||||
struct man_node *p;
|
||||
|
||||
p = man_node_alloc(m, line, pos, MAN_BLOCK, tok);
|
||||
if ( ! man_node_append(m, p))
|
||||
return(0);
|
||||
m->next = MAN_NEXT_CHILD;
|
||||
return(1);
|
||||
}
|
||||
|
||||
int
|
||||
man_word_alloc(struct man *m, int line, int pos, const char *word)
|
||||
{
|
||||
struct man_node *n;
|
||||
|
||||
n = man_node_alloc(m, line, pos, MAN_TEXT, MAN_MAX);
|
||||
n->string = roff_strdup(m->roff, word);
|
||||
|
||||
if ( ! man_node_append(m, n))
|
||||
return(0);
|
||||
|
||||
m->next = MAN_NEXT_SIBLING;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Free all of the resources held by a node. This does NOT unlink a
|
||||
* node from its context; for that, see man_node_unlink().
|
||||
*/
|
||||
static void
|
||||
man_node_free(struct man_node *p)
|
||||
{
|
||||
|
||||
if (p->string)
|
||||
free(p->string);
|
||||
free(p);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
man_node_delete(struct man *m, struct man_node *p)
|
||||
{
|
||||
|
||||
while (p->child)
|
||||
man_node_delete(m, p->child);
|
||||
|
||||
man_node_unlink(m, p);
|
||||
man_node_free(p);
|
||||
}
|
||||
|
||||
int
|
||||
man_addeqn(struct man *m, const struct eqn *ep)
|
||||
{
|
||||
struct man_node *n;
|
||||
|
||||
assert( ! (MAN_HALT & m->flags));
|
||||
|
||||
n = man_node_alloc(m, ep->ln, ep->pos, MAN_EQN, MAN_MAX);
|
||||
n->eqn = ep;
|
||||
|
||||
if ( ! man_node_append(m, n))
|
||||
return(0);
|
||||
|
||||
m->next = MAN_NEXT_SIBLING;
|
||||
return(man_descope(m, ep->ln, ep->pos));
|
||||
}
|
||||
|
||||
int
|
||||
man_addspan(struct man *m, const struct tbl_span *sp)
|
||||
{
|
||||
struct man_node *n;
|
||||
|
||||
assert( ! (MAN_HALT & m->flags));
|
||||
|
||||
n = man_node_alloc(m, sp->line, 0, MAN_TBL, MAN_MAX);
|
||||
n->span = sp;
|
||||
|
||||
if ( ! man_node_append(m, n))
|
||||
return(0);
|
||||
|
||||
m->next = MAN_NEXT_SIBLING;
|
||||
return(man_descope(m, sp->line, 0));
|
||||
}
|
||||
|
||||
static int
|
||||
man_descope(struct man *m, int line, int offs)
|
||||
{
|
||||
/*
|
||||
* Co-ordinate what happens with having a next-line scope open:
|
||||
* first close out the element scope (if applicable), then close
|
||||
* out the block scope (also if applicable).
|
||||
*/
|
||||
|
||||
if (MAN_ELINE & m->flags) {
|
||||
m->flags &= ~MAN_ELINE;
|
||||
if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX))
|
||||
return(0);
|
||||
}
|
||||
|
||||
if ( ! (MAN_BLINE & m->flags))
|
||||
return(1);
|
||||
m->flags &= ~MAN_BLINE;
|
||||
|
||||
if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX))
|
||||
return(0);
|
||||
return(man_body_alloc(m, line, offs, m->last->tok));
|
||||
}
|
||||
|
||||
static int
|
||||
man_ptext(struct man *m, int line, char *buf, int offs)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Literal free-form text whitespace is preserved. */
|
||||
|
||||
if (MAN_LITERAL & m->flags) {
|
||||
if ( ! man_word_alloc(m, line, offs, buf + offs))
|
||||
return(0);
|
||||
return(man_descope(m, line, offs));
|
||||
}
|
||||
|
||||
/* Pump blank lines directly into the backend. */
|
||||
|
||||
for (i = offs; ' ' == buf[i]; i++)
|
||||
/* Skip leading whitespace. */ ;
|
||||
|
||||
if ('\0' == buf[i]) {
|
||||
/* Allocate a blank entry. */
|
||||
if ( ! man_word_alloc(m, line, offs, ""))
|
||||
return(0);
|
||||
return(man_descope(m, line, offs));
|
||||
}
|
||||
|
||||
/*
|
||||
* Warn if the last un-escaped character is whitespace. Then
|
||||
* strip away the remaining spaces (tabs stay!).
|
||||
*/
|
||||
|
||||
i = (int)strlen(buf);
|
||||
assert(i);
|
||||
|
||||
if (' ' == buf[i - 1] || '\t' == buf[i - 1]) {
|
||||
if (i > 1 && '\\' != buf[i - 2])
|
||||
man_pmsg(m, line, i - 1, MANDOCERR_EOLNSPACE);
|
||||
|
||||
for (--i; i && ' ' == buf[i]; i--)
|
||||
/* Spin back to non-space. */ ;
|
||||
|
||||
/* Jump ahead of escaped whitespace. */
|
||||
i += '\\' == buf[i] ? 2 : 1;
|
||||
|
||||
buf[i] = '\0';
|
||||
}
|
||||
|
||||
if ( ! man_word_alloc(m, line, offs, buf + offs))
|
||||
return(0);
|
||||
|
||||
/*
|
||||
* End-of-sentence check. If the last character is an unescaped
|
||||
* EOS character, then flag the node as being the end of a
|
||||
* sentence. The front-end will know how to interpret this.
|
||||
*/
|
||||
|
||||
assert(i);
|
||||
if (mandoc_eos(buf, (size_t)i, 0))
|
||||
m->last->flags |= MAN_EOS;
|
||||
|
||||
return(man_descope(m, line, offs));
|
||||
}
|
||||
|
||||
static int
|
||||
man_pmacro(struct man *m, int ln, char *buf, int offs)
|
||||
{
|
||||
int i, ppos;
|
||||
enum mant tok;
|
||||
char mac[5];
|
||||
struct man_node *n;
|
||||
|
||||
if ('"' == buf[offs]) {
|
||||
man_pmsg(m, ln, offs, MANDOCERR_BADCOMMENT);
|
||||
return(1);
|
||||
} else if ('\0' == buf[offs])
|
||||
return(1);
|
||||
|
||||
ppos = offs;
|
||||
|
||||
/*
|
||||
* Copy the first word into a nil-terminated buffer.
|
||||
* Stop copying when a tab, space, or eoln is encountered.
|
||||
*/
|
||||
|
||||
i = 0;
|
||||
while (i < 4 && '\0' != buf[offs] &&
|
||||
' ' != buf[offs] && '\t' != buf[offs])
|
||||
mac[i++] = buf[offs++];
|
||||
|
||||
mac[i] = '\0';
|
||||
|
||||
tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX;
|
||||
|
||||
if (MAN_MAX == tok) {
|
||||
mandoc_vmsg(MANDOCERR_MACRO, m->parse, ln,
|
||||
ppos, "%s", buf + ppos - 1);
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* The macro is sane. Jump to the next word. */
|
||||
|
||||
while (buf[offs] && ' ' == buf[offs])
|
||||
offs++;
|
||||
|
||||
/*
|
||||
* Trailing whitespace. Note that tabs are allowed to be passed
|
||||
* into the parser as "text", so we only warn about spaces here.
|
||||
*/
|
||||
|
||||
if ('\0' == buf[offs] && ' ' == buf[offs - 1])
|
||||
man_pmsg(m, ln, offs - 1, MANDOCERR_EOLNSPACE);
|
||||
|
||||
/*
|
||||
* Remove prior ELINE macro, as it's being clobbered by a new
|
||||
* macro. Note that NSCOPED macros do not close out ELINE
|
||||
* macros---they don't print text---so we let those slip by.
|
||||
*/
|
||||
|
||||
if ( ! (MAN_NSCOPED & man_macros[tok].flags) &&
|
||||
m->flags & MAN_ELINE) {
|
||||
n = m->last;
|
||||
assert(MAN_TEXT != n->type);
|
||||
|
||||
/* Remove repeated NSCOPED macros causing ELINE. */
|
||||
|
||||
if (MAN_NSCOPED & man_macros[n->tok].flags)
|
||||
n = n->parent;
|
||||
|
||||
mandoc_vmsg(MANDOCERR_LINESCOPE, m->parse, n->line,
|
||||
n->pos, "%s breaks %s", man_macronames[tok],
|
||||
man_macronames[n->tok]);
|
||||
|
||||
man_node_delete(m, n);
|
||||
m->flags &= ~MAN_ELINE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove prior BLINE macro that is being clobbered.
|
||||
*/
|
||||
if ((m->flags & MAN_BLINE) &&
|
||||
(MAN_BSCOPE & man_macros[tok].flags)) {
|
||||
n = m->last;
|
||||
|
||||
/* Might be a text node like 8 in
|
||||
* .TP 8
|
||||
* .SH foo
|
||||
*/
|
||||
if (MAN_TEXT == n->type)
|
||||
n = n->parent;
|
||||
|
||||
/* Remove element that didn't end BLINE, if any. */
|
||||
if ( ! (MAN_BSCOPE & man_macros[n->tok].flags))
|
||||
n = n->parent;
|
||||
|
||||
assert(MAN_HEAD == n->type);
|
||||
n = n->parent;
|
||||
assert(MAN_BLOCK == n->type);
|
||||
assert(MAN_SCOPED & man_macros[n->tok].flags);
|
||||
|
||||
mandoc_vmsg(MANDOCERR_LINESCOPE, m->parse, n->line,
|
||||
n->pos, "%s breaks %s", man_macronames[tok],
|
||||
man_macronames[n->tok]);
|
||||
|
||||
man_node_delete(m, n);
|
||||
m->flags &= ~MAN_BLINE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the fact that we're in the next-line for a block. In
|
||||
* this way, embedded roff instructions can "remember" state
|
||||
* when they exit.
|
||||
*/
|
||||
|
||||
if (MAN_BLINE & m->flags)
|
||||
m->flags |= MAN_BPLINE;
|
||||
|
||||
/* Call to handler... */
|
||||
|
||||
assert(man_macros[tok].fp);
|
||||
if ( ! (*man_macros[tok].fp)(m, tok, ln, ppos, &offs, buf))
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* We weren't in a block-line scope when entering the
|
||||
* above-parsed macro, so return.
|
||||
*/
|
||||
|
||||
if ( ! (MAN_BPLINE & m->flags)) {
|
||||
m->flags &= ~MAN_ILINE;
|
||||
return(1);
|
||||
}
|
||||
m->flags &= ~MAN_BPLINE;
|
||||
|
||||
/*
|
||||
* If we're in a block scope, then allow this macro to slip by
|
||||
* without closing scope around it.
|
||||
*/
|
||||
|
||||
if (MAN_ILINE & m->flags) {
|
||||
m->flags &= ~MAN_ILINE;
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we've opened a new next-line element scope, then return
|
||||
* now, as the next line will close out the block scope.
|
||||
*/
|
||||
|
||||
if (MAN_ELINE & m->flags)
|
||||
return(1);
|
||||
|
||||
/* Close out the block scope opened in the prior line. */
|
||||
|
||||
assert(MAN_BLINE & m->flags);
|
||||
m->flags &= ~MAN_BLINE;
|
||||
|
||||
if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX))
|
||||
return(0);
|
||||
return(man_body_alloc(m, ln, ppos, m->last->tok));
|
||||
|
||||
err: /* Error out. */
|
||||
|
||||
m->flags |= MAN_HALT;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unlink a node from its context. If "m" is provided, the last parse
|
||||
* point will also be adjusted accordingly.
|
||||
*/
|
||||
static void
|
||||
man_node_unlink(struct man *m, struct man_node *n)
|
||||
{
|
||||
|
||||
/* Adjust siblings. */
|
||||
|
||||
if (n->prev)
|
||||
n->prev->next = n->next;
|
||||
if (n->next)
|
||||
n->next->prev = n->prev;
|
||||
|
||||
/* Adjust parent. */
|
||||
|
||||
if (n->parent) {
|
||||
n->parent->nchild--;
|
||||
if (n->parent->child == n)
|
||||
n->parent->child = n->prev ? n->prev : n->next;
|
||||
}
|
||||
|
||||
/* Adjust parse point, if applicable. */
|
||||
|
||||
if (m && m->last == n) {
|
||||
/*XXX: this can occur when bailing from validation. */
|
||||
/*assert(NULL == n->next);*/
|
||||
if (n->prev) {
|
||||
m->last = n->prev;
|
||||
m->next = MAN_NEXT_SIBLING;
|
||||
} else {
|
||||
m->last = n->parent;
|
||||
m->next = MAN_NEXT_CHILD;
|
||||
}
|
||||
}
|
||||
|
||||
if (m && m->first == n)
|
||||
m->first = NULL;
|
||||
}
|
||||
|
||||
const struct mparse *
|
||||
man_mparse(const struct man *m)
|
||||
{
|
||||
|
||||
assert(m && m->parse);
|
||||
return(m->parse);
|
||||
}
|
113
contrib/mdocml/man.h
Normal file
113
contrib/mdocml/man.h
Normal file
@ -0,0 +1,113 @@
|
||||
/* $Id: man.h,v 1.60 2012/01/03 15:16:24 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 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 MAN_H
|
||||
#define MAN_H
|
||||
|
||||
enum mant {
|
||||
MAN_br = 0,
|
||||
MAN_TH,
|
||||
MAN_SH,
|
||||
MAN_SS,
|
||||
MAN_TP,
|
||||
MAN_LP,
|
||||
MAN_PP,
|
||||
MAN_P,
|
||||
MAN_IP,
|
||||
MAN_HP,
|
||||
MAN_SM,
|
||||
MAN_SB,
|
||||
MAN_BI,
|
||||
MAN_IB,
|
||||
MAN_BR,
|
||||
MAN_RB,
|
||||
MAN_R,
|
||||
MAN_B,
|
||||
MAN_I,
|
||||
MAN_IR,
|
||||
MAN_RI,
|
||||
MAN_na,
|
||||
MAN_sp,
|
||||
MAN_nf,
|
||||
MAN_fi,
|
||||
MAN_RE,
|
||||
MAN_RS,
|
||||
MAN_DT,
|
||||
MAN_UC,
|
||||
MAN_PD,
|
||||
MAN_AT,
|
||||
MAN_in,
|
||||
MAN_ft,
|
||||
MAN_OP,
|
||||
MAN_MAX
|
||||
};
|
||||
|
||||
enum man_type {
|
||||
MAN_TEXT,
|
||||
MAN_ELEM,
|
||||
MAN_ROOT,
|
||||
MAN_BLOCK,
|
||||
MAN_HEAD,
|
||||
MAN_BODY,
|
||||
MAN_TAIL,
|
||||
MAN_TBL,
|
||||
MAN_EQN
|
||||
};
|
||||
|
||||
struct man_meta {
|
||||
char *msec; /* `TH' section (1, 3p, etc.) */
|
||||
char *date; /* `TH' normalised date */
|
||||
char *vol; /* `TH' volume */
|
||||
char *title; /* `TH' title (e.g., FOO) */
|
||||
char *source; /* `TH' source (e.g., GNU) */
|
||||
};
|
||||
|
||||
struct man_node {
|
||||
struct man_node *parent; /* parent AST node */
|
||||
struct man_node *child; /* first child AST node */
|
||||
struct man_node *next; /* sibling AST node */
|
||||
struct man_node *prev; /* prior sibling AST node */
|
||||
int nchild; /* number children */
|
||||
int line;
|
||||
int pos;
|
||||
enum mant tok; /* tok or MAN__MAX if none */
|
||||
int flags;
|
||||
#define MAN_VALID (1 << 0) /* has been validated */
|
||||
#define MAN_EOS (1 << 2) /* at sentence boundary */
|
||||
#define MAN_LINE (1 << 3) /* first macro/text on line */
|
||||
enum man_type type; /* AST node type */
|
||||
char *string; /* TEXT node argument */
|
||||
struct man_node *head; /* BLOCK node HEAD ptr */
|
||||
struct man_node *tail; /* BLOCK node TAIL ptr */
|
||||
struct man_node *body; /* BLOCK node BODY ptr */
|
||||
const struct tbl_span *span; /* TBL */
|
||||
const struct eqn *eqn; /* EQN */
|
||||
};
|
||||
|
||||
/* Names of macros. Index is enum mant. */
|
||||
extern const char *const *man_macronames;
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
struct man;
|
||||
|
||||
const struct man_node *man_node(const struct man *);
|
||||
const struct man_meta *man_meta(const struct man *);
|
||||
const struct mparse *man_mparse(const struct man *);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /*!MAN_H*/
|
107
contrib/mdocml/man_hash.c
Normal file
107
contrib/mdocml/man_hash.c
Normal file
@ -0,0 +1,107 @@
|
||||
/* $Id: man_hash.c,v 1.25 2011/07/24 18:15:14 kristaps Exp $ */
|
||||
/*
|
||||
* 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
|
||||
* 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "man.h"
|
||||
#include "mandoc.h"
|
||||
#include "libman.h"
|
||||
|
||||
#define HASH_DEPTH 6
|
||||
|
||||
#define HASH_ROW(x) do { \
|
||||
if (isupper((unsigned char)(x))) \
|
||||
(x) -= 65; \
|
||||
else \
|
||||
(x) -= 97; \
|
||||
(x) *= HASH_DEPTH; \
|
||||
} while (/* CONSTCOND */ 0)
|
||||
|
||||
/*
|
||||
* Lookup table is indexed first by lower-case first letter (plus one
|
||||
* for the period, which is stored in the last row), then by lower or
|
||||
* uppercase second letter. Buckets correspond to the index of the
|
||||
* macro (the integer value of the enum stored as a char to save a bit
|
||||
* of space).
|
||||
*/
|
||||
static unsigned char table[26 * HASH_DEPTH];
|
||||
|
||||
/*
|
||||
* XXX - this hash has global scope, so if intended for use as a library
|
||||
* with multiple callers, it will need re-invocation protection.
|
||||
*/
|
||||
void
|
||||
man_hash_init(void)
|
||||
{
|
||||
int i, j, x;
|
||||
|
||||
memset(table, UCHAR_MAX, sizeof(table));
|
||||
|
||||
assert(/* LINTED */
|
||||
MAN_MAX < UCHAR_MAX);
|
||||
|
||||
for (i = 0; i < (int)MAN_MAX; i++) {
|
||||
x = man_macronames[i][0];
|
||||
|
||||
assert(isalpha((unsigned char)x));
|
||||
|
||||
HASH_ROW(x);
|
||||
|
||||
for (j = 0; j < HASH_DEPTH; j++)
|
||||
if (UCHAR_MAX == table[x + j]) {
|
||||
table[x + j] = (unsigned char)i;
|
||||
break;
|
||||
}
|
||||
|
||||
assert(j < HASH_DEPTH);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum mant
|
||||
man_hash_find(const char *tmp)
|
||||
{
|
||||
int x, y, i;
|
||||
enum mant tok;
|
||||
|
||||
if ('\0' == (x = tmp[0]))
|
||||
return(MAN_MAX);
|
||||
if ( ! (isalpha((unsigned char)x)))
|
||||
return(MAN_MAX);
|
||||
|
||||
HASH_ROW(x);
|
||||
|
||||
for (i = 0; i < HASH_DEPTH; i++) {
|
||||
if (UCHAR_MAX == (y = table[x + i]))
|
||||
return(MAN_MAX);
|
||||
|
||||
tok = (enum mant)y;
|
||||
if (0 == strcmp(tmp, man_macronames[tok]))
|
||||
return(tok);
|
||||
}
|
||||
|
||||
return(MAN_MAX);
|
||||
}
|
688
contrib/mdocml/man_html.c
Normal file
688
contrib/mdocml/man_html.c
Normal file
@ -0,0 +1,688 @@
|
||||
/* $Id: man_html.c,v 1.86 2012/01/03 15:16:24 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "out.h"
|
||||
#include "html.h"
|
||||
#include "man.h"
|
||||
#include "main.h"
|
||||
|
||||
/* TODO: preserve ident widths. */
|
||||
/* FIXME: have PD set the default vspace width. */
|
||||
|
||||
#define INDENT 5
|
||||
|
||||
#define MAN_ARGS const struct man_meta *m, \
|
||||
const struct man_node *n, \
|
||||
struct mhtml *mh, \
|
||||
struct html *h
|
||||
|
||||
struct mhtml {
|
||||
int fl;
|
||||
#define MANH_LITERAL (1 << 0) /* literal context */
|
||||
};
|
||||
|
||||
struct htmlman {
|
||||
int (*pre)(MAN_ARGS);
|
||||
int (*post)(MAN_ARGS);
|
||||
};
|
||||
|
||||
static void print_bvspace(struct html *,
|
||||
const struct man_node *);
|
||||
static void print_man(MAN_ARGS);
|
||||
static void print_man_head(MAN_ARGS);
|
||||
static void print_man_nodelist(MAN_ARGS);
|
||||
static void print_man_node(MAN_ARGS);
|
||||
static int a2width(const struct man_node *,
|
||||
struct roffsu *);
|
||||
static int man_B_pre(MAN_ARGS);
|
||||
static int man_HP_pre(MAN_ARGS);
|
||||
static int man_IP_pre(MAN_ARGS);
|
||||
static int man_I_pre(MAN_ARGS);
|
||||
static int man_OP_pre(MAN_ARGS);
|
||||
static int man_PP_pre(MAN_ARGS);
|
||||
static int man_RS_pre(MAN_ARGS);
|
||||
static int man_SH_pre(MAN_ARGS);
|
||||
static int man_SM_pre(MAN_ARGS);
|
||||
static int man_SS_pre(MAN_ARGS);
|
||||
static int man_alt_pre(MAN_ARGS);
|
||||
static int man_br_pre(MAN_ARGS);
|
||||
static int man_ign_pre(MAN_ARGS);
|
||||
static int man_in_pre(MAN_ARGS);
|
||||
static int man_literal_pre(MAN_ARGS);
|
||||
static void man_root_post(MAN_ARGS);
|
||||
static void man_root_pre(MAN_ARGS);
|
||||
|
||||
static const struct htmlman mans[MAN_MAX] = {
|
||||
{ man_br_pre, NULL }, /* br */
|
||||
{ NULL, NULL }, /* TH */
|
||||
{ man_SH_pre, NULL }, /* SH */
|
||||
{ man_SS_pre, NULL }, /* SS */
|
||||
{ man_IP_pre, NULL }, /* TP */
|
||||
{ man_PP_pre, NULL }, /* LP */
|
||||
{ man_PP_pre, NULL }, /* PP */
|
||||
{ man_PP_pre, NULL }, /* P */
|
||||
{ man_IP_pre, NULL }, /* IP */
|
||||
{ man_HP_pre, NULL }, /* HP */
|
||||
{ man_SM_pre, NULL }, /* SM */
|
||||
{ man_SM_pre, NULL }, /* SB */
|
||||
{ man_alt_pre, NULL }, /* BI */
|
||||
{ man_alt_pre, NULL }, /* IB */
|
||||
{ man_alt_pre, NULL }, /* BR */
|
||||
{ man_alt_pre, NULL }, /* RB */
|
||||
{ NULL, NULL }, /* R */
|
||||
{ man_B_pre, NULL }, /* B */
|
||||
{ man_I_pre, NULL }, /* I */
|
||||
{ man_alt_pre, NULL }, /* IR */
|
||||
{ man_alt_pre, NULL }, /* RI */
|
||||
{ man_ign_pre, NULL }, /* na */
|
||||
{ man_br_pre, NULL }, /* sp */
|
||||
{ man_literal_pre, NULL }, /* nf */
|
||||
{ man_literal_pre, NULL }, /* fi */
|
||||
{ NULL, NULL }, /* RE */
|
||||
{ man_RS_pre, NULL }, /* RS */
|
||||
{ man_ign_pre, NULL }, /* DT */
|
||||
{ man_ign_pre, NULL }, /* UC */
|
||||
{ man_ign_pre, NULL }, /* PD */
|
||||
{ man_ign_pre, NULL }, /* AT */
|
||||
{ man_in_pre, NULL }, /* in */
|
||||
{ man_ign_pre, NULL }, /* ft */
|
||||
{ man_OP_pre, NULL }, /* OP */
|
||||
};
|
||||
|
||||
/*
|
||||
* Printing leading vertical space before a block.
|
||||
* This is used for the paragraph macros.
|
||||
* The rules are pretty simple, since there's very little nesting going
|
||||
* on here. Basically, if we're the first within another block (SS/SH),
|
||||
* then don't emit vertical space. If we are (RS), then do. If not the
|
||||
* first, print it.
|
||||
*/
|
||||
static void
|
||||
print_bvspace(struct html *h, const struct man_node *n)
|
||||
{
|
||||
|
||||
if (n->body && n->body->child)
|
||||
if (MAN_TBL == n->body->child->type)
|
||||
return;
|
||||
|
||||
if (MAN_ROOT == n->parent->type || MAN_RS != n->parent->tok)
|
||||
if (NULL == n->prev)
|
||||
return;
|
||||
|
||||
print_otag(h, TAG_P, 0, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
html_man(void *arg, const struct man *m)
|
||||
{
|
||||
struct mhtml mh;
|
||||
|
||||
memset(&mh, 0, sizeof(struct mhtml));
|
||||
print_man(man_meta(m), man_node(m), &mh, (struct html *)arg);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
static void
|
||||
print_man(MAN_ARGS)
|
||||
{
|
||||
struct tag *t, *tt;
|
||||
struct htmlpair tag;
|
||||
|
||||
PAIR_CLASS_INIT(&tag, "mandoc");
|
||||
|
||||
if ( ! (HTML_FRAGMENT & h->oflags)) {
|
||||
print_gen_decls(h);
|
||||
t = print_otag(h, TAG_HTML, 0, NULL);
|
||||
tt = print_otag(h, TAG_HEAD, 0, NULL);
|
||||
print_man_head(m, n, mh, h);
|
||||
print_tagq(h, tt);
|
||||
print_otag(h, TAG_BODY, 0, NULL);
|
||||
print_otag(h, TAG_DIV, 1, &tag);
|
||||
} else
|
||||
t = print_otag(h, TAG_DIV, 1, &tag);
|
||||
|
||||
print_man_nodelist(m, n, mh, h);
|
||||
print_tagq(h, t);
|
||||
}
|
||||
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
print_man_head(MAN_ARGS)
|
||||
{
|
||||
|
||||
print_gen_head(h);
|
||||
assert(m->title);
|
||||
assert(m->msec);
|
||||
bufcat_fmt(h, "%s(%s)", m->title, m->msec);
|
||||
print_otag(h, TAG_TITLE, 0, NULL);
|
||||
print_text(h, h->buf);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
print_man_nodelist(MAN_ARGS)
|
||||
{
|
||||
|
||||
print_man_node(m, n, mh, h);
|
||||
if (n->next)
|
||||
print_man_nodelist(m, n->next, mh, h);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
print_man_node(MAN_ARGS)
|
||||
{
|
||||
int child;
|
||||
struct tag *t;
|
||||
|
||||
child = 1;
|
||||
t = h->tags.head;
|
||||
|
||||
switch (n->type) {
|
||||
case (MAN_ROOT):
|
||||
man_root_pre(m, n, mh, h);
|
||||
break;
|
||||
case (MAN_TEXT):
|
||||
/*
|
||||
* If we have a blank line, output a vertical space.
|
||||
* If we have a space as the first character, break
|
||||
* before printing the line's data.
|
||||
*/
|
||||
if ('\0' == *n->string) {
|
||||
print_otag(h, TAG_P, 0, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (' ' == *n->string && MAN_LINE & n->flags)
|
||||
print_otag(h, TAG_BR, 0, NULL);
|
||||
else if (MANH_LITERAL & mh->fl && n->prev)
|
||||
print_otag(h, TAG_BR, 0, NULL);
|
||||
|
||||
print_text(h, n->string);
|
||||
return;
|
||||
case (MAN_EQN):
|
||||
print_eqn(h, n->eqn);
|
||||
break;
|
||||
case (MAN_TBL):
|
||||
/*
|
||||
* This will take care of initialising all of the table
|
||||
* state data for the first table, then tearing it down
|
||||
* for the last one.
|
||||
*/
|
||||
print_tbl(h, n->span);
|
||||
return;
|
||||
default:
|
||||
/*
|
||||
* Close out scope of font prior to opening a macro
|
||||
* scope.
|
||||
*/
|
||||
if (HTMLFONT_NONE != h->metac) {
|
||||
h->metal = h->metac;
|
||||
h->metac = HTMLFONT_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Close out the current table, if it's open, and unset
|
||||
* the "meta" table state. This will be reopened on the
|
||||
* next table element.
|
||||
*/
|
||||
if (h->tblt) {
|
||||
print_tblclose(h);
|
||||
t = h->tags.head;
|
||||
}
|
||||
if (mans[n->tok].pre)
|
||||
child = (*mans[n->tok].pre)(m, n, mh, h);
|
||||
break;
|
||||
}
|
||||
|
||||
if (child && n->child)
|
||||
print_man_nodelist(m, n->child, mh, h);
|
||||
|
||||
/* This will automatically close out any font scope. */
|
||||
print_stagq(h, t);
|
||||
|
||||
switch (n->type) {
|
||||
case (MAN_ROOT):
|
||||
man_root_post(m, n, mh, h);
|
||||
break;
|
||||
case (MAN_EQN):
|
||||
break;
|
||||
default:
|
||||
if (mans[n->tok].post)
|
||||
(*mans[n->tok].post)(m, n, mh, h);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
a2width(const struct man_node *n, struct roffsu *su)
|
||||
{
|
||||
|
||||
if (MAN_TEXT != n->type)
|
||||
return(0);
|
||||
if (a2roffsu(n->string, su, SCALE_BU))
|
||||
return(1);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
man_root_pre(MAN_ARGS)
|
||||
{
|
||||
struct htmlpair tag[3];
|
||||
struct tag *t, *tt;
|
||||
char b[BUFSIZ], title[BUFSIZ];
|
||||
|
||||
b[0] = 0;
|
||||
if (m->vol)
|
||||
(void)strlcat(b, m->vol, BUFSIZ);
|
||||
|
||||
assert(m->title);
|
||||
assert(m->msec);
|
||||
snprintf(title, BUFSIZ - 1, "%s(%s)", m->title, m->msec);
|
||||
|
||||
PAIR_SUMMARY_INIT(&tag[0], "Document Header");
|
||||
PAIR_CLASS_INIT(&tag[1], "head");
|
||||
PAIR_INIT(&tag[2], ATTR_WIDTH, "100%");
|
||||
t = print_otag(h, TAG_TABLE, 3, tag);
|
||||
PAIR_INIT(&tag[0], ATTR_WIDTH, "30%");
|
||||
print_otag(h, TAG_COL, 1, tag);
|
||||
print_otag(h, TAG_COL, 1, tag);
|
||||
print_otag(h, TAG_COL, 1, tag);
|
||||
|
||||
print_otag(h, TAG_TBODY, 0, NULL);
|
||||
|
||||
tt = print_otag(h, TAG_TR, 0, NULL);
|
||||
|
||||
PAIR_CLASS_INIT(&tag[0], "head-ltitle");
|
||||
print_otag(h, TAG_TD, 1, tag);
|
||||
print_text(h, title);
|
||||
print_stagq(h, tt);
|
||||
|
||||
PAIR_CLASS_INIT(&tag[0], "head-vol");
|
||||
PAIR_INIT(&tag[1], ATTR_ALIGN, "center");
|
||||
print_otag(h, TAG_TD, 2, tag);
|
||||
print_text(h, b);
|
||||
print_stagq(h, tt);
|
||||
|
||||
PAIR_CLASS_INIT(&tag[0], "head-rtitle");
|
||||
PAIR_INIT(&tag[1], ATTR_ALIGN, "right");
|
||||
print_otag(h, TAG_TD, 2, tag);
|
||||
print_text(h, title);
|
||||
print_tagq(h, t);
|
||||
}
|
||||
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
man_root_post(MAN_ARGS)
|
||||
{
|
||||
struct htmlpair tag[3];
|
||||
struct tag *t, *tt;
|
||||
|
||||
PAIR_SUMMARY_INIT(&tag[0], "Document Footer");
|
||||
PAIR_CLASS_INIT(&tag[1], "foot");
|
||||
PAIR_INIT(&tag[2], ATTR_WIDTH, "100%");
|
||||
t = print_otag(h, TAG_TABLE, 3, tag);
|
||||
PAIR_INIT(&tag[0], ATTR_WIDTH, "50%");
|
||||
print_otag(h, TAG_COL, 1, tag);
|
||||
print_otag(h, TAG_COL, 1, tag);
|
||||
|
||||
tt = print_otag(h, TAG_TR, 0, NULL);
|
||||
|
||||
PAIR_CLASS_INIT(&tag[0], "foot-date");
|
||||
print_otag(h, TAG_TD, 1, tag);
|
||||
|
||||
assert(m->date);
|
||||
print_text(h, m->date);
|
||||
print_stagq(h, tt);
|
||||
|
||||
PAIR_CLASS_INIT(&tag[0], "foot-os");
|
||||
PAIR_INIT(&tag[1], ATTR_ALIGN, "right");
|
||||
print_otag(h, TAG_TD, 2, tag);
|
||||
|
||||
if (m->source)
|
||||
print_text(h, m->source);
|
||||
print_tagq(h, t);
|
||||
}
|
||||
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
man_br_pre(MAN_ARGS)
|
||||
{
|
||||
struct roffsu su;
|
||||
struct htmlpair tag;
|
||||
|
||||
SCALE_VS_INIT(&su, 1);
|
||||
|
||||
if (MAN_sp == n->tok) {
|
||||
if (NULL != (n = n->child))
|
||||
if ( ! a2roffsu(n->string, &su, SCALE_VS))
|
||||
SCALE_VS_INIT(&su, atoi(n->string));
|
||||
} else
|
||||
su.scale = 0;
|
||||
|
||||
bufinit(h);
|
||||
bufcat_su(h, "height", &su);
|
||||
PAIR_STYLE_INIT(&tag, h);
|
||||
print_otag(h, TAG_DIV, 1, &tag);
|
||||
|
||||
/* So the div isn't empty: */
|
||||
print_text(h, "\\~");
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
man_SH_pre(MAN_ARGS)
|
||||
{
|
||||
struct htmlpair tag;
|
||||
|
||||
if (MAN_BLOCK == n->type) {
|
||||
mh->fl &= ~MANH_LITERAL;
|
||||
PAIR_CLASS_INIT(&tag, "section");
|
||||
print_otag(h, TAG_DIV, 1, &tag);
|
||||
return(1);
|
||||
} else if (MAN_BODY == n->type)
|
||||
return(1);
|
||||
|
||||
print_otag(h, TAG_H1, 0, NULL);
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
man_alt_pre(MAN_ARGS)
|
||||
{
|
||||
const struct man_node *nn;
|
||||
int i, savelit;
|
||||
enum htmltag fp;
|
||||
struct tag *t;
|
||||
|
||||
if ((savelit = mh->fl & MANH_LITERAL))
|
||||
print_otag(h, TAG_BR, 0, NULL);
|
||||
|
||||
mh->fl &= ~MANH_LITERAL;
|
||||
|
||||
for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
|
||||
t = NULL;
|
||||
switch (n->tok) {
|
||||
case (MAN_BI):
|
||||
fp = i % 2 ? TAG_I : TAG_B;
|
||||
break;
|
||||
case (MAN_IB):
|
||||
fp = i % 2 ? TAG_B : TAG_I;
|
||||
break;
|
||||
case (MAN_RI):
|
||||
fp = i % 2 ? TAG_I : TAG_MAX;
|
||||
break;
|
||||
case (MAN_IR):
|
||||
fp = i % 2 ? TAG_MAX : TAG_I;
|
||||
break;
|
||||
case (MAN_BR):
|
||||
fp = i % 2 ? TAG_MAX : TAG_B;
|
||||
break;
|
||||
case (MAN_RB):
|
||||
fp = i % 2 ? TAG_B : TAG_MAX;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
if (i)
|
||||
h->flags |= HTML_NOSPACE;
|
||||
|
||||
if (TAG_MAX != fp)
|
||||
t = print_otag(h, fp, 0, NULL);
|
||||
|
||||
print_man_node(m, nn, mh, h);
|
||||
|
||||
if (t)
|
||||
print_tagq(h, t);
|
||||
}
|
||||
|
||||
if (savelit)
|
||||
mh->fl |= MANH_LITERAL;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
man_SM_pre(MAN_ARGS)
|
||||
{
|
||||
|
||||
print_otag(h, TAG_SMALL, 0, NULL);
|
||||
if (MAN_SB == n->tok)
|
||||
print_otag(h, TAG_B, 0, NULL);
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
man_SS_pre(MAN_ARGS)
|
||||
{
|
||||
struct htmlpair tag;
|
||||
|
||||
if (MAN_BLOCK == n->type) {
|
||||
mh->fl &= ~MANH_LITERAL;
|
||||
PAIR_CLASS_INIT(&tag, "subsection");
|
||||
print_otag(h, TAG_DIV, 1, &tag);
|
||||
return(1);
|
||||
} else if (MAN_BODY == n->type)
|
||||
return(1);
|
||||
|
||||
print_otag(h, TAG_H2, 0, NULL);
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
man_PP_pre(MAN_ARGS)
|
||||
{
|
||||
|
||||
if (MAN_HEAD == n->type)
|
||||
return(0);
|
||||
else if (MAN_BLOCK == n->type)
|
||||
print_bvspace(h, n);
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
man_IP_pre(MAN_ARGS)
|
||||
{
|
||||
const struct man_node *nn;
|
||||
|
||||
if (MAN_BODY == n->type) {
|
||||
print_otag(h, TAG_DD, 0, NULL);
|
||||
return(1);
|
||||
} else if (MAN_HEAD != n->type) {
|
||||
print_otag(h, TAG_DL, 0, NULL);
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* FIXME: width specification. */
|
||||
|
||||
print_otag(h, TAG_DT, 0, NULL);
|
||||
|
||||
/* For IP, only print the first header element. */
|
||||
|
||||
if (MAN_IP == n->tok && n->child)
|
||||
print_man_node(m, n->child, mh, h);
|
||||
|
||||
/* For TP, only print next-line header elements. */
|
||||
|
||||
if (MAN_TP == n->tok)
|
||||
for (nn = n->child; nn; nn = nn->next)
|
||||
if (nn->line > n->line)
|
||||
print_man_node(m, nn, mh, h);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
man_HP_pre(MAN_ARGS)
|
||||
{
|
||||
struct htmlpair tag;
|
||||
struct roffsu su;
|
||||
const struct man_node *np;
|
||||
|
||||
if (MAN_HEAD == n->type)
|
||||
return(0);
|
||||
else if (MAN_BLOCK != n->type)
|
||||
return(1);
|
||||
|
||||
np = n->head->child;
|
||||
|
||||
if (NULL == np || ! a2width(np, &su))
|
||||
SCALE_HS_INIT(&su, INDENT);
|
||||
|
||||
bufinit(h);
|
||||
|
||||
print_bvspace(h, n);
|
||||
bufcat_su(h, "margin-left", &su);
|
||||
su.scale = -su.scale;
|
||||
bufcat_su(h, "text-indent", &su);
|
||||
PAIR_STYLE_INIT(&tag, h);
|
||||
print_otag(h, TAG_P, 1, &tag);
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
man_OP_pre(MAN_ARGS)
|
||||
{
|
||||
struct tag *tt;
|
||||
struct htmlpair tag;
|
||||
|
||||
print_text(h, "[");
|
||||
h->flags |= HTML_NOSPACE;
|
||||
PAIR_CLASS_INIT(&tag, "opt");
|
||||
tt = print_otag(h, TAG_SPAN, 1, &tag);
|
||||
|
||||
if (NULL != (n = n->child)) {
|
||||
print_otag(h, TAG_B, 0, NULL);
|
||||
print_text(h, n->string);
|
||||
}
|
||||
|
||||
print_stagq(h, tt);
|
||||
|
||||
if (NULL != n && NULL != n->next) {
|
||||
print_otag(h, TAG_I, 0, NULL);
|
||||
print_text(h, n->next->string);
|
||||
}
|
||||
|
||||
print_stagq(h, tt);
|
||||
h->flags |= HTML_NOSPACE;
|
||||
print_text(h, "]");
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
man_B_pre(MAN_ARGS)
|
||||
{
|
||||
|
||||
print_otag(h, TAG_B, 0, NULL);
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
man_I_pre(MAN_ARGS)
|
||||
{
|
||||
|
||||
print_otag(h, TAG_I, 0, NULL);
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
man_literal_pre(MAN_ARGS)
|
||||
{
|
||||
|
||||
if (MAN_nf != n->tok) {
|
||||
print_otag(h, TAG_BR, 0, NULL);
|
||||
mh->fl &= ~MANH_LITERAL;
|
||||
} else
|
||||
mh->fl |= MANH_LITERAL;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
man_in_pre(MAN_ARGS)
|
||||
{
|
||||
|
||||
print_otag(h, TAG_BR, 0, NULL);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
man_ign_pre(MAN_ARGS)
|
||||
{
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
man_RS_pre(MAN_ARGS)
|
||||
{
|
||||
struct htmlpair tag;
|
||||
struct roffsu su;
|
||||
|
||||
if (MAN_HEAD == n->type)
|
||||
return(0);
|
||||
else if (MAN_BODY == n->type)
|
||||
return(1);
|
||||
|
||||
SCALE_HS_INIT(&su, INDENT);
|
||||
if (n->head->child)
|
||||
a2width(n->head->child, &su);
|
||||
|
||||
bufinit(h);
|
||||
bufcat_su(h, "margin-left", &su);
|
||||
PAIR_STYLE_INIT(&tag, h);
|
||||
print_otag(h, TAG_DIV, 1, &tag);
|
||||
return(1);
|
||||
}
|
484
contrib/mdocml/man_macro.c
Normal file
484
contrib/mdocml/man_macro.c
Normal file
@ -0,0 +1,484 @@
|
||||
/* $Id: man_macro.c,v 1.71 2012/01/03 15:16:24 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "man.h"
|
||||
#include "mandoc.h"
|
||||
#include "libmandoc.h"
|
||||
#include "libman.h"
|
||||
|
||||
enum rew {
|
||||
REW_REWIND,
|
||||
REW_NOHALT,
|
||||
REW_HALT
|
||||
};
|
||||
|
||||
static int blk_close(MACRO_PROT_ARGS);
|
||||
static int blk_exp(MACRO_PROT_ARGS);
|
||||
static int blk_imp(MACRO_PROT_ARGS);
|
||||
static int in_line_eoln(MACRO_PROT_ARGS);
|
||||
static int man_args(struct man *, int,
|
||||
int *, char *, char **);
|
||||
|
||||
static int rew_scope(enum man_type,
|
||||
struct man *, enum mant);
|
||||
static enum rew rew_dohalt(enum mant, enum man_type,
|
||||
const struct man_node *);
|
||||
static enum rew rew_block(enum mant, enum man_type,
|
||||
const struct man_node *);
|
||||
static void rew_warn(struct man *,
|
||||
struct man_node *, enum mandocerr);
|
||||
|
||||
const struct man_macro __man_macros[MAN_MAX] = {
|
||||
{ in_line_eoln, MAN_NSCOPED }, /* br */
|
||||
{ in_line_eoln, MAN_BSCOPE }, /* TH */
|
||||
{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SH */
|
||||
{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SS */
|
||||
{ blk_imp, MAN_BSCOPE | MAN_SCOPED | MAN_FSCOPED }, /* TP */
|
||||
{ blk_imp, MAN_BSCOPE }, /* LP */
|
||||
{ blk_imp, MAN_BSCOPE }, /* PP */
|
||||
{ blk_imp, MAN_BSCOPE }, /* P */
|
||||
{ blk_imp, MAN_BSCOPE }, /* IP */
|
||||
{ blk_imp, MAN_BSCOPE }, /* HP */
|
||||
{ in_line_eoln, MAN_SCOPED }, /* SM */
|
||||
{ in_line_eoln, MAN_SCOPED }, /* SB */
|
||||
{ in_line_eoln, 0 }, /* BI */
|
||||
{ in_line_eoln, 0 }, /* IB */
|
||||
{ in_line_eoln, 0 }, /* BR */
|
||||
{ in_line_eoln, 0 }, /* RB */
|
||||
{ in_line_eoln, MAN_SCOPED }, /* R */
|
||||
{ in_line_eoln, MAN_SCOPED }, /* B */
|
||||
{ in_line_eoln, MAN_SCOPED }, /* I */
|
||||
{ in_line_eoln, 0 }, /* IR */
|
||||
{ in_line_eoln, 0 }, /* RI */
|
||||
{ in_line_eoln, MAN_NSCOPED }, /* na */
|
||||
{ in_line_eoln, MAN_NSCOPED }, /* sp */
|
||||
{ in_line_eoln, MAN_BSCOPE }, /* nf */
|
||||
{ in_line_eoln, MAN_BSCOPE }, /* fi */
|
||||
{ blk_close, 0 }, /* RE */
|
||||
{ blk_exp, MAN_EXPLICIT }, /* RS */
|
||||
{ in_line_eoln, 0 }, /* DT */
|
||||
{ in_line_eoln, 0 }, /* UC */
|
||||
{ in_line_eoln, 0 }, /* PD */
|
||||
{ in_line_eoln, 0 }, /* AT */
|
||||
{ in_line_eoln, 0 }, /* in */
|
||||
{ in_line_eoln, 0 }, /* ft */
|
||||
{ in_line_eoln, 0 }, /* OP */
|
||||
};
|
||||
|
||||
const struct man_macro * const man_macros = __man_macros;
|
||||
|
||||
|
||||
/*
|
||||
* Warn when "n" is an explicit non-roff macro.
|
||||
*/
|
||||
static void
|
||||
rew_warn(struct man *m, struct man_node *n, enum mandocerr er)
|
||||
{
|
||||
|
||||
if (er == MANDOCERR_MAX || MAN_BLOCK != n->type)
|
||||
return;
|
||||
if (MAN_VALID & n->flags)
|
||||
return;
|
||||
if ( ! (MAN_EXPLICIT & man_macros[n->tok].flags))
|
||||
return;
|
||||
|
||||
assert(er < MANDOCERR_FATAL);
|
||||
man_nmsg(m, n, er);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Rewind scope. If a code "er" != MANDOCERR_MAX has been provided, it
|
||||
* will be used if an explicit block scope is being closed out.
|
||||
*/
|
||||
int
|
||||
man_unscope(struct man *m, const struct man_node *to,
|
||||
enum mandocerr er)
|
||||
{
|
||||
struct man_node *n;
|
||||
|
||||
assert(to);
|
||||
|
||||
m->next = MAN_NEXT_SIBLING;
|
||||
|
||||
/* LINTED */
|
||||
while (m->last != to) {
|
||||
/*
|
||||
* Save the parent here, because we may delete the
|
||||
* m->last node in the post-validation phase and reset
|
||||
* it to m->last->parent, causing a step in the closing
|
||||
* out to be lost.
|
||||
*/
|
||||
n = m->last->parent;
|
||||
rew_warn(m, m->last, er);
|
||||
if ( ! man_valid_post(m))
|
||||
return(0);
|
||||
m->last = n;
|
||||
assert(m->last);
|
||||
}
|
||||
|
||||
rew_warn(m, m->last, er);
|
||||
if ( ! man_valid_post(m))
|
||||
return(0);
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
static enum rew
|
||||
rew_block(enum mant ntok, enum man_type type, const struct man_node *n)
|
||||
{
|
||||
|
||||
if (MAN_BLOCK == type && ntok == n->parent->tok &&
|
||||
MAN_BODY == n->parent->type)
|
||||
return(REW_REWIND);
|
||||
return(ntok == n->tok ? REW_HALT : REW_NOHALT);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* There are three scope levels: scoped to the root (all), scoped to the
|
||||
* section (all less sections), and scoped to subsections (all less
|
||||
* sections and subsections).
|
||||
*/
|
||||
static enum rew
|
||||
rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n)
|
||||
{
|
||||
enum rew c;
|
||||
|
||||
/* We cannot progress beyond the root ever. */
|
||||
if (MAN_ROOT == n->type)
|
||||
return(REW_HALT);
|
||||
|
||||
assert(n->parent);
|
||||
|
||||
/* Normal nodes shouldn't go to the level of the root. */
|
||||
if (MAN_ROOT == n->parent->type)
|
||||
return(REW_REWIND);
|
||||
|
||||
/* Already-validated nodes should be closed out. */
|
||||
if (MAN_VALID & n->flags)
|
||||
return(REW_NOHALT);
|
||||
|
||||
/* First: rewind to ourselves. */
|
||||
if (type == n->type && tok == n->tok)
|
||||
return(REW_REWIND);
|
||||
|
||||
/*
|
||||
* Next follow the implicit scope-smashings as defined by man.7:
|
||||
* section, sub-section, etc.
|
||||
*/
|
||||
|
||||
switch (tok) {
|
||||
case (MAN_SH):
|
||||
break;
|
||||
case (MAN_SS):
|
||||
/* Rewind to a section, if a block. */
|
||||
if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
|
||||
return(c);
|
||||
break;
|
||||
case (MAN_RS):
|
||||
/* Rewind to a subsection, if a block. */
|
||||
if (REW_NOHALT != (c = rew_block(MAN_SS, type, n)))
|
||||
return(c);
|
||||
/* Rewind to a section, if a block. */
|
||||
if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
|
||||
return(c);
|
||||
break;
|
||||
default:
|
||||
/* Rewind to an offsetter, if a block. */
|
||||
if (REW_NOHALT != (c = rew_block(MAN_RS, type, n)))
|
||||
return(c);
|
||||
/* Rewind to a subsection, if a block. */
|
||||
if (REW_NOHALT != (c = rew_block(MAN_SS, type, n)))
|
||||
return(c);
|
||||
/* Rewind to a section, if a block. */
|
||||
if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
|
||||
return(c);
|
||||
break;
|
||||
}
|
||||
|
||||
return(REW_NOHALT);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Rewinding entails ascending the parse tree until a coherent point,
|
||||
* for example, the `SH' macro will close out any intervening `SS'
|
||||
* scopes. When a scope is closed, it must be validated and actioned.
|
||||
*/
|
||||
static int
|
||||
rew_scope(enum man_type type, struct man *m, enum mant tok)
|
||||
{
|
||||
struct man_node *n;
|
||||
enum rew c;
|
||||
|
||||
/* LINTED */
|
||||
for (n = m->last; n; n = n->parent) {
|
||||
/*
|
||||
* Whether we should stop immediately (REW_HALT), stop
|
||||
* and rewind until this point (REW_REWIND), or keep
|
||||
* rewinding (REW_NOHALT).
|
||||
*/
|
||||
c = rew_dohalt(tok, type, n);
|
||||
if (REW_HALT == c)
|
||||
return(1);
|
||||
if (REW_REWIND == c)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rewind until the current point. Warn if we're a roff
|
||||
* instruction that's mowing over explicit scopes.
|
||||
*/
|
||||
assert(n);
|
||||
|
||||
return(man_unscope(m, n, MANDOCERR_MAX));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Close out a generic explicit macro.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
int
|
||||
blk_close(MACRO_PROT_ARGS)
|
||||
{
|
||||
enum mant ntok;
|
||||
const struct man_node *nn;
|
||||
|
||||
switch (tok) {
|
||||
case (MAN_RE):
|
||||
ntok = MAN_RS;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
for (nn = m->last->parent; nn; nn = nn->parent)
|
||||
if (ntok == nn->tok)
|
||||
break;
|
||||
|
||||
if (NULL == nn)
|
||||
man_pmsg(m, line, ppos, MANDOCERR_NOSCOPE);
|
||||
|
||||
if ( ! rew_scope(MAN_BODY, m, ntok))
|
||||
return(0);
|
||||
if ( ! rew_scope(MAN_BLOCK, m, ntok))
|
||||
return(0);
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
blk_exp(MACRO_PROT_ARGS)
|
||||
{
|
||||
int la;
|
||||
char *p;
|
||||
|
||||
/*
|
||||
* Close out prior scopes. "Regular" explicit macros cannot be
|
||||
* nested, but we allow roff macros to be placed just about
|
||||
* anywhere.
|
||||
*/
|
||||
|
||||
if ( ! man_block_alloc(m, line, ppos, tok))
|
||||
return(0);
|
||||
if ( ! man_head_alloc(m, line, ppos, tok))
|
||||
return(0);
|
||||
|
||||
for (;;) {
|
||||
la = *pos;
|
||||
if ( ! man_args(m, line, pos, buf, &p))
|
||||
break;
|
||||
if ( ! man_word_alloc(m, line, la, p))
|
||||
return(0);
|
||||
}
|
||||
|
||||
assert(m);
|
||||
assert(tok != MAN_MAX);
|
||||
|
||||
if ( ! rew_scope(MAN_HEAD, m, tok))
|
||||
return(0);
|
||||
return(man_body_alloc(m, line, ppos, tok));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Parse an implicit-block macro. These contain a MAN_HEAD and a
|
||||
* MAN_BODY contained within a MAN_BLOCK. Rules for closing out other
|
||||
* scopes, such as `SH' closing out an `SS', are defined in the rew
|
||||
* routines.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
int
|
||||
blk_imp(MACRO_PROT_ARGS)
|
||||
{
|
||||
int la;
|
||||
char *p;
|
||||
struct man_node *n;
|
||||
|
||||
/* Close out prior scopes. */
|
||||
|
||||
if ( ! rew_scope(MAN_BODY, m, tok))
|
||||
return(0);
|
||||
if ( ! rew_scope(MAN_BLOCK, m, tok))
|
||||
return(0);
|
||||
|
||||
/* Allocate new block & head scope. */
|
||||
|
||||
if ( ! man_block_alloc(m, line, ppos, tok))
|
||||
return(0);
|
||||
if ( ! man_head_alloc(m, line, ppos, tok))
|
||||
return(0);
|
||||
|
||||
n = m->last;
|
||||
|
||||
/* Add line arguments. */
|
||||
|
||||
for (;;) {
|
||||
la = *pos;
|
||||
if ( ! man_args(m, line, pos, buf, &p))
|
||||
break;
|
||||
if ( ! man_word_alloc(m, line, la, p))
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Close out head and open body (unless MAN_SCOPE). */
|
||||
|
||||
if (MAN_SCOPED & man_macros[tok].flags) {
|
||||
/* If we're forcing scope (`TP'), keep it open. */
|
||||
if (MAN_FSCOPED & man_macros[tok].flags) {
|
||||
m->flags |= MAN_BLINE;
|
||||
return(1);
|
||||
} else if (n == m->last) {
|
||||
m->flags |= MAN_BLINE;
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! rew_scope(MAN_HEAD, m, tok))
|
||||
return(0);
|
||||
return(man_body_alloc(m, line, ppos, tok));
|
||||
}
|
||||
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
in_line_eoln(MACRO_PROT_ARGS)
|
||||
{
|
||||
int la;
|
||||
char *p;
|
||||
struct man_node *n;
|
||||
|
||||
if ( ! man_elem_alloc(m, line, ppos, tok))
|
||||
return(0);
|
||||
|
||||
n = m->last;
|
||||
|
||||
for (;;) {
|
||||
la = *pos;
|
||||
if ( ! man_args(m, line, pos, buf, &p))
|
||||
break;
|
||||
if ( ! man_word_alloc(m, line, la, p))
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If no arguments are specified and this is MAN_SCOPED (i.e.,
|
||||
* next-line scoped), then set our mode to indicate that we're
|
||||
* waiting for terms to load into our context.
|
||||
*/
|
||||
|
||||
if (n == m->last && MAN_SCOPED & man_macros[tok].flags) {
|
||||
assert( ! (MAN_NSCOPED & man_macros[tok].flags));
|
||||
m->flags |= MAN_ELINE;
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* Set ignorable context, if applicable. */
|
||||
|
||||
if (MAN_NSCOPED & man_macros[tok].flags) {
|
||||
assert( ! (MAN_SCOPED & man_macros[tok].flags));
|
||||
m->flags |= MAN_ILINE;
|
||||
}
|
||||
|
||||
assert(MAN_ROOT != m->last->type);
|
||||
m->next = MAN_NEXT_SIBLING;
|
||||
|
||||
/*
|
||||
* Rewind our element scope. Note that when TH is pruned, we'll
|
||||
* be back at the root, so make sure that we don't clobber as
|
||||
* its sibling.
|
||||
*/
|
||||
|
||||
for ( ; m->last; m->last = m->last->parent) {
|
||||
if (m->last == n)
|
||||
break;
|
||||
if (m->last->type == MAN_ROOT)
|
||||
break;
|
||||
if ( ! man_valid_post(m))
|
||||
return(0);
|
||||
}
|
||||
|
||||
assert(m->last);
|
||||
|
||||
/*
|
||||
* Same here regarding whether we're back at the root.
|
||||
*/
|
||||
|
||||
if (m->last->type != MAN_ROOT && ! man_valid_post(m))
|
||||
return(0);
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
man_macroend(struct man *m)
|
||||
{
|
||||
|
||||
return(man_unscope(m, m->first, MANDOCERR_SCOPEEXIT));
|
||||
}
|
||||
|
||||
static int
|
||||
man_args(struct man *m, int line, int *pos, char *buf, char **v)
|
||||
{
|
||||
char *start;
|
||||
|
||||
assert(*pos);
|
||||
*v = start = buf + *pos;
|
||||
assert(' ' != *start);
|
||||
|
||||
if ('\0' == *start)
|
||||
return(0);
|
||||
|
||||
*v = mandoc_getarg(m->parse, v, line, pos);
|
||||
return(1);
|
||||
}
|
1117
contrib/mdocml/man_term.c
Normal file
1117
contrib/mdocml/man_term.c
Normal file
File diff suppressed because it is too large
Load Diff
550
contrib/mdocml/man_validate.c
Normal file
550
contrib/mdocml/man_validate.c
Normal file
@ -0,0 +1,550 @@
|
||||
/* $Id: man_validate.c,v 1.80 2012/01/03 15:16:24 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 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
|
||||
* 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "man.h"
|
||||
#include "mandoc.h"
|
||||
#include "libman.h"
|
||||
#include "libmandoc.h"
|
||||
|
||||
#define CHKARGS struct man *m, struct man_node *n
|
||||
|
||||
typedef int (*v_check)(CHKARGS);
|
||||
|
||||
struct man_valid {
|
||||
v_check *pres;
|
||||
v_check *posts;
|
||||
};
|
||||
|
||||
static int check_eq0(CHKARGS);
|
||||
static int check_eq2(CHKARGS);
|
||||
static int check_le1(CHKARGS);
|
||||
static int check_ge2(CHKARGS);
|
||||
static int check_le5(CHKARGS);
|
||||
static int check_par(CHKARGS);
|
||||
static int check_part(CHKARGS);
|
||||
static int check_root(CHKARGS);
|
||||
static void check_text(CHKARGS);
|
||||
|
||||
static int post_AT(CHKARGS);
|
||||
static int post_vs(CHKARGS);
|
||||
static int post_fi(CHKARGS);
|
||||
static int post_ft(CHKARGS);
|
||||
static int post_nf(CHKARGS);
|
||||
static int post_sec(CHKARGS);
|
||||
static int post_TH(CHKARGS);
|
||||
static int post_UC(CHKARGS);
|
||||
static int pre_sec(CHKARGS);
|
||||
|
||||
static v_check posts_at[] = { post_AT, NULL };
|
||||
static v_check posts_br[] = { post_vs, check_eq0, NULL };
|
||||
static v_check posts_eq0[] = { check_eq0, NULL };
|
||||
static v_check posts_eq2[] = { check_eq2, NULL };
|
||||
static v_check posts_fi[] = { check_eq0, post_fi, NULL };
|
||||
static v_check posts_ft[] = { post_ft, NULL };
|
||||
static v_check posts_nf[] = { check_eq0, post_nf, NULL };
|
||||
static v_check posts_par[] = { check_par, NULL };
|
||||
static v_check posts_part[] = { check_part, NULL };
|
||||
static v_check posts_sec[] = { post_sec, NULL };
|
||||
static v_check posts_sp[] = { post_vs, check_le1, NULL };
|
||||
static v_check posts_th[] = { check_ge2, check_le5, post_TH, NULL };
|
||||
static v_check posts_uc[] = { post_UC, NULL };
|
||||
static v_check pres_sec[] = { pre_sec, NULL };
|
||||
|
||||
static const struct man_valid man_valids[MAN_MAX] = {
|
||||
{ NULL, posts_br }, /* br */
|
||||
{ NULL, posts_th }, /* TH */
|
||||
{ pres_sec, posts_sec }, /* SH */
|
||||
{ pres_sec, posts_sec }, /* SS */
|
||||
{ NULL, NULL }, /* TP */
|
||||
{ NULL, posts_par }, /* LP */
|
||||
{ NULL, posts_par }, /* PP */
|
||||
{ NULL, posts_par }, /* P */
|
||||
{ NULL, NULL }, /* IP */
|
||||
{ NULL, NULL }, /* HP */
|
||||
{ NULL, NULL }, /* SM */
|
||||
{ NULL, NULL }, /* SB */
|
||||
{ NULL, NULL }, /* BI */
|
||||
{ NULL, NULL }, /* IB */
|
||||
{ NULL, NULL }, /* BR */
|
||||
{ NULL, NULL }, /* RB */
|
||||
{ NULL, NULL }, /* R */
|
||||
{ NULL, NULL }, /* B */
|
||||
{ NULL, NULL }, /* I */
|
||||
{ NULL, NULL }, /* IR */
|
||||
{ NULL, NULL }, /* RI */
|
||||
{ NULL, posts_eq0 }, /* na */
|
||||
{ NULL, posts_sp }, /* sp */
|
||||
{ NULL, posts_nf }, /* nf */
|
||||
{ NULL, posts_fi }, /* fi */
|
||||
{ NULL, NULL }, /* RE */
|
||||
{ NULL, posts_part }, /* RS */
|
||||
{ NULL, NULL }, /* DT */
|
||||
{ NULL, posts_uc }, /* UC */
|
||||
{ NULL, NULL }, /* PD */
|
||||
{ NULL, posts_at }, /* AT */
|
||||
{ NULL, NULL }, /* in */
|
||||
{ NULL, posts_ft }, /* ft */
|
||||
{ NULL, posts_eq2 }, /* OP */
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
man_valid_pre(struct man *m, struct man_node *n)
|
||||
{
|
||||
v_check *cp;
|
||||
|
||||
switch (n->type) {
|
||||
case (MAN_TEXT):
|
||||
/* FALLTHROUGH */
|
||||
case (MAN_ROOT):
|
||||
/* FALLTHROUGH */
|
||||
case (MAN_EQN):
|
||||
/* FALLTHROUGH */
|
||||
case (MAN_TBL):
|
||||
return(1);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (NULL == (cp = man_valids[n->tok].pres))
|
||||
return(1);
|
||||
for ( ; *cp; cp++)
|
||||
if ( ! (*cp)(m, n))
|
||||
return(0);
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
man_valid_post(struct man *m)
|
||||
{
|
||||
v_check *cp;
|
||||
|
||||
if (MAN_VALID & m->last->flags)
|
||||
return(1);
|
||||
m->last->flags |= MAN_VALID;
|
||||
|
||||
switch (m->last->type) {
|
||||
case (MAN_TEXT):
|
||||
check_text(m, m->last);
|
||||
return(1);
|
||||
case (MAN_ROOT):
|
||||
return(check_root(m, m->last));
|
||||
case (MAN_EQN):
|
||||
/* FALLTHROUGH */
|
||||
case (MAN_TBL):
|
||||
return(1);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (NULL == (cp = man_valids[m->last->tok].posts))
|
||||
return(1);
|
||||
for ( ; *cp; cp++)
|
||||
if ( ! (*cp)(m, m->last))
|
||||
return(0);
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
check_root(CHKARGS)
|
||||
{
|
||||
|
||||
if (MAN_BLINE & m->flags)
|
||||
man_nmsg(m, n, MANDOCERR_SCOPEEXIT);
|
||||
else if (MAN_ELINE & m->flags)
|
||||
man_nmsg(m, n, MANDOCERR_SCOPEEXIT);
|
||||
|
||||
m->flags &= ~MAN_BLINE;
|
||||
m->flags &= ~MAN_ELINE;
|
||||
|
||||
if (NULL == m->first->child) {
|
||||
man_nmsg(m, n, MANDOCERR_NODOCBODY);
|
||||
return(0);
|
||||
} else if (NULL == m->meta.title) {
|
||||
man_nmsg(m, n, MANDOCERR_NOTITLE);
|
||||
|
||||
/*
|
||||
* If a title hasn't been set, do so now (by
|
||||
* implication, date and section also aren't set).
|
||||
*/
|
||||
|
||||
m->meta.title = mandoc_strdup("unknown");
|
||||
m->meta.msec = mandoc_strdup("1");
|
||||
m->meta.date = mandoc_normdate
|
||||
(m->parse, NULL, n->line, n->pos);
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
static void
|
||||
check_text(CHKARGS)
|
||||
{
|
||||
char *cp, *p;
|
||||
|
||||
if (MAN_LITERAL & m->flags)
|
||||
return;
|
||||
|
||||
cp = n->string;
|
||||
for (p = cp; NULL != (p = strchr(p, '\t')); p++)
|
||||
man_pmsg(m, n->line, (int)(p - cp), MANDOCERR_BADTAB);
|
||||
}
|
||||
|
||||
#define INEQ_DEFINE(x, ineq, name) \
|
||||
static int \
|
||||
check_##name(CHKARGS) \
|
||||
{ \
|
||||
if (n->nchild ineq (x)) \
|
||||
return(1); \
|
||||
mandoc_vmsg(MANDOCERR_ARGCOUNT, m->parse, n->line, n->pos, \
|
||||
"line arguments %s %d (have %d)", \
|
||||
#ineq, (x), n->nchild); \
|
||||
return(1); \
|
||||
}
|
||||
|
||||
INEQ_DEFINE(0, ==, eq0)
|
||||
INEQ_DEFINE(2, ==, eq2)
|
||||
INEQ_DEFINE(1, <=, le1)
|
||||
INEQ_DEFINE(2, >=, ge2)
|
||||
INEQ_DEFINE(5, <=, le5)
|
||||
|
||||
static int
|
||||
post_ft(CHKARGS)
|
||||
{
|
||||
char *cp;
|
||||
int ok;
|
||||
|
||||
if (0 == n->nchild)
|
||||
return(1);
|
||||
|
||||
ok = 0;
|
||||
cp = n->child->string;
|
||||
switch (*cp) {
|
||||
case ('1'):
|
||||
/* FALLTHROUGH */
|
||||
case ('2'):
|
||||
/* FALLTHROUGH */
|
||||
case ('3'):
|
||||
/* FALLTHROUGH */
|
||||
case ('4'):
|
||||
/* FALLTHROUGH */
|
||||
case ('I'):
|
||||
/* FALLTHROUGH */
|
||||
case ('P'):
|
||||
/* FALLTHROUGH */
|
||||
case ('R'):
|
||||
if ('\0' == cp[1])
|
||||
ok = 1;
|
||||
break;
|
||||
case ('B'):
|
||||
if ('\0' == cp[1] || ('I' == cp[1] && '\0' == cp[2]))
|
||||
ok = 1;
|
||||
break;
|
||||
case ('C'):
|
||||
if ('W' == cp[1] && '\0' == cp[2])
|
||||
ok = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (0 == ok) {
|
||||
mandoc_vmsg
|
||||
(MANDOCERR_BADFONT, m->parse,
|
||||
n->line, n->pos, "%s", cp);
|
||||
*cp = '\0';
|
||||
}
|
||||
|
||||
if (1 < n->nchild)
|
||||
mandoc_vmsg
|
||||
(MANDOCERR_ARGCOUNT, m->parse, n->line,
|
||||
n->pos, "want one child (have %d)",
|
||||
n->nchild);
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int
|
||||
pre_sec(CHKARGS)
|
||||
{
|
||||
|
||||
if (MAN_BLOCK == n->type)
|
||||
m->flags &= ~MAN_LITERAL;
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int
|
||||
post_sec(CHKARGS)
|
||||
{
|
||||
|
||||
if ( ! (MAN_HEAD == n->type && 0 == n->nchild))
|
||||
return(1);
|
||||
|
||||
man_nmsg(m, n, MANDOCERR_SYNTARGCOUNT);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
check_part(CHKARGS)
|
||||
{
|
||||
|
||||
if (MAN_BODY == n->type && 0 == n->nchild)
|
||||
mandoc_msg(MANDOCERR_ARGCWARN, m->parse, n->line,
|
||||
n->pos, "want children (have none)");
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
check_par(CHKARGS)
|
||||
{
|
||||
|
||||
switch (n->type) {
|
||||
case (MAN_BLOCK):
|
||||
if (0 == n->body->nchild)
|
||||
man_node_delete(m, n);
|
||||
break;
|
||||
case (MAN_BODY):
|
||||
if (0 == n->nchild)
|
||||
man_nmsg(m, n, MANDOCERR_IGNPAR);
|
||||
break;
|
||||
case (MAN_HEAD):
|
||||
if (n->nchild)
|
||||
man_nmsg(m, n, MANDOCERR_ARGSLOST);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
post_TH(CHKARGS)
|
||||
{
|
||||
const char *p;
|
||||
int line, pos;
|
||||
|
||||
if (m->meta.title)
|
||||
free(m->meta.title);
|
||||
if (m->meta.vol)
|
||||
free(m->meta.vol);
|
||||
if (m->meta.source)
|
||||
free(m->meta.source);
|
||||
if (m->meta.msec)
|
||||
free(m->meta.msec);
|
||||
if (m->meta.date)
|
||||
free(m->meta.date);
|
||||
|
||||
line = n->line;
|
||||
pos = n->pos;
|
||||
m->meta.title = m->meta.vol = m->meta.date =
|
||||
m->meta.msec = m->meta.source = NULL;
|
||||
|
||||
/* ->TITLE<- MSEC DATE SOURCE VOL */
|
||||
|
||||
n = n->child;
|
||||
if (n && n->string) {
|
||||
for (p = n->string; '\0' != *p; p++) {
|
||||
/* Only warn about this once... */
|
||||
if (isalpha((unsigned char)*p) &&
|
||||
! isupper((unsigned char)*p)) {
|
||||
man_nmsg(m, n, MANDOCERR_UPPERCASE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
m->meta.title = mandoc_strdup(n->string);
|
||||
} else
|
||||
m->meta.title = mandoc_strdup("");
|
||||
|
||||
/* TITLE ->MSEC<- DATE SOURCE VOL */
|
||||
|
||||
if (n)
|
||||
n = n->next;
|
||||
if (n && n->string)
|
||||
m->meta.msec = mandoc_strdup(n->string);
|
||||
else
|
||||
m->meta.msec = mandoc_strdup("");
|
||||
|
||||
/* TITLE MSEC ->DATE<- SOURCE VOL */
|
||||
|
||||
if (n)
|
||||
n = n->next;
|
||||
if (n && n->string && '\0' != n->string[0]) {
|
||||
pos = n->pos;
|
||||
m->meta.date = mandoc_normdate
|
||||
(m->parse, n->string, line, pos);
|
||||
} else
|
||||
m->meta.date = mandoc_strdup("");
|
||||
|
||||
/* TITLE MSEC DATE ->SOURCE<- VOL */
|
||||
|
||||
if (n && (n = n->next))
|
||||
m->meta.source = mandoc_strdup(n->string);
|
||||
|
||||
/* TITLE MSEC DATE SOURCE ->VOL<- */
|
||||
/* If missing, use the default VOL name for MSEC. */
|
||||
|
||||
if (n && (n = n->next))
|
||||
m->meta.vol = mandoc_strdup(n->string);
|
||||
else if ('\0' != m->meta.msec[0] &&
|
||||
(NULL != (p = mandoc_a2msec(m->meta.msec))))
|
||||
m->meta.vol = mandoc_strdup(p);
|
||||
|
||||
/*
|
||||
* Remove the `TH' node after we've processed it for our
|
||||
* meta-data.
|
||||
*/
|
||||
man_node_delete(m, m->last);
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int
|
||||
post_nf(CHKARGS)
|
||||
{
|
||||
|
||||
if (MAN_LITERAL & m->flags)
|
||||
man_nmsg(m, n, MANDOCERR_SCOPEREP);
|
||||
|
||||
m->flags |= MAN_LITERAL;
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int
|
||||
post_fi(CHKARGS)
|
||||
{
|
||||
|
||||
if ( ! (MAN_LITERAL & m->flags))
|
||||
man_nmsg(m, n, MANDOCERR_WNOSCOPE);
|
||||
|
||||
m->flags &= ~MAN_LITERAL;
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int
|
||||
post_UC(CHKARGS)
|
||||
{
|
||||
static const char * const bsd_versions[] = {
|
||||
"3rd Berkeley Distribution",
|
||||
"4th Berkeley Distribution",
|
||||
"4.2 Berkeley Distribution",
|
||||
"4.3 Berkeley Distribution",
|
||||
"4.4 Berkeley Distribution",
|
||||
};
|
||||
|
||||
const char *p, *s;
|
||||
|
||||
n = n->child;
|
||||
|
||||
if (NULL == n || MAN_TEXT != n->type)
|
||||
p = bsd_versions[0];
|
||||
else {
|
||||
s = n->string;
|
||||
if (0 == strcmp(s, "3"))
|
||||
p = bsd_versions[0];
|
||||
else if (0 == strcmp(s, "4"))
|
||||
p = bsd_versions[1];
|
||||
else if (0 == strcmp(s, "5"))
|
||||
p = bsd_versions[2];
|
||||
else if (0 == strcmp(s, "6"))
|
||||
p = bsd_versions[3];
|
||||
else if (0 == strcmp(s, "7"))
|
||||
p = bsd_versions[4];
|
||||
else
|
||||
p = bsd_versions[0];
|
||||
}
|
||||
|
||||
if (m->meta.source)
|
||||
free(m->meta.source);
|
||||
|
||||
m->meta.source = mandoc_strdup(p);
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int
|
||||
post_AT(CHKARGS)
|
||||
{
|
||||
static const char * const unix_versions[] = {
|
||||
"7th Edition",
|
||||
"System III",
|
||||
"System V",
|
||||
"System V Release 2",
|
||||
};
|
||||
|
||||
const char *p, *s;
|
||||
struct man_node *nn;
|
||||
|
||||
n = n->child;
|
||||
|
||||
if (NULL == n || MAN_TEXT != n->type)
|
||||
p = unix_versions[0];
|
||||
else {
|
||||
s = n->string;
|
||||
if (0 == strcmp(s, "3"))
|
||||
p = unix_versions[0];
|
||||
else if (0 == strcmp(s, "4"))
|
||||
p = unix_versions[1];
|
||||
else if (0 == strcmp(s, "5")) {
|
||||
nn = n->next;
|
||||
if (nn && MAN_TEXT == nn->type && nn->string[0])
|
||||
p = unix_versions[3];
|
||||
else
|
||||
p = unix_versions[2];
|
||||
} else
|
||||
p = unix_versions[0];
|
||||
}
|
||||
|
||||
if (m->meta.source)
|
||||
free(m->meta.source);
|
||||
|
||||
m->meta.source = mandoc_strdup(p);
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int
|
||||
post_vs(CHKARGS)
|
||||
{
|
||||
|
||||
/*
|
||||
* Don't warn about this because it occurs in pod2man and would
|
||||
* cause considerable (unfixable) warnage.
|
||||
*/
|
||||
if (NULL == n->prev && MAN_ROOT == n->parent->type)
|
||||
man_node_delete(m, n);
|
||||
|
||||
return(1);
|
||||
}
|
669
contrib/mdocml/mandoc.1
Normal file
669
contrib/mdocml/mandoc.1
Normal file
@ -0,0 +1,669 @@
|
||||
.\" $Id: mandoc.1,v 1.100 2011/12/25 19:35:44 kristaps Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2009, 2010, 2011 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.
|
||||
.\"
|
||||
.Dd $Mdocdate: December 25 2011 $
|
||||
.Dt MANDOC 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm mandoc
|
||||
.Nd format and display UNIX manuals
|
||||
.Sh SYNOPSIS
|
||||
.Nm mandoc
|
||||
.Op Fl V
|
||||
.Op Fl m Ns Ar format
|
||||
.Op Fl O Ns Ar option
|
||||
.Op Fl T Ns Ar output
|
||||
.Op Fl W Ns Ar level
|
||||
.Op Ar
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility formats
|
||||
.Ux
|
||||
manual pages for display.
|
||||
.Pp
|
||||
By default,
|
||||
.Nm
|
||||
reads
|
||||
.Xr mdoc 7
|
||||
or
|
||||
.Xr man 7
|
||||
text from stdin, implying
|
||||
.Fl m Ns Cm andoc ,
|
||||
and produces
|
||||
.Fl T Ns Cm ascii
|
||||
output.
|
||||
.Pp
|
||||
The arguments are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl m Ns Ar format
|
||||
Input format.
|
||||
See
|
||||
.Sx Input Formats
|
||||
for available formats.
|
||||
Defaults to
|
||||
.Fl m Ns Cm andoc .
|
||||
.It Fl O Ns Ar option
|
||||
Comma-separated output options.
|
||||
.It Fl T Ns Ar output
|
||||
Output format.
|
||||
See
|
||||
.Sx Output Formats
|
||||
for available formats.
|
||||
Defaults to
|
||||
.Fl T Ns Cm ascii .
|
||||
.It Fl V
|
||||
Print version and exit.
|
||||
.It Fl W Ns Ar level
|
||||
Specify the minimum message
|
||||
.Ar level
|
||||
to be reported on the standard error output and to affect the exit status.
|
||||
The
|
||||
.Ar level
|
||||
can be
|
||||
.Cm warning ,
|
||||
.Cm error ,
|
||||
or
|
||||
.Cm fatal .
|
||||
The default is
|
||||
.Fl W Ns Cm fatal ;
|
||||
.Fl W Ns Cm all
|
||||
is an alias for
|
||||
.Fl W Ns Cm warning .
|
||||
See
|
||||
.Sx EXIT STATUS
|
||||
and
|
||||
.Sx DIAGNOSTICS
|
||||
for details.
|
||||
.Pp
|
||||
The special option
|
||||
.Fl W Ns Cm stop
|
||||
tells
|
||||
.Nm
|
||||
to exit after parsing a file that causes warnings or errors of at least
|
||||
the requested level.
|
||||
No formatted output will be produced from that file.
|
||||
If both a
|
||||
.Ar level
|
||||
and
|
||||
.Cm stop
|
||||
are requested, they can be joined with a comma, for example
|
||||
.Fl W Ns Cm error , Ns Cm stop .
|
||||
.It Ar file
|
||||
Read input from zero or more files.
|
||||
If unspecified, reads from stdin.
|
||||
If multiple files are specified,
|
||||
.Nm
|
||||
will halt with the first failed parse.
|
||||
.El
|
||||
.Ss Input Formats
|
||||
The
|
||||
.Nm
|
||||
utility accepts
|
||||
.Xr mdoc 7
|
||||
and
|
||||
.Xr man 7
|
||||
input with
|
||||
.Fl m Ns Cm doc
|
||||
and
|
||||
.Fl m Ns Cm an ,
|
||||
respectively.
|
||||
The
|
||||
.Xr mdoc 7
|
||||
format is
|
||||
.Em strongly
|
||||
recommended;
|
||||
.Xr man 7
|
||||
should only be used for legacy manuals.
|
||||
.Pp
|
||||
A third option,
|
||||
.Fl m Ns Cm andoc ,
|
||||
which is also the default, determines encoding on-the-fly: if the first
|
||||
non-comment macro is
|
||||
.Sq \&Dd
|
||||
or
|
||||
.Sq \&Dt ,
|
||||
the
|
||||
.Xr mdoc 7
|
||||
parser is used; otherwise, the
|
||||
.Xr man 7
|
||||
parser is used.
|
||||
.Pp
|
||||
If multiple
|
||||
files are specified with
|
||||
.Fl m Ns Cm andoc ,
|
||||
each has its file-type determined this way.
|
||||
If multiple files are
|
||||
specified and
|
||||
.Fl m Ns Cm doc
|
||||
or
|
||||
.Fl m Ns Cm an
|
||||
is specified, then this format is used exclusively.
|
||||
.Ss Output Formats
|
||||
The
|
||||
.Nm
|
||||
utility accepts the following
|
||||
.Fl T
|
||||
arguments, which correspond to output modes:
|
||||
.Bl -tag -width "-Tlocale"
|
||||
.It Fl T Ns Cm ascii
|
||||
Produce 7-bit ASCII output.
|
||||
This is the default.
|
||||
See
|
||||
.Sx ASCII Output .
|
||||
.It Fl T Ns Cm html
|
||||
Produce strict CSS1/HTML-4.01 output.
|
||||
See
|
||||
.Sx HTML Output .
|
||||
.It Fl T Ns Cm lint
|
||||
Parse only: produce no output.
|
||||
Implies
|
||||
.Fl W Ns Cm warning .
|
||||
.It Fl T Ns Cm locale
|
||||
Encode output using the current locale.
|
||||
See
|
||||
.Sx Locale Output .
|
||||
.It Fl T Ns Cm man
|
||||
Produce
|
||||
.Xr man 7
|
||||
format output.
|
||||
See
|
||||
.Sx Man Output .
|
||||
.It Fl T Ns Cm pdf
|
||||
Produce PDF output.
|
||||
See
|
||||
.Sx PDF Output .
|
||||
.It Fl T Ns Cm ps
|
||||
Produce PostScript output.
|
||||
See
|
||||
.Sx PostScript Output .
|
||||
.It Fl T Ns Cm tree
|
||||
Produce an indented parse tree.
|
||||
.It Fl T Ns Cm utf8
|
||||
Encode output in the UTF\-8 multi-byte format.
|
||||
See
|
||||
.Sx UTF\-8 Output .
|
||||
.It Fl T Ns Cm xhtml
|
||||
Produce strict CSS1/XHTML-1.0 output.
|
||||
See
|
||||
.Sx XHTML Output .
|
||||
.El
|
||||
.Pp
|
||||
If multiple input files are specified, these will be processed by the
|
||||
corresponding filter in-order.
|
||||
.Ss ASCII Output
|
||||
Output produced by
|
||||
.Fl T Ns Cm ascii ,
|
||||
which is the default, is rendered in standard 7-bit ASCII documented in
|
||||
.Xr ascii 7 .
|
||||
.Pp
|
||||
Font styles are applied by using back-spaced encoding such that an
|
||||
underlined character
|
||||
.Sq c
|
||||
is rendered as
|
||||
.Sq _ Ns \e[bs] Ns c ,
|
||||
where
|
||||
.Sq \e[bs]
|
||||
is the back-space character number 8.
|
||||
Emboldened characters are rendered as
|
||||
.Sq c Ns \e[bs] Ns c .
|
||||
.Pp
|
||||
The special characters documented in
|
||||
.Xr mandoc_char 7
|
||||
are rendered best-effort in an ASCII equivalent.
|
||||
If no equivalent is found,
|
||||
.Sq \&?
|
||||
is used instead.
|
||||
.Pp
|
||||
Output width is limited to 78 visible columns unless literal input lines
|
||||
exceed this limit.
|
||||
.Pp
|
||||
The following
|
||||
.Fl O
|
||||
arguments are accepted:
|
||||
.Bl -tag -width Ds
|
||||
.It Cm indent Ns = Ns Ar indent
|
||||
The left margin for normal text is set to
|
||||
.Ar indent
|
||||
blank characters instead of the default of five for
|
||||
.Xr mdoc 7
|
||||
and seven for
|
||||
.Xr man 7 .
|
||||
Increasing this is not recommended; it may result in degraded formatting,
|
||||
for example overfull lines or ugly line breaks.
|
||||
.It Cm width Ns = Ns Ar width
|
||||
The output width is set to
|
||||
.Ar width ,
|
||||
which will normalise to \(>=60.
|
||||
.El
|
||||
.Ss HTML Output
|
||||
Output produced by
|
||||
.Fl T Ns Cm html
|
||||
conforms to HTML-4.01 strict.
|
||||
.Pp
|
||||
The
|
||||
.Pa example.style.css
|
||||
file documents style-sheet classes available for customising output.
|
||||
If a style-sheet is not specified with
|
||||
.Fl O Ns Ar style ,
|
||||
.Fl T Ns Cm html
|
||||
defaults to simple output readable in any graphical or text-based web
|
||||
browser.
|
||||
.Pp
|
||||
Special characters are rendered in decimal-encoded UTF\-8.
|
||||
.Pp
|
||||
The following
|
||||
.Fl O
|
||||
arguments are accepted:
|
||||
.Bl -tag -width Ds
|
||||
.It Cm fragment
|
||||
Omit the
|
||||
.Aq !DOCTYPE
|
||||
declaration and the
|
||||
.Aq html ,
|
||||
.Aq head ,
|
||||
and
|
||||
.Aq body
|
||||
elements and only emit the subtree below the
|
||||
.Aq body
|
||||
element.
|
||||
The
|
||||
.Cm style
|
||||
argument will be ignored.
|
||||
This is useful when embedding manual content within existing documents.
|
||||
.It Cm includes Ns = Ns Ar fmt
|
||||
The string
|
||||
.Ar fmt ,
|
||||
for example,
|
||||
.Ar ../src/%I.html ,
|
||||
is used as a template for linked header files (usually via the
|
||||
.Sq \&In
|
||||
macro).
|
||||
Instances of
|
||||
.Sq \&%I
|
||||
are replaced with the include filename.
|
||||
The default is not to present a
|
||||
hyperlink.
|
||||
.It Cm man Ns = Ns Ar fmt
|
||||
The string
|
||||
.Ar fmt ,
|
||||
for example,
|
||||
.Ar ../html%S/%N.%S.html ,
|
||||
is used as a template for linked manuals (usually via the
|
||||
.Sq \&Xr
|
||||
macro).
|
||||
Instances of
|
||||
.Sq \&%N
|
||||
and
|
||||
.Sq %S
|
||||
are replaced with the linked manual's name and section, respectively.
|
||||
If no section is included, section 1 is assumed.
|
||||
The default is not to
|
||||
present a hyperlink.
|
||||
.It Cm style Ns = Ns Ar style.css
|
||||
The file
|
||||
.Ar style.css
|
||||
is used for an external style-sheet.
|
||||
This must be a valid absolute or
|
||||
relative URI.
|
||||
.El
|
||||
.Ss Locale Output
|
||||
Locale-depending output encoding is triggered with
|
||||
.Fl T Ns Cm locale .
|
||||
This option is not available on all systems: systems without locale
|
||||
support, or those whose internal representation is not natively UCS-4,
|
||||
will fall back to
|
||||
.Fl T Ns Cm ascii .
|
||||
See
|
||||
.Sx ASCII Output
|
||||
for font style specification and available command-line arguments.
|
||||
.Ss Man Output
|
||||
Translate input format into
|
||||
.Xr man 7
|
||||
output format.
|
||||
This is useful for distributing manual sources to legancy systems
|
||||
lacking
|
||||
.Xr mdoc 7
|
||||
formatters.
|
||||
.Pp
|
||||
If
|
||||
.Xr mdoc 7
|
||||
is passed as input, it is translated into
|
||||
.Xr man 7 .
|
||||
If the input format is
|
||||
.Xr man 7 ,
|
||||
the input is copied to the output, expanding any
|
||||
.Xr roff 7
|
||||
.Sq so
|
||||
requests.
|
||||
The parser is also run, and as usual, the
|
||||
.Fl W
|
||||
level controls which
|
||||
.Sx DIAGNOSTICS
|
||||
are displayed before copying the input to the output.
|
||||
.Ss PDF Output
|
||||
PDF-1.1 output may be generated by
|
||||
.Fl T Ns Cm pdf .
|
||||
See
|
||||
.Sx PostScript Output
|
||||
for
|
||||
.Fl O
|
||||
arguments and defaults.
|
||||
.Ss PostScript Output
|
||||
PostScript
|
||||
.Qq Adobe-3.0
|
||||
Level-2 pages may be generated by
|
||||
.Fl T Ns Cm ps .
|
||||
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 .
|
||||
.Pp
|
||||
The following
|
||||
.Fl O
|
||||
arguments are accepted:
|
||||
.Bl -tag -width Ds
|
||||
.It Cm paper Ns = Ns Ar name
|
||||
The paper size
|
||||
.Ar name
|
||||
may be one of
|
||||
.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 UTF\-8 Output
|
||||
Use
|
||||
.Fl T Ns Cm utf8
|
||||
to force a UTF\-8 locale.
|
||||
See
|
||||
.Sx Locale Output
|
||||
for details and options.
|
||||
.Ss XHTML Output
|
||||
Output produced by
|
||||
.Fl T Ns Cm xhtml
|
||||
conforms to XHTML-1.0 strict.
|
||||
.Pp
|
||||
See
|
||||
.Sx HTML Output
|
||||
for details; beyond generating XHTML tags instead of HTML tags, these
|
||||
output modes are identical.
|
||||
.Sh EXIT STATUS
|
||||
The
|
||||
.Nm
|
||||
utility exits with one of the following values, controlled by the message
|
||||
.Ar level
|
||||
associated with the
|
||||
.Fl W
|
||||
option:
|
||||
.Pp
|
||||
.Bl -tag -width Ds -compact
|
||||
.It 0
|
||||
No warnings or errors occurred, or those that did were ignored because
|
||||
they were lower than the requested
|
||||
.Ar level .
|
||||
.It 2
|
||||
At least one warning occurred, but no error, and
|
||||
.Fl W Ns Cm warning
|
||||
was specified.
|
||||
.It 3
|
||||
At least one parsing error occurred, but no fatal error, and
|
||||
.Fl W Ns Cm error
|
||||
or
|
||||
.Fl W Ns Cm warning
|
||||
was specified.
|
||||
.It 4
|
||||
A fatal parsing error occurred.
|
||||
.It 5
|
||||
Invalid command line arguments were specified.
|
||||
No input files have been read.
|
||||
.It 6
|
||||
An operating system error occurred, for example memory exhaustion or an
|
||||
error accessing input files.
|
||||
Such errors cause
|
||||
.Nm
|
||||
to exit at once, possibly in the middle of parsing or formatting a file.
|
||||
.El
|
||||
.Pp
|
||||
Note that selecting
|
||||
.Fl T Ns Cm lint
|
||||
output mode implies
|
||||
.Fl W Ns Cm warning .
|
||||
.Sh EXAMPLES
|
||||
To page manuals to the terminal:
|
||||
.Pp
|
||||
.Dl $ mandoc \-Wall,stop mandoc.1 2\*(Gt&1 | less
|
||||
.Dl $ mandoc mandoc.1 mdoc.3 mdoc.7 | less
|
||||
.Pp
|
||||
To produce HTML manuals with
|
||||
.Ar style.css
|
||||
as the style-sheet:
|
||||
.Pp
|
||||
.Dl $ mandoc \-Thtml -Ostyle=style.css mdoc.7 \*(Gt mdoc.7.html
|
||||
.Pp
|
||||
To check over a large set of manuals:
|
||||
.Pp
|
||||
.Dl $ mandoc \-Tlint `find /usr/src -name \e*\e.[1-9]`
|
||||
.Pp
|
||||
To produce a series of PostScript manuals for A4 paper:
|
||||
.Pp
|
||||
.Dl $ mandoc \-Tps \-Opaper=a4 mdoc.7 man.7 \*(Gt manuals.ps
|
||||
.Pp
|
||||
Convert a modern
|
||||
.Xr mdoc 7
|
||||
manual to the older
|
||||
.Xr man 7
|
||||
format, for use on systems lacking an
|
||||
.Xr mdoc 7
|
||||
parser:
|
||||
.Pp
|
||||
.Dl $ mandoc \-Tman foo.mdoc \*(Gt foo.man
|
||||
.Sh DIAGNOSTICS
|
||||
Standard error messages reporting parsing errors are prefixed by
|
||||
.Pp
|
||||
.Sm off
|
||||
.D1 Ar file : line : column : \ level :
|
||||
.Sm on
|
||||
.Pp
|
||||
where the fields have the following meanings:
|
||||
.Bl -tag -width "column"
|
||||
.It Ar file
|
||||
The name of the input file causing the message.
|
||||
.It Ar line
|
||||
The line number in that input file.
|
||||
Line numbering starts at 1.
|
||||
.It Ar column
|
||||
The column number in that input file.
|
||||
Column numbering starts at 1.
|
||||
If the issue is caused by a word, the column number usually
|
||||
points to the first character of the word.
|
||||
.It Ar level
|
||||
The message level, printed in capital letters.
|
||||
.El
|
||||
.Pp
|
||||
Message levels have the following meanings:
|
||||
.Bl -tag -width "warning"
|
||||
.It Cm fatal
|
||||
The parser is unable to parse a given input file at all.
|
||||
No formatted output is produced from that input file.
|
||||
.It Cm error
|
||||
An input file contains syntax that cannot be safely interpreted,
|
||||
either because it is invalid or because
|
||||
.Nm
|
||||
does not implement it yet.
|
||||
By discarding part of the input or inserting missing tokens,
|
||||
the parser is able to continue, and the error does not prevent
|
||||
generation of formatted output, but typically, preparing that
|
||||
output involves information loss, broken document structure
|
||||
or unintended formatting.
|
||||
.It Cm warning
|
||||
An input file uses obsolete, discouraged or non-portable syntax.
|
||||
All the same, the meaning of the input is unambiguous and a correct
|
||||
rendering can be produced.
|
||||
Documents causing warnings may render poorly when using other
|
||||
formatting tools instead of
|
||||
.Nm .
|
||||
.El
|
||||
.Pp
|
||||
Messages of the
|
||||
.Cm warning
|
||||
and
|
||||
.Cm error
|
||||
levels are hidden unless their level, or a lower level, is requested using a
|
||||
.Fl W
|
||||
option or
|
||||
.Fl T Ns Cm lint
|
||||
output mode.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
utility may also print messages related to invalid command line arguments
|
||||
or operating system errors, for example when memory is exhausted or
|
||||
input files cannot be read.
|
||||
Such messages do not carry the prefix described above.
|
||||
.Sh COMPATIBILITY
|
||||
This section summarises
|
||||
.Nm
|
||||
compatibility with GNU troff.
|
||||
Each input and output format is separately noted.
|
||||
.Ss ASCII Compatibility
|
||||
.Bl -bullet -compact
|
||||
.It
|
||||
Unrenderable unicode codepoints specified with
|
||||
.Sq \e[uNNNN]
|
||||
escapes are printed as
|
||||
.Sq \&?
|
||||
in mandoc.
|
||||
In GNU troff, these raise an error.
|
||||
.It
|
||||
The
|
||||
.Sq \&Bd \-literal
|
||||
and
|
||||
.Sq \&Bd \-unfilled
|
||||
macros of
|
||||
.Xr mdoc 7
|
||||
in
|
||||
.Fl T Ns Cm ascii
|
||||
are synonyms, as are \-filled and \-ragged.
|
||||
.It
|
||||
In historic GNU troff, the
|
||||
.Sq \&Pa
|
||||
.Xr mdoc 7
|
||||
macro does not underline when scoped under an
|
||||
.Sq \&It
|
||||
in the FILES section.
|
||||
This behaves correctly in
|
||||
.Nm .
|
||||
.It
|
||||
A list or display following the
|
||||
.Sq \&Ss
|
||||
.Xr mdoc 7
|
||||
macro in
|
||||
.Fl T Ns Cm ascii
|
||||
does not assert a prior vertical break, just as it doesn't with
|
||||
.Sq \&Sh .
|
||||
.It
|
||||
The
|
||||
.Sq \&na
|
||||
.Xr man 7
|
||||
macro in
|
||||
.Fl T Ns Cm ascii
|
||||
has no effect.
|
||||
.It
|
||||
Words aren't hyphenated.
|
||||
.El
|
||||
.Ss HTML/XHTML Compatibility
|
||||
.Bl -bullet -compact
|
||||
.It
|
||||
The
|
||||
.Sq \efP
|
||||
escape will revert the font to the previous
|
||||
.Sq \ef
|
||||
escape, not to the last rendered decoration, which is now dictated by
|
||||
CSS instead of hard-coded.
|
||||
It also will not span past the current scope,
|
||||
for the same reason.
|
||||
Note that in
|
||||
.Sx ASCII Output
|
||||
mode, this will work fine.
|
||||
.It
|
||||
The
|
||||
.Xr mdoc 7
|
||||
.Sq \&Bl \-hang
|
||||
and
|
||||
.Sq \&Bl \-tag
|
||||
list types render similarly (no break following overreached left-hand
|
||||
side) due to the expressive constraints of HTML.
|
||||
.It
|
||||
The
|
||||
.Xr man 7
|
||||
.Sq IP
|
||||
and
|
||||
.Sq TP
|
||||
lists render similarly.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr eqn 7 ,
|
||||
.Xr man 7 ,
|
||||
.Xr mandoc_char 7 ,
|
||||
.Xr mdoc 7 ,
|
||||
.Xr roff 7 ,
|
||||
.Xr tbl 7
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Nm
|
||||
utility was written by
|
||||
.An Kristaps Dzonsons ,
|
||||
.Mt kristaps@bsd.lv .
|
||||
.Sh CAVEATS
|
||||
In
|
||||
.Fl T Ns Cm html
|
||||
and
|
||||
.Fl T Ns Cm xhtml ,
|
||||
the maximum size of an element attribute is determined by
|
||||
.Dv BUFSIZ ,
|
||||
which is usually 1024 bytes.
|
||||
Be aware of this when setting long link
|
||||
formats such as
|
||||
.Fl O Ns Cm style Ns = Ns Ar really/long/link .
|
||||
.Pp
|
||||
Nesting elements within next-line element scopes of
|
||||
.Fl m Ns Cm an ,
|
||||
such as
|
||||
.Sq br
|
||||
within an empty
|
||||
.Sq B ,
|
||||
will confuse
|
||||
.Fl T Ns Cm html
|
||||
and
|
||||
.Fl T Ns Cm xhtml
|
||||
and cause them to forget the formatting of the prior next-line scope.
|
||||
.Pp
|
||||
The
|
||||
.Sq \(aq
|
||||
control character is an alias for the standard macro control character
|
||||
and does not emit a line-break as stipulated in GNU troff.
|
600
contrib/mdocml/mandoc.3
Normal file
600
contrib/mdocml/mandoc.3
Normal file
@ -0,0 +1,600 @@
|
||||
.\" $Id: mandoc.3,v 1.17 2012/01/13 15:27:14 joerg Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2009, 2010, 2011 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
|
||||
.\" 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.
|
||||
.\"
|
||||
.Dd $Mdocdate: January 13 2012 $
|
||||
.Dt MANDOC 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm mandoc ,
|
||||
.Nm mandoc_escape ,
|
||||
.Nm man_meta ,
|
||||
.Nm man_mparse ,
|
||||
.Nm man_node ,
|
||||
.Nm mchars_alloc ,
|
||||
.Nm mchars_free ,
|
||||
.Nm mchars_num2char ,
|
||||
.Nm mchars_num2uc ,
|
||||
.Nm mchars_spec2cp ,
|
||||
.Nm mchars_spec2str ,
|
||||
.Nm mdoc_meta ,
|
||||
.Nm mdoc_node ,
|
||||
.Nm mparse_alloc ,
|
||||
.Nm mparse_free ,
|
||||
.Nm mparse_getkeep ,
|
||||
.Nm mparse_keep ,
|
||||
.Nm mparse_readfd ,
|
||||
.Nm mparse_reset ,
|
||||
.Nm mparse_result ,
|
||||
.Nm mparse_strerror ,
|
||||
.Nm mparse_strlevel
|
||||
.Nd mandoc macro compiler library
|
||||
.Sh LIBRARY
|
||||
.Lb mandoc
|
||||
.Sh SYNOPSIS
|
||||
.In man.h
|
||||
.In mdoc.h
|
||||
.In mandoc.h
|
||||
.Ft "enum mandoc_esc"
|
||||
.Fo mandoc_escape
|
||||
.Fa "const char **end"
|
||||
.Fa "const char **start"
|
||||
.Fa "int *sz"
|
||||
.Fc
|
||||
.Ft "const struct man_meta *"
|
||||
.Fo man_meta
|
||||
.Fa "const struct man *man"
|
||||
.Fc
|
||||
.Ft "const struct mparse *"
|
||||
.Fo man_mparse
|
||||
.Fa "const struct man *man"
|
||||
.Fc
|
||||
.Ft "const struct man_node *"
|
||||
.Fo man_node
|
||||
.Fa "const struct man *man"
|
||||
.Fc
|
||||
.Ft "struct mchars *"
|
||||
.Fn mchars_alloc
|
||||
.Ft void
|
||||
.Fn mchars_free "struct mchars *p"
|
||||
.Ft char
|
||||
.Fn mchars_num2char "const char *cp" "size_t sz"
|
||||
.Ft int
|
||||
.Fn mchars_num2uc "const char *cp" "size_t sz"
|
||||
.Ft "const char *"
|
||||
.Fo mchars_spec2str
|
||||
.Fa "const struct mchars *p"
|
||||
.Fa "const char *cp"
|
||||
.Fa "size_t sz"
|
||||
.Fa "size_t *rsz"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo mchars_spec2cp
|
||||
.Fa "const struct mchars *p"
|
||||
.Fa "const char *cp"
|
||||
.Fa "size_t sz"
|
||||
.Ft "const char *"
|
||||
.Fc
|
||||
.Ft "const struct mdoc_meta *"
|
||||
.Fo mdoc_meta
|
||||
.Fa "const struct mdoc *mdoc"
|
||||
.Fc
|
||||
.Ft "const struct mdoc_node *"
|
||||
.Fo mdoc_node
|
||||
.Fa "const struct mdoc *mdoc"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo mparse_alloc
|
||||
.Fa "enum mparset type"
|
||||
.Fa "enum mandoclevel wlevel"
|
||||
.Fa "mandocmsg msg"
|
||||
.Fa "void *msgarg"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo mparse_free
|
||||
.Fa "struct mparse *parse"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo mparse_getkeep
|
||||
.Fa "const struct mparse *parse"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo mparse_keep
|
||||
.Fa "struct mparse *parse"
|
||||
.Fc
|
||||
.Ft "enum mandoclevel"
|
||||
.Fo mparse_readfd
|
||||
.Fa "struct mparse *parse"
|
||||
.Fa "int fd"
|
||||
.Fa "const char *fname"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo mparse_reset
|
||||
.Fa "struct mparse *parse"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo mparse_result
|
||||
.Fa "struct mparse *parse"
|
||||
.Fa "struct mdoc **mdoc"
|
||||
.Fa "struct man **man"
|
||||
.Fc
|
||||
.Ft "const char *"
|
||||
.Fo mparse_strerror
|
||||
.Fa "enum mandocerr"
|
||||
.Fc
|
||||
.Ft "const char *"
|
||||
.Fo mparse_strlevel
|
||||
.Fa "enum mandoclevel"
|
||||
.Fc
|
||||
.Vt extern const char * const * man_macronames;
|
||||
.Vt extern const char * const * mdoc_argnames;
|
||||
.Vt extern const char * const * mdoc_macronames;
|
||||
.Fd "#define ASCII_NBRSP"
|
||||
.Fd "#define ASCII_HYPH"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm mandoc
|
||||
library parses a
|
||||
.Ux
|
||||
manual into an abstract syntax tree (AST).
|
||||
.Ux
|
||||
manuals are composed of
|
||||
.Xr mdoc 7
|
||||
or
|
||||
.Xr man 7 ,
|
||||
and may be mixed with
|
||||
.Xr roff 7 ,
|
||||
.Xr tbl 7 ,
|
||||
and
|
||||
.Xr eqn 7
|
||||
invocations.
|
||||
.Pp
|
||||
The following describes a general parse sequence:
|
||||
.Bl -enum
|
||||
.It
|
||||
initiate a parsing sequence with
|
||||
.Fn mparse_alloc ;
|
||||
.It
|
||||
parse files or file descriptors with
|
||||
.Fn mparse_readfd ;
|
||||
.It
|
||||
retrieve a parsed syntax tree, if the parse was successful, with
|
||||
.Fn mparse_result ;
|
||||
.It
|
||||
iterate over parse nodes with
|
||||
.Fn mdoc_node
|
||||
or
|
||||
.Fn man_node ;
|
||||
.It
|
||||
free all allocated memory with
|
||||
.Fn mparse_free ,
|
||||
or invoke
|
||||
.Fn mparse_reset
|
||||
and parse new files.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
library also contains routines for translating character strings into glyphs
|
||||
.Pq see Fn mchars_alloc
|
||||
and parsing escape sequences from strings
|
||||
.Pq see Fn mandoc_escape .
|
||||
.Sh REFERENCE
|
||||
This section documents the functions, types, and variables available
|
||||
via
|
||||
.In mandoc.h .
|
||||
.Ss Types
|
||||
.Bl -ohang
|
||||
.It Vt "enum mandoc_esc"
|
||||
An escape sequence classification.
|
||||
.It Vt "enum mandocerr"
|
||||
A fatal error, error, or warning message during parsing.
|
||||
.It Vt "enum mandoclevel"
|
||||
A classification of an
|
||||
.Vt "enum mandoclevel"
|
||||
as regards system operation.
|
||||
.It Vt "struct mchars"
|
||||
An opaque pointer to an object allowing for translation between
|
||||
character strings and glyphs.
|
||||
See
|
||||
.Fn mchars_alloc .
|
||||
.It Vt "enum mparset"
|
||||
The type of parser when reading input.
|
||||
This should usually be
|
||||
.Dv MPARSE_AUTO
|
||||
for auto-detection.
|
||||
.It Vt "struct mparse"
|
||||
An opaque pointer to a running parse sequence.
|
||||
Created with
|
||||
.Fn mparse_alloc
|
||||
and freed with
|
||||
.Fn mparse_free .
|
||||
This may be used across parsed input if
|
||||
.Fn mparse_reset
|
||||
is called between parses.
|
||||
.It Vt "mandocmsg"
|
||||
A prototype for a function to handle fatal error, error, and warning
|
||||
messages emitted by the parser.
|
||||
.El
|
||||
.Ss Functions
|
||||
.Bl -ohang
|
||||
.It Fn mandoc_escape
|
||||
Scan an escape sequence, i.e., a character string beginning with
|
||||
.Sq \e .
|
||||
Pass a pointer to the character after the
|
||||
.Sq \e
|
||||
as
|
||||
.Va end ;
|
||||
it will be set to the supremum of the parsed escape sequence unless
|
||||
returning
|
||||
.Dv ESCAPE_ERROR ,
|
||||
in which case the string is bogus and should be
|
||||
thrown away.
|
||||
If not
|
||||
.Dv ESCAPE_ERROR
|
||||
or
|
||||
.Dv ESCAPE_IGNORE ,
|
||||
.Va start
|
||||
is set to the first relevant character of the substring (font, glyph,
|
||||
whatever) of length
|
||||
.Va sz .
|
||||
Both
|
||||
.Va start
|
||||
and
|
||||
.Va sz
|
||||
may be
|
||||
.Dv NULL .
|
||||
.It Fn man_meta
|
||||
Obtain the meta-data of a successful parse.
|
||||
This may only be used on a pointer returned by
|
||||
.Fn mparse_result .
|
||||
.It Fn man_mparse
|
||||
Get the parser used for the current output.
|
||||
.It Fn man_node
|
||||
Obtain the root node of a successful parse.
|
||||
This may only be used on a pointer returned by
|
||||
.Fn mparse_result .
|
||||
.It Fn mchars_alloc
|
||||
Allocate an
|
||||
.Vt "struct mchars *"
|
||||
object for translating special characters into glyphs.
|
||||
See
|
||||
.Xr mandoc_char 7
|
||||
for an overview of special characters.
|
||||
The object must be freed with
|
||||
.Fn mchars_free .
|
||||
.It Fn mchars_free
|
||||
Free an object created with
|
||||
.Fn mchars_alloc .
|
||||
.It Fn mchars_num2char
|
||||
Convert a character index (e.g., the \eN\(aq\(aq escape) into a
|
||||
printable ASCII character.
|
||||
Returns \e0 (the nil character) if the input sequence is malformed.
|
||||
.It Fn mchars_num2uc
|
||||
Convert a hexadecimal character index (e.g., the \e[uNNNN] escape) into
|
||||
a Unicode codepoint.
|
||||
Returns \e0 (the nil character) if the input sequence is malformed.
|
||||
.It Fn mchars_spec2cp
|
||||
Convert a special character into a valid Unicode codepoint.
|
||||
Returns \-1 on failure or a non-zero Unicode codepoint on success.
|
||||
.It Fn mchars_spec2str
|
||||
Convert a special character into an ASCII string.
|
||||
Returns
|
||||
.Dv NULL
|
||||
on failure.
|
||||
.It Fn mdoc_meta
|
||||
Obtain the meta-data of a successful parse.
|
||||
This may only be used on a pointer returned by
|
||||
.Fn mparse_result .
|
||||
.It Fn mdoc_node
|
||||
Obtain the root node of a successful parse.
|
||||
This may only be used on a pointer returned by
|
||||
.Fn mparse_result .
|
||||
.It Fn mparse_alloc
|
||||
Allocate a parser.
|
||||
The same parser may be used for multiple files so long as
|
||||
.Fn mparse_reset
|
||||
is called between parses.
|
||||
.Fn mparse_free
|
||||
must be called to free the memory allocated by this function.
|
||||
.It Fn mparse_free
|
||||
Free all memory allocated by
|
||||
.Fn mparse_alloc .
|
||||
.It Fn mparse_getkeep
|
||||
Acquire the keep buffer.
|
||||
Must follow a call of
|
||||
.Fn mparse_keep .
|
||||
.It Fn mparse_keep
|
||||
Instruct the parser to retain a copy of its parsed input.
|
||||
This can be acquired with subsequent
|
||||
.Fn mparse_getkeep
|
||||
calls.
|
||||
.It Fn mparse_readfd
|
||||
Parse a file or file descriptor.
|
||||
If
|
||||
.Va fd
|
||||
is -1,
|
||||
.Va fname
|
||||
is opened for reading.
|
||||
Otherwise,
|
||||
.Va fname
|
||||
is assumed to be the name associated with
|
||||
.Va fd .
|
||||
This may be called multiple times with different parameters; however,
|
||||
.Fn mparse_reset
|
||||
should be invoked between parses.
|
||||
.It Fn mparse_reset
|
||||
Reset a parser so that
|
||||
.Fn mparse_readfd
|
||||
may be used again.
|
||||
.It Fn mparse_result
|
||||
Obtain the result of a parse.
|
||||
Only successful parses
|
||||
.Po
|
||||
i.e., those where
|
||||
.Fn mparse_readfd
|
||||
returned less than MANDOCLEVEL_FATAL
|
||||
.Pc
|
||||
should invoke this function, in which case one of the two pointers will
|
||||
be filled in.
|
||||
.It Fn mparse_strerror
|
||||
Return a statically-allocated string representation of an error code.
|
||||
.It Fn mparse_strlevel
|
||||
Return a statically-allocated string representation of a level code.
|
||||
.El
|
||||
.Ss Variables
|
||||
.Bl -ohang
|
||||
.It Va man_macronames
|
||||
The string representation of a man macro as indexed by
|
||||
.Vt "enum mant" .
|
||||
.It Va mdoc_argnames
|
||||
The string representation of a mdoc macro argument as indexed by
|
||||
.Vt "enum mdocargt" .
|
||||
.It Va mdoc_macronames
|
||||
The string representation of a mdoc macro as indexed by
|
||||
.Vt "enum mdoct" .
|
||||
.El
|
||||
.Sh IMPLEMENTATION NOTES
|
||||
This section consists of structural documentation for
|
||||
.Xr mdoc 7
|
||||
and
|
||||
.Xr man 7
|
||||
syntax trees and strings.
|
||||
.Ss Man and Mdoc Strings
|
||||
Strings may be extracted from mdoc and man meta-data, or from text
|
||||
nodes (MDOC_TEXT and MAN_TEXT, respectively).
|
||||
These strings have special non-printing formatting cues embedded in the
|
||||
text itself, as well as
|
||||
.Xr roff 7
|
||||
escapes preserved from input.
|
||||
Implementing systems will need to handle both situations to produce
|
||||
human-readable text.
|
||||
In general, strings may be assumed to consist of 7-bit ASCII characters.
|
||||
.Pp
|
||||
The following non-printing characters may be embedded in text strings:
|
||||
.Bl -tag -width Ds
|
||||
.It Dv ASCII_NBRSP
|
||||
A non-breaking space character.
|
||||
.It Dv ASCII_HYPH
|
||||
A soft hyphen.
|
||||
.El
|
||||
.Pp
|
||||
Escape characters are also passed verbatim into text strings.
|
||||
An escape character is a sequence of characters beginning with the
|
||||
backslash
|
||||
.Pq Sq \e .
|
||||
To construct human-readable text, these should be intercepted with
|
||||
.Fn mandoc_escape
|
||||
and converted with one of
|
||||
.Fn mchars_num2char ,
|
||||
.Fn mchars_spec2str ,
|
||||
and so on.
|
||||
.Ss Man Abstract Syntax Tree
|
||||
This AST is governed by the ontological rules dictated in
|
||||
.Xr man 7
|
||||
and derives its terminology accordingly.
|
||||
.Pp
|
||||
The AST is composed of
|
||||
.Vt struct man_node
|
||||
nodes with element, root and text types as declared by the
|
||||
.Va type
|
||||
field.
|
||||
Each node also provides its parse point (the
|
||||
.Va line ,
|
||||
.Va sec ,
|
||||
and
|
||||
.Va pos
|
||||
fields), its position in the tree (the
|
||||
.Va parent ,
|
||||
.Va child ,
|
||||
.Va next
|
||||
and
|
||||
.Va prev
|
||||
fields) and some type-specific data.
|
||||
.Pp
|
||||
The tree itself is arranged according to the following normal form,
|
||||
where capitalised non-terminals represent nodes.
|
||||
.Pp
|
||||
.Bl -tag -width "ELEMENTXX" -compact
|
||||
.It ROOT
|
||||
\(<- mnode+
|
||||
.It mnode
|
||||
\(<- ELEMENT | TEXT | BLOCK
|
||||
.It BLOCK
|
||||
\(<- HEAD BODY
|
||||
.It HEAD
|
||||
\(<- mnode*
|
||||
.It BODY
|
||||
\(<- mnode*
|
||||
.It ELEMENT
|
||||
\(<- ELEMENT | TEXT*
|
||||
.It TEXT
|
||||
\(<- [[:ascii:]]*
|
||||
.El
|
||||
.Pp
|
||||
The only elements capable of nesting other elements are those with
|
||||
next-lint scope as documented in
|
||||
.Xr man 7 .
|
||||
.Ss Mdoc Abstract Syntax Tree
|
||||
This AST is governed by the ontological
|
||||
rules dictated in
|
||||
.Xr mdoc 7
|
||||
and derives its terminology accordingly.
|
||||
.Qq In-line
|
||||
elements described in
|
||||
.Xr mdoc 7
|
||||
are described simply as
|
||||
.Qq elements .
|
||||
.Pp
|
||||
The AST is composed of
|
||||
.Vt struct mdoc_node
|
||||
nodes with block, head, body, element, root and text types as declared
|
||||
by the
|
||||
.Va type
|
||||
field.
|
||||
Each node also provides its parse point (the
|
||||
.Va line ,
|
||||
.Va sec ,
|
||||
and
|
||||
.Va pos
|
||||
fields), its position in the tree (the
|
||||
.Va parent ,
|
||||
.Va child ,
|
||||
.Va nchild ,
|
||||
.Va next
|
||||
and
|
||||
.Va prev
|
||||
fields) and some type-specific data, in particular, for nodes generated
|
||||
from macros, the generating macro in the
|
||||
.Va tok
|
||||
field.
|
||||
.Pp
|
||||
The tree itself is arranged according to the following normal form,
|
||||
where capitalised non-terminals represent nodes.
|
||||
.Pp
|
||||
.Bl -tag -width "ELEMENTXX" -compact
|
||||
.It ROOT
|
||||
\(<- mnode+
|
||||
.It mnode
|
||||
\(<- BLOCK | ELEMENT | TEXT
|
||||
.It BLOCK
|
||||
\(<- HEAD [TEXT] (BODY [TEXT])+ [TAIL [TEXT]]
|
||||
.It ELEMENT
|
||||
\(<- TEXT*
|
||||
.It HEAD
|
||||
\(<- mnode*
|
||||
.It BODY
|
||||
\(<- mnode* [ENDBODY mnode*]
|
||||
.It TAIL
|
||||
\(<- mnode*
|
||||
.It TEXT
|
||||
\(<- [[:ascii:]]*
|
||||
.El
|
||||
.Pp
|
||||
Of note are the TEXT nodes following the HEAD, BODY and TAIL nodes of
|
||||
the BLOCK production: these refer to punctuation marks.
|
||||
Furthermore, although a TEXT node will generally have a non-zero-length
|
||||
string, in the specific case of
|
||||
.Sq \&.Bd \-literal ,
|
||||
an empty line will produce a zero-length string.
|
||||
Multiple body parts are only found in invocations of
|
||||
.Sq \&Bl \-column ,
|
||||
where a new body introduces a new phrase.
|
||||
.Pp
|
||||
The
|
||||
.Xr mdoc 7
|
||||
syntax tree accommodates for broken block structures as well.
|
||||
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 ,
|
||||
has the same
|
||||
.Va tok
|
||||
as the BLOCK it is ending, and has a
|
||||
.Va pending
|
||||
field pointing to that BLOCK's BODY node.
|
||||
It is an indirect child of that BODY node
|
||||
and has no children of its own.
|
||||
.Pp
|
||||
An ENDBODY node is generated when a block ends while one of its child
|
||||
blocks is still open, like in the following example:
|
||||
.Bd -literal -offset indent
|
||||
\&.Ao ao
|
||||
\&.Bo bo ac
|
||||
\&.Ac bc
|
||||
\&.Bc end
|
||||
.Ed
|
||||
.Pp
|
||||
This example results in the following block structure:
|
||||
.Bd -literal -offset indent
|
||||
BLOCK Ao
|
||||
HEAD Ao
|
||||
BODY Ao
|
||||
TEXT ao
|
||||
BLOCK Bo, pending -> Ao
|
||||
HEAD Bo
|
||||
BODY Bo
|
||||
TEXT bo
|
||||
TEXT ac
|
||||
ENDBODY Ao, pending -> Ao
|
||||
TEXT bc
|
||||
TEXT end
|
||||
.Ed
|
||||
.Pp
|
||||
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
|
||||
.Pp
|
||||
Support for badly-nested blocks is only provided for backward
|
||||
compatibility with some older
|
||||
.Xr mdoc 7
|
||||
implementations.
|
||||
Using badly-nested blocks is
|
||||
.Em strongly discouraged ;
|
||||
for example, the
|
||||
.Fl T Ns Cm html
|
||||
and
|
||||
.Fl T Ns Cm xhtml
|
||||
front-ends to
|
||||
.Xr mandoc 1
|
||||
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 SEE ALSO
|
||||
.Xr mandoc 1 ,
|
||||
.Xr eqn 7 ,
|
||||
.Xr man 7 ,
|
||||
.Xr mandoc_char 7 ,
|
||||
.Xr mdoc 7 ,
|
||||
.Xr roff 7 ,
|
||||
.Xr tbl 7
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Nm
|
||||
library was written by
|
||||
.An Kristaps Dzonsons ,
|
||||
.Mt kristaps@bsd.lv .
|
735
contrib/mdocml/mandoc.c
Normal file
735
contrib/mdocml/mandoc.c
Normal file
@ -0,0 +1,735 @@
|
||||
/* $Id: mandoc.c,v 1.62 2011/12/03 16:08:51 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* 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 AUTHORS DISCLAIM ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "libmandoc.h"
|
||||
|
||||
#define DATESIZE 32
|
||||
|
||||
static int a2time(time_t *, const char *, const char *);
|
||||
static char *time2a(time_t);
|
||||
static int numescape(const char *);
|
||||
|
||||
/*
|
||||
* Pass over recursive numerical expressions. This context of this
|
||||
* function is important: it's only called within character-terminating
|
||||
* escapes (e.g., \s[xxxyyy]), so all we need to do is handle initial
|
||||
* recursion: we don't care about what's in these blocks.
|
||||
* This returns the number of characters skipped or -1 if an error
|
||||
* occurs (the caller should bail).
|
||||
*/
|
||||
static int
|
||||
numescape(const char *start)
|
||||
{
|
||||
int i;
|
||||
size_t sz;
|
||||
const char *cp;
|
||||
|
||||
i = 0;
|
||||
|
||||
/* The expression consists of a subexpression. */
|
||||
|
||||
if ('\\' == start[i]) {
|
||||
cp = &start[++i];
|
||||
/*
|
||||
* Read past the end of the subexpression.
|
||||
* Bail immediately on errors.
|
||||
*/
|
||||
if (ESCAPE_ERROR == mandoc_escape(&cp, NULL, NULL))
|
||||
return(-1);
|
||||
return(i + cp - &start[i]);
|
||||
}
|
||||
|
||||
if ('(' != start[i++])
|
||||
return(0);
|
||||
|
||||
/*
|
||||
* A parenthesised subexpression. Read until the closing
|
||||
* parenthesis, making sure to handle any nested subexpressions
|
||||
* that might ruin our parse.
|
||||
*/
|
||||
|
||||
while (')' != start[i]) {
|
||||
sz = strcspn(&start[i], ")\\");
|
||||
i += (int)sz;
|
||||
|
||||
if ('\0' == start[i])
|
||||
return(-1);
|
||||
else if ('\\' != start[i])
|
||||
continue;
|
||||
|
||||
cp = &start[++i];
|
||||
if (ESCAPE_ERROR == mandoc_escape(&cp, NULL, NULL))
|
||||
return(-1);
|
||||
i += cp - &start[i];
|
||||
}
|
||||
|
||||
/* Read past the terminating ')'. */
|
||||
return(++i);
|
||||
}
|
||||
|
||||
enum mandoc_esc
|
||||
mandoc_escape(const char **end, const char **start, int *sz)
|
||||
{
|
||||
char c, term, numeric;
|
||||
int i, lim, ssz, rlim;
|
||||
const char *cp, *rstart;
|
||||
enum mandoc_esc gly;
|
||||
|
||||
cp = *end;
|
||||
rstart = cp;
|
||||
if (start)
|
||||
*start = rstart;
|
||||
i = lim = 0;
|
||||
gly = ESCAPE_ERROR;
|
||||
term = numeric = '\0';
|
||||
|
||||
switch ((c = cp[i++])) {
|
||||
/*
|
||||
* First the glyphs. There are several different forms of
|
||||
* these, but each eventually returns a substring of the glyph
|
||||
* name.
|
||||
*/
|
||||
case ('('):
|
||||
gly = ESCAPE_SPECIAL;
|
||||
lim = 2;
|
||||
break;
|
||||
case ('['):
|
||||
gly = ESCAPE_SPECIAL;
|
||||
/*
|
||||
* Unicode escapes are defined in groff as \[uXXXX] to
|
||||
* \[u10FFFF], where the contained value must be a valid
|
||||
* Unicode codepoint. Here, however, only check whether
|
||||
* it's not a zero-width escape.
|
||||
*/
|
||||
if ('u' == cp[i] && ']' != cp[i + 1])
|
||||
gly = ESCAPE_UNICODE;
|
||||
term = ']';
|
||||
break;
|
||||
case ('C'):
|
||||
if ('\'' != cp[i])
|
||||
return(ESCAPE_ERROR);
|
||||
gly = ESCAPE_SPECIAL;
|
||||
term = '\'';
|
||||
break;
|
||||
|
||||
/*
|
||||
* Handle all triggers matching \X(xy, \Xx, and \X[xxxx], where
|
||||
* 'X' is the trigger. These have opaque sub-strings.
|
||||
*/
|
||||
case ('F'):
|
||||
/* FALLTHROUGH */
|
||||
case ('g'):
|
||||
/* FALLTHROUGH */
|
||||
case ('k'):
|
||||
/* FALLTHROUGH */
|
||||
case ('M'):
|
||||
/* FALLTHROUGH */
|
||||
case ('m'):
|
||||
/* FALLTHROUGH */
|
||||
case ('n'):
|
||||
/* FALLTHROUGH */
|
||||
case ('V'):
|
||||
/* FALLTHROUGH */
|
||||
case ('Y'):
|
||||
gly = ESCAPE_IGNORE;
|
||||
/* FALLTHROUGH */
|
||||
case ('f'):
|
||||
if (ESCAPE_ERROR == gly)
|
||||
gly = ESCAPE_FONT;
|
||||
|
||||
rstart= &cp[i];
|
||||
if (start)
|
||||
*start = rstart;
|
||||
|
||||
switch (cp[i++]) {
|
||||
case ('('):
|
||||
lim = 2;
|
||||
break;
|
||||
case ('['):
|
||||
term = ']';
|
||||
break;
|
||||
default:
|
||||
lim = 1;
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
* These escapes are of the form \X'Y', where 'X' is the trigger
|
||||
* and 'Y' is any string. These have opaque sub-strings.
|
||||
*/
|
||||
case ('A'):
|
||||
/* FALLTHROUGH */
|
||||
case ('b'):
|
||||
/* FALLTHROUGH */
|
||||
case ('D'):
|
||||
/* FALLTHROUGH */
|
||||
case ('o'):
|
||||
/* FALLTHROUGH */
|
||||
case ('R'):
|
||||
/* FALLTHROUGH */
|
||||
case ('X'):
|
||||
/* FALLTHROUGH */
|
||||
case ('Z'):
|
||||
if ('\'' != cp[i++])
|
||||
return(ESCAPE_ERROR);
|
||||
gly = ESCAPE_IGNORE;
|
||||
term = '\'';
|
||||
break;
|
||||
|
||||
/*
|
||||
* These escapes are of the form \X'N', where 'X' is the trigger
|
||||
* and 'N' resolves to a numerical expression.
|
||||
*/
|
||||
case ('B'):
|
||||
/* FALLTHROUGH */
|
||||
case ('h'):
|
||||
/* FALLTHROUGH */
|
||||
case ('H'):
|
||||
/* FALLTHROUGH */
|
||||
case ('L'):
|
||||
/* FALLTHROUGH */
|
||||
case ('l'):
|
||||
gly = ESCAPE_NUMBERED;
|
||||
/* FALLTHROUGH */
|
||||
case ('S'):
|
||||
/* FALLTHROUGH */
|
||||
case ('v'):
|
||||
/* FALLTHROUGH */
|
||||
case ('w'):
|
||||
/* FALLTHROUGH */
|
||||
case ('x'):
|
||||
if (ESCAPE_ERROR == gly)
|
||||
gly = ESCAPE_IGNORE;
|
||||
if ('\'' != cp[i++])
|
||||
return(ESCAPE_ERROR);
|
||||
term = numeric = '\'';
|
||||
break;
|
||||
|
||||
/*
|
||||
* Special handling for the numbered character escape.
|
||||
* XXX Do any other escapes need similar handling?
|
||||
*/
|
||||
case ('N'):
|
||||
if ('\0' == cp[i])
|
||||
return(ESCAPE_ERROR);
|
||||
*end = &cp[++i];
|
||||
if (isdigit((unsigned char)cp[i-1]))
|
||||
return(ESCAPE_IGNORE);
|
||||
while (isdigit((unsigned char)**end))
|
||||
(*end)++;
|
||||
if (start)
|
||||
*start = &cp[i];
|
||||
if (sz)
|
||||
*sz = *end - &cp[i];
|
||||
if ('\0' != **end)
|
||||
(*end)++;
|
||||
return(ESCAPE_NUMBERED);
|
||||
|
||||
/*
|
||||
* Sizes get a special category of their own.
|
||||
*/
|
||||
case ('s'):
|
||||
gly = ESCAPE_IGNORE;
|
||||
|
||||
rstart = &cp[i];
|
||||
if (start)
|
||||
*start = rstart;
|
||||
|
||||
/* See +/- counts as a sign. */
|
||||
c = cp[i];
|
||||
if ('+' == c || '-' == c || ASCII_HYPH == c)
|
||||
++i;
|
||||
|
||||
switch (cp[i++]) {
|
||||
case ('('):
|
||||
lim = 2;
|
||||
break;
|
||||
case ('['):
|
||||
term = numeric = ']';
|
||||
break;
|
||||
case ('\''):
|
||||
term = numeric = '\'';
|
||||
break;
|
||||
default:
|
||||
lim = 1;
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
|
||||
/* See +/- counts as a sign. */
|
||||
c = cp[i];
|
||||
if ('+' == c || '-' == c || ASCII_HYPH == c)
|
||||
++i;
|
||||
|
||||
break;
|
||||
|
||||
/*
|
||||
* Anything else is assumed to be a glyph.
|
||||
*/
|
||||
default:
|
||||
gly = ESCAPE_SPECIAL;
|
||||
lim = 1;
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
|
||||
assert(ESCAPE_ERROR != gly);
|
||||
|
||||
rstart = &cp[i];
|
||||
if (start)
|
||||
*start = rstart;
|
||||
|
||||
/*
|
||||
* If a terminating block has been specified, we need to
|
||||
* handle the case of recursion, which could have their
|
||||
* own terminating blocks that mess up our parse. This, by the
|
||||
* way, means that the "start" and "size" values will be
|
||||
* effectively meaningless.
|
||||
*/
|
||||
|
||||
ssz = 0;
|
||||
if (numeric && -1 == (ssz = numescape(&cp[i])))
|
||||
return(ESCAPE_ERROR);
|
||||
|
||||
i += ssz;
|
||||
rlim = -1;
|
||||
|
||||
/*
|
||||
* We have a character terminator. Try to read up to that
|
||||
* character. If we can't (i.e., we hit the nil), then return
|
||||
* an error; if we can, calculate our length, read past the
|
||||
* terminating character, and exit.
|
||||
*/
|
||||
|
||||
if ('\0' != term) {
|
||||
*end = strchr(&cp[i], term);
|
||||
if ('\0' == *end)
|
||||
return(ESCAPE_ERROR);
|
||||
|
||||
rlim = *end - &cp[i];
|
||||
if (sz)
|
||||
*sz = rlim;
|
||||
(*end)++;
|
||||
goto out;
|
||||
}
|
||||
|
||||
assert(lim > 0);
|
||||
|
||||
/*
|
||||
* We have a numeric limit. If the string is shorter than that,
|
||||
* stop and return an error. Else adjust our endpoint, length,
|
||||
* and return the current glyph.
|
||||
*/
|
||||
|
||||
if ((size_t)lim > strlen(&cp[i]))
|
||||
return(ESCAPE_ERROR);
|
||||
|
||||
rlim = lim;
|
||||
if (sz)
|
||||
*sz = rlim;
|
||||
|
||||
*end = &cp[i] + lim;
|
||||
|
||||
out:
|
||||
assert(rlim >= 0 && rstart);
|
||||
|
||||
/* Run post-processors. */
|
||||
|
||||
switch (gly) {
|
||||
case (ESCAPE_FONT):
|
||||
/*
|
||||
* Pretend that the constant-width font modes are the
|
||||
* same as the regular font modes.
|
||||
*/
|
||||
if (2 == rlim && 'C' == *rstart)
|
||||
rstart++;
|
||||
else if (1 != rlim)
|
||||
break;
|
||||
|
||||
switch (*rstart) {
|
||||
case ('3'):
|
||||
/* FALLTHROUGH */
|
||||
case ('B'):
|
||||
gly = ESCAPE_FONTBOLD;
|
||||
break;
|
||||
case ('2'):
|
||||
/* FALLTHROUGH */
|
||||
case ('I'):
|
||||
gly = ESCAPE_FONTITALIC;
|
||||
break;
|
||||
case ('P'):
|
||||
gly = ESCAPE_FONTPREV;
|
||||
break;
|
||||
case ('1'):
|
||||
/* FALLTHROUGH */
|
||||
case ('R'):
|
||||
gly = ESCAPE_FONTROMAN;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case (ESCAPE_SPECIAL):
|
||||
if (1 != rlim)
|
||||
break;
|
||||
if ('c' == *rstart)
|
||||
gly = ESCAPE_NOSPACE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return(gly);
|
||||
}
|
||||
|
||||
void *
|
||||
mandoc_calloc(size_t num, size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
ptr = calloc(num, size);
|
||||
if (NULL == ptr) {
|
||||
perror(NULL);
|
||||
exit((int)MANDOCLEVEL_SYSERR);
|
||||
}
|
||||
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
mandoc_malloc(size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
ptr = malloc(size);
|
||||
if (NULL == ptr) {
|
||||
perror(NULL);
|
||||
exit((int)MANDOCLEVEL_SYSERR);
|
||||
}
|
||||
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
mandoc_realloc(void *ptr, size_t size)
|
||||
{
|
||||
|
||||
ptr = realloc(ptr, size);
|
||||
if (NULL == ptr) {
|
||||
perror(NULL);
|
||||
exit((int)MANDOCLEVEL_SYSERR);
|
||||
}
|
||||
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
char *
|
||||
mandoc_strndup(const char *ptr, size_t sz)
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = mandoc_malloc(sz + 1);
|
||||
memcpy(p, ptr, sz);
|
||||
p[(int)sz] = '\0';
|
||||
return(p);
|
||||
}
|
||||
|
||||
char *
|
||||
mandoc_strdup(const char *ptr)
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = strdup(ptr);
|
||||
if (NULL == p) {
|
||||
perror(NULL);
|
||||
exit((int)MANDOCLEVEL_SYSERR);
|
||||
}
|
||||
|
||||
return(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a quoted or unquoted roff-style request or macro argument.
|
||||
* Return a pointer to the parsed argument, which is either the original
|
||||
* pointer or advanced by one byte in case the argument is quoted.
|
||||
* Null-terminate the argument in place.
|
||||
* Collapse pairs of quotes inside quoted arguments.
|
||||
* Advance the argument pointer to the next argument,
|
||||
* or to the null byte terminating the argument line.
|
||||
*/
|
||||
char *
|
||||
mandoc_getarg(struct mparse *parse, char **cpp, int ln, int *pos)
|
||||
{
|
||||
char *start, *cp;
|
||||
int quoted, pairs, white;
|
||||
|
||||
/* Quoting can only start with a new word. */
|
||||
start = *cpp;
|
||||
quoted = 0;
|
||||
if ('"' == *start) {
|
||||
quoted = 1;
|
||||
start++;
|
||||
}
|
||||
|
||||
pairs = 0;
|
||||
white = 0;
|
||||
for (cp = start; '\0' != *cp; cp++) {
|
||||
/* Move left after quoted quotes and escaped backslashes. */
|
||||
if (pairs)
|
||||
cp[-pairs] = cp[0];
|
||||
if ('\\' == cp[0]) {
|
||||
if ('\\' == cp[1]) {
|
||||
/* Poor man's copy mode. */
|
||||
pairs++;
|
||||
cp++;
|
||||
} else if (0 == quoted && ' ' == cp[1])
|
||||
/* Skip escaped blanks. */
|
||||
cp++;
|
||||
} else if (0 == quoted) {
|
||||
if (' ' == cp[0]) {
|
||||
/* Unescaped blanks end unquoted args. */
|
||||
white = 1;
|
||||
break;
|
||||
}
|
||||
} else if ('"' == cp[0]) {
|
||||
if ('"' == cp[1]) {
|
||||
/* Quoted quotes collapse. */
|
||||
pairs++;
|
||||
cp++;
|
||||
} else {
|
||||
/* Unquoted quotes end quoted args. */
|
||||
quoted = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Quoted argument without a closing quote. */
|
||||
if (1 == quoted)
|
||||
mandoc_msg(MANDOCERR_BADQUOTE, parse, ln, *pos, NULL);
|
||||
|
||||
/* Null-terminate this argument and move to the next one. */
|
||||
if (pairs)
|
||||
cp[-pairs] = '\0';
|
||||
if ('\0' != *cp) {
|
||||
*cp++ = '\0';
|
||||
while (' ' == *cp)
|
||||
cp++;
|
||||
}
|
||||
*pos += (int)(cp - start) + (quoted ? 1 : 0);
|
||||
*cpp = cp;
|
||||
|
||||
if ('\0' == *cp && (white || ' ' == cp[-1]))
|
||||
mandoc_msg(MANDOCERR_EOLNSPACE, parse, ln, *pos, NULL);
|
||||
|
||||
return(start);
|
||||
}
|
||||
|
||||
static int
|
||||
a2time(time_t *t, const char *fmt, const char *p)
|
||||
{
|
||||
struct tm tm;
|
||||
char *pp;
|
||||
|
||||
memset(&tm, 0, sizeof(struct tm));
|
||||
|
||||
pp = NULL;
|
||||
#ifdef HAVE_STRPTIME
|
||||
pp = strptime(p, fmt, &tm);
|
||||
#endif
|
||||
if (NULL != pp && '\0' == *pp) {
|
||||
*t = mktime(&tm);
|
||||
return(1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static char *
|
||||
time2a(time_t t)
|
||||
{
|
||||
struct tm *tm;
|
||||
char *buf, *p;
|
||||
size_t ssz;
|
||||
int isz;
|
||||
|
||||
tm = localtime(&t);
|
||||
|
||||
/*
|
||||
* Reserve space:
|
||||
* up to 9 characters for the month (September) + blank
|
||||
* up to 2 characters for the day + comma + blank
|
||||
* 4 characters for the year and a terminating '\0'
|
||||
*/
|
||||
p = buf = mandoc_malloc(10 + 4 + 4 + 1);
|
||||
|
||||
if (0 == (ssz = strftime(p, 10 + 1, "%B ", tm)))
|
||||
goto fail;
|
||||
p += (int)ssz;
|
||||
|
||||
if (-1 == (isz = snprintf(p, 4 + 1, "%d, ", tm->tm_mday)))
|
||||
goto fail;
|
||||
p += isz;
|
||||
|
||||
if (0 == strftime(p, 4 + 1, "%Y", tm))
|
||||
goto fail;
|
||||
return(buf);
|
||||
|
||||
fail:
|
||||
free(buf);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
char *
|
||||
mandoc_normdate(struct mparse *parse, char *in, int ln, int pos)
|
||||
{
|
||||
char *out;
|
||||
time_t t;
|
||||
|
||||
if (NULL == in || '\0' == *in ||
|
||||
0 == strcmp(in, "$" "Mdocdate$")) {
|
||||
mandoc_msg(MANDOCERR_NODATE, parse, ln, pos, NULL);
|
||||
time(&t);
|
||||
}
|
||||
else if (a2time(&t, "%Y-%m-%d", in))
|
||||
t = 0;
|
||||
else if (!a2time(&t, "$" "Mdocdate: %b %d %Y $", in) &&
|
||||
!a2time(&t, "%b %d, %Y", in)) {
|
||||
mandoc_msg(MANDOCERR_BADDATE, parse, ln, pos, NULL);
|
||||
t = 0;
|
||||
}
|
||||
out = t ? time2a(t) : NULL;
|
||||
return(out ? out : mandoc_strdup(in));
|
||||
}
|
||||
|
||||
int
|
||||
mandoc_eos(const char *p, size_t sz, int enclosed)
|
||||
{
|
||||
const char *q;
|
||||
int found;
|
||||
|
||||
if (0 == sz)
|
||||
return(0);
|
||||
|
||||
/*
|
||||
* End-of-sentence recognition must include situations where
|
||||
* some symbols, such as `)', allow prior EOS punctuation to
|
||||
* propagate outward.
|
||||
*/
|
||||
|
||||
found = 0;
|
||||
for (q = p + (int)sz - 1; q >= p; q--) {
|
||||
switch (*q) {
|
||||
case ('\"'):
|
||||
/* FALLTHROUGH */
|
||||
case ('\''):
|
||||
/* FALLTHROUGH */
|
||||
case (']'):
|
||||
/* FALLTHROUGH */
|
||||
case (')'):
|
||||
if (0 == found)
|
||||
enclosed = 1;
|
||||
break;
|
||||
case ('.'):
|
||||
/* FALLTHROUGH */
|
||||
case ('!'):
|
||||
/* FALLTHROUGH */
|
||||
case ('?'):
|
||||
found = 1;
|
||||
break;
|
||||
default:
|
||||
return(found && (!enclosed || isalnum((unsigned char)*q)));
|
||||
}
|
||||
}
|
||||
|
||||
return(found && !enclosed);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find out whether a line is a macro line or not. If it is, adjust the
|
||||
* current position and return one; if it isn't, return zero and don't
|
||||
* change the current position.
|
||||
*/
|
||||
int
|
||||
mandoc_getcontrol(const char *cp, int *ppos)
|
||||
{
|
||||
int pos;
|
||||
|
||||
pos = *ppos;
|
||||
|
||||
if ('\\' == cp[pos] && '.' == cp[pos + 1])
|
||||
pos += 2;
|
||||
else if ('.' == cp[pos] || '\'' == cp[pos])
|
||||
pos++;
|
||||
else
|
||||
return(0);
|
||||
|
||||
while (' ' == cp[pos] || '\t' == cp[pos])
|
||||
pos++;
|
||||
|
||||
*ppos = pos;
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a string to a long that may not be <0.
|
||||
* If the string is invalid, or is less than 0, return -1.
|
||||
*/
|
||||
int
|
||||
mandoc_strntoi(const char *p, size_t sz, int base)
|
||||
{
|
||||
char buf[32];
|
||||
char *ep;
|
||||
long v;
|
||||
|
||||
if (sz > 31)
|
||||
return(-1);
|
||||
|
||||
memcpy(buf, p, sz);
|
||||
buf[(int)sz] = '\0';
|
||||
|
||||
errno = 0;
|
||||
v = strtol(buf, &ep, base);
|
||||
|
||||
if (buf[0] == '\0' || *ep != '\0')
|
||||
return(-1);
|
||||
|
||||
if (v > INT_MAX)
|
||||
v = INT_MAX;
|
||||
if (v < INT_MIN)
|
||||
v = INT_MIN;
|
||||
|
||||
return((int)v);
|
||||
}
|
432
contrib/mdocml/mandoc.h
Normal file
432
contrib/mdocml/mandoc.h
Normal file
@ -0,0 +1,432 @@
|
||||
/* $Id: mandoc.h,v 1.99 2012/02/16 20:51:31 joerg Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2010, 2011 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 MANDOC_H
|
||||
#define MANDOC_H
|
||||
|
||||
#define ASCII_NBRSP 31 /* non-breaking space */
|
||||
#define ASCII_HYPH 30 /* breakable hyphen */
|
||||
|
||||
/*
|
||||
* Status level. This refers to both internal status (i.e., whilst
|
||||
* running, when warnings/errors are reported) and an indicator of a
|
||||
* threshold of when to halt (when said internal state exceeds the
|
||||
* threshold).
|
||||
*/
|
||||
enum mandoclevel {
|
||||
MANDOCLEVEL_OK = 0,
|
||||
MANDOCLEVEL_RESERVED,
|
||||
MANDOCLEVEL_WARNING, /* warnings: syntax, whitespace, etc. */
|
||||
MANDOCLEVEL_ERROR, /* input has been thrown away */
|
||||
MANDOCLEVEL_FATAL, /* input is borked */
|
||||
MANDOCLEVEL_BADARG, /* bad argument in invocation */
|
||||
MANDOCLEVEL_SYSERR, /* system error */
|
||||
MANDOCLEVEL_MAX
|
||||
};
|
||||
|
||||
/*
|
||||
* All possible things that can go wrong within a parse, be it libroff,
|
||||
* libmdoc, or libman.
|
||||
*/
|
||||
enum mandocerr {
|
||||
MANDOCERR_OK,
|
||||
|
||||
MANDOCERR_WARNING, /* ===== start of warnings ===== */
|
||||
|
||||
/* related to the prologue */
|
||||
MANDOCERR_NOTITLE, /* no title in document */
|
||||
MANDOCERR_UPPERCASE, /* document title should be all caps */
|
||||
MANDOCERR_BADMSEC, /* unknown manual section */
|
||||
MANDOCERR_NODATE, /* date missing, using today's date */
|
||||
MANDOCERR_BADDATE, /* cannot parse date, using it verbatim */
|
||||
MANDOCERR_PROLOGOOO, /* prologue macros out of order */
|
||||
MANDOCERR_PROLOGREP, /* duplicate prologue macro */
|
||||
MANDOCERR_BADPROLOG, /* macro not allowed in prologue */
|
||||
MANDOCERR_BADBODY, /* macro not allowed in body */
|
||||
|
||||
/* related to document structure */
|
||||
MANDOCERR_SO, /* .so is fragile, better use ln(1) */
|
||||
MANDOCERR_NAMESECFIRST, /* NAME section must come first */
|
||||
MANDOCERR_BADNAMESEC, /* bad NAME section contents */
|
||||
MANDOCERR_NONAME, /* manual name not yet set */
|
||||
MANDOCERR_SECOOO, /* sections out of conventional order */
|
||||
MANDOCERR_SECREP, /* duplicate section name */
|
||||
MANDOCERR_SECMSEC, /* section not in conventional manual section */
|
||||
|
||||
/* related to macros and nesting */
|
||||
MANDOCERR_MACROOBS, /* skipping obsolete macro */
|
||||
MANDOCERR_IGNPAR, /* skipping paragraph macro */
|
||||
MANDOCERR_IGNNS, /* skipping no-space macro */
|
||||
MANDOCERR_SCOPENEST, /* blocks badly nested */
|
||||
MANDOCERR_CHILD, /* child violates parent syntax */
|
||||
MANDOCERR_NESTEDDISP, /* nested displays are not portable */
|
||||
MANDOCERR_SCOPEREP, /* already in literal mode */
|
||||
MANDOCERR_LINESCOPE, /* line scope broken */
|
||||
|
||||
/* related to missing macro arguments */
|
||||
MANDOCERR_MACROEMPTY, /* skipping empty macro */
|
||||
MANDOCERR_ARGCWARN, /* argument count wrong */
|
||||
MANDOCERR_DISPTYPE, /* missing display type */
|
||||
MANDOCERR_LISTFIRST, /* list type must come first */
|
||||
MANDOCERR_NOWIDTHARG, /* tag lists require a width argument */
|
||||
MANDOCERR_FONTTYPE, /* missing font type */
|
||||
MANDOCERR_WNOSCOPE, /* skipping end of block that is not open */
|
||||
|
||||
/* related to bad macro arguments */
|
||||
MANDOCERR_IGNARGV, /* skipping argument */
|
||||
MANDOCERR_ARGVREP, /* duplicate argument */
|
||||
MANDOCERR_DISPREP, /* duplicate display type */
|
||||
MANDOCERR_LISTREP, /* duplicate list type */
|
||||
MANDOCERR_BADATT, /* unknown AT&T UNIX version */
|
||||
MANDOCERR_BADBOOL, /* bad Boolean value */
|
||||
MANDOCERR_BADFONT, /* unknown font */
|
||||
MANDOCERR_BADSTANDARD, /* unknown standard specifier */
|
||||
MANDOCERR_BADWIDTH, /* bad width argument */
|
||||
|
||||
/* related to plain text */
|
||||
MANDOCERR_NOBLANKLN, /* blank line in non-literal context */
|
||||
MANDOCERR_BADTAB, /* tab in non-literal context */
|
||||
MANDOCERR_EOLNSPACE, /* end of line whitespace */
|
||||
MANDOCERR_BADCOMMENT, /* bad comment style */
|
||||
MANDOCERR_BADESCAPE, /* unknown escape sequence */
|
||||
MANDOCERR_BADQUOTE, /* unterminated quoted string */
|
||||
|
||||
/* related to equations */
|
||||
MANDOCERR_EQNQUOTE, /* unexpected literal in equation */
|
||||
|
||||
MANDOCERR_ERROR, /* ===== start of errors ===== */
|
||||
|
||||
/* related to equations */
|
||||
MANDOCERR_EQNNSCOPE, /* unexpected equation scope closure*/
|
||||
MANDOCERR_EQNSCOPE, /* equation scope open on exit */
|
||||
MANDOCERR_EQNBADSCOPE, /* overlapping equation scopes */
|
||||
MANDOCERR_EQNEOF, /* unexpected end of equation */
|
||||
MANDOCERR_EQNSYNT, /* equation syntax error */
|
||||
|
||||
/* related to tables */
|
||||
MANDOCERR_TBL, /* bad table syntax */
|
||||
MANDOCERR_TBLOPT, /* bad table option */
|
||||
MANDOCERR_TBLLAYOUT, /* bad table layout */
|
||||
MANDOCERR_TBLNOLAYOUT, /* no table layout cells specified */
|
||||
MANDOCERR_TBLNODATA, /* no table data cells specified */
|
||||
MANDOCERR_TBLIGNDATA, /* ignore data in cell */
|
||||
MANDOCERR_TBLBLOCK, /* data block still open */
|
||||
MANDOCERR_TBLEXTRADAT, /* ignoring extra data cells */
|
||||
|
||||
MANDOCERR_ROFFLOOP, /* input stack limit exceeded, infinite loop? */
|
||||
MANDOCERR_BADCHAR, /* skipping bad character */
|
||||
MANDOCERR_NAMESC, /* escaped character not allowed in a name */
|
||||
MANDOCERR_NOTEXT, /* skipping text before the first section header */
|
||||
MANDOCERR_MACRO, /* skipping unknown macro */
|
||||
MANDOCERR_REQUEST, /* NOT IMPLEMENTED: skipping request */
|
||||
MANDOCERR_ARGCOUNT, /* argument count wrong */
|
||||
MANDOCERR_NOSCOPE, /* skipping end of block that is not open */
|
||||
MANDOCERR_SCOPEBROKEN, /* missing end of block */
|
||||
MANDOCERR_SCOPEEXIT, /* scope open on exit */
|
||||
MANDOCERR_UNAME, /* uname(3) system call failed */
|
||||
/* FIXME: merge following with MANDOCERR_ARGCOUNT */
|
||||
MANDOCERR_NOARGS, /* macro requires line argument(s) */
|
||||
MANDOCERR_NOBODY, /* macro requires body argument(s) */
|
||||
MANDOCERR_NOARGV, /* macro requires argument(s) */
|
||||
MANDOCERR_LISTTYPE, /* missing list type */
|
||||
MANDOCERR_ARGSLOST, /* line argument(s) will be lost */
|
||||
MANDOCERR_BODYLOST, /* body argument(s) will be lost */
|
||||
|
||||
MANDOCERR_FATAL, /* ===== start of fatal errors ===== */
|
||||
|
||||
MANDOCERR_NOTMANUAL, /* manual isn't really a manual */
|
||||
MANDOCERR_COLUMNS, /* column syntax is inconsistent */
|
||||
MANDOCERR_BADDISP, /* NOT IMPLEMENTED: .Bd -file */
|
||||
MANDOCERR_SYNTARGVCOUNT, /* argument count wrong, violates syntax */
|
||||
MANDOCERR_SYNTCHILD, /* child violates parent syntax */
|
||||
MANDOCERR_SYNTARGCOUNT, /* argument count wrong, violates syntax */
|
||||
MANDOCERR_SOPATH, /* NOT IMPLEMENTED: .so with absolute path or ".." */
|
||||
MANDOCERR_NODOCBODY, /* no document body */
|
||||
MANDOCERR_NODOCPROLOG, /* no document prologue */
|
||||
MANDOCERR_MEM, /* static buffer exhausted */
|
||||
MANDOCERR_MAX
|
||||
};
|
||||
|
||||
struct tbl {
|
||||
char tab; /* cell-separator */
|
||||
char decimal; /* decimal point */
|
||||
int linesize;
|
||||
int opts;
|
||||
#define TBL_OPT_CENTRE (1 << 0)
|
||||
#define TBL_OPT_EXPAND (1 << 1)
|
||||
#define TBL_OPT_BOX (1 << 2)
|
||||
#define TBL_OPT_DBOX (1 << 3)
|
||||
#define TBL_OPT_ALLBOX (1 << 4)
|
||||
#define TBL_OPT_NOKEEP (1 << 5)
|
||||
#define TBL_OPT_NOSPACE (1 << 6)
|
||||
int cols; /* number of columns */
|
||||
};
|
||||
|
||||
enum tbl_headt {
|
||||
TBL_HEAD_DATA, /* plug in data from tbl_dat */
|
||||
TBL_HEAD_VERT, /* vertical spacer */
|
||||
TBL_HEAD_DVERT /* double-vertical spacer */
|
||||
};
|
||||
|
||||
/*
|
||||
* The head of a table specifies all of its columns. When formatting a
|
||||
* tbl_span, iterate over these and plug in data from the tbl_span when
|
||||
* appropriate, using tbl_cell as a guide to placement.
|
||||
*/
|
||||
struct tbl_head {
|
||||
enum tbl_headt pos;
|
||||
int ident; /* 0 <= unique id < cols */
|
||||
struct tbl_head *next;
|
||||
struct tbl_head *prev;
|
||||
};
|
||||
|
||||
enum tbl_cellt {
|
||||
TBL_CELL_CENTRE, /* c, C */
|
||||
TBL_CELL_RIGHT, /* r, R */
|
||||
TBL_CELL_LEFT, /* l, L */
|
||||
TBL_CELL_NUMBER, /* n, N */
|
||||
TBL_CELL_SPAN, /* s, S */
|
||||
TBL_CELL_LONG, /* a, A */
|
||||
TBL_CELL_DOWN, /* ^ */
|
||||
TBL_CELL_HORIZ, /* _, - */
|
||||
TBL_CELL_DHORIZ, /* = */
|
||||
TBL_CELL_VERT, /* | */
|
||||
TBL_CELL_DVERT, /* || */
|
||||
TBL_CELL_MAX
|
||||
};
|
||||
|
||||
/*
|
||||
* A cell in a layout row.
|
||||
*/
|
||||
struct tbl_cell {
|
||||
struct tbl_cell *next;
|
||||
enum tbl_cellt pos;
|
||||
size_t spacing;
|
||||
int flags;
|
||||
#define TBL_CELL_TALIGN (1 << 0) /* t, T */
|
||||
#define TBL_CELL_BALIGN (1 << 1) /* d, D */
|
||||
#define TBL_CELL_BOLD (1 << 2) /* fB, B, b */
|
||||
#define TBL_CELL_ITALIC (1 << 3) /* fI, I, i */
|
||||
#define TBL_CELL_EQUAL (1 << 4) /* e, E */
|
||||
#define TBL_CELL_UP (1 << 5) /* u, U */
|
||||
#define TBL_CELL_WIGN (1 << 6) /* z, Z */
|
||||
struct tbl_head *head;
|
||||
};
|
||||
|
||||
/*
|
||||
* A layout row.
|
||||
*/
|
||||
struct tbl_row {
|
||||
struct tbl_row *next;
|
||||
struct tbl_cell *first;
|
||||
struct tbl_cell *last;
|
||||
};
|
||||
|
||||
enum tbl_datt {
|
||||
TBL_DATA_NONE, /* has no data */
|
||||
TBL_DATA_DATA, /* consists of data/string */
|
||||
TBL_DATA_HORIZ, /* horizontal line */
|
||||
TBL_DATA_DHORIZ, /* double-horizontal line */
|
||||
TBL_DATA_NHORIZ, /* squeezed horizontal line */
|
||||
TBL_DATA_NDHORIZ /* squeezed double-horizontal line */
|
||||
};
|
||||
|
||||
/*
|
||||
* A cell within a row of data. The "string" field contains the actual
|
||||
* string value that's in the cell. The rest is layout.
|
||||
*/
|
||||
struct tbl_dat {
|
||||
struct tbl_cell *layout; /* layout cell */
|
||||
int spans; /* how many spans follow */
|
||||
struct tbl_dat *next;
|
||||
char *string; /* data (NULL if not TBL_DATA_DATA) */
|
||||
enum tbl_datt pos;
|
||||
};
|
||||
|
||||
enum tbl_spant {
|
||||
TBL_SPAN_DATA, /* span consists of data */
|
||||
TBL_SPAN_HORIZ, /* span is horizontal line */
|
||||
TBL_SPAN_DHORIZ /* span is double horizontal line */
|
||||
};
|
||||
|
||||
/*
|
||||
* A row of data in a table.
|
||||
*/
|
||||
struct tbl_span {
|
||||
struct tbl *tbl;
|
||||
struct tbl_head *head;
|
||||
struct tbl_row *layout; /* layout row */
|
||||
struct tbl_dat *first;
|
||||
struct tbl_dat *last;
|
||||
int line; /* parse line */
|
||||
int flags;
|
||||
#define TBL_SPAN_FIRST (1 << 0)
|
||||
#define TBL_SPAN_LAST (1 << 1)
|
||||
enum tbl_spant pos;
|
||||
struct tbl_span *next;
|
||||
};
|
||||
|
||||
enum eqn_boxt {
|
||||
EQN_ROOT, /* root of parse tree */
|
||||
EQN_TEXT, /* text (number, variable, whatever) */
|
||||
EQN_SUBEXPR, /* nested `eqn' subexpression */
|
||||
EQN_LIST, /* subexpressions list */
|
||||
EQN_MATRIX /* matrix subexpression */
|
||||
};
|
||||
|
||||
enum eqn_markt {
|
||||
EQNMARK_NONE = 0,
|
||||
EQNMARK_DOT,
|
||||
EQNMARK_DOTDOT,
|
||||
EQNMARK_HAT,
|
||||
EQNMARK_TILDE,
|
||||
EQNMARK_VEC,
|
||||
EQNMARK_DYAD,
|
||||
EQNMARK_BAR,
|
||||
EQNMARK_UNDER,
|
||||
EQNMARK__MAX
|
||||
};
|
||||
|
||||
enum eqn_fontt {
|
||||
EQNFONT_NONE = 0,
|
||||
EQNFONT_ROMAN,
|
||||
EQNFONT_BOLD,
|
||||
EQNFONT_FAT,
|
||||
EQNFONT_ITALIC,
|
||||
EQNFONT__MAX
|
||||
};
|
||||
|
||||
enum eqn_post {
|
||||
EQNPOS_NONE = 0,
|
||||
EQNPOS_OVER,
|
||||
EQNPOS_SUP,
|
||||
EQNPOS_SUB,
|
||||
EQNPOS_TO,
|
||||
EQNPOS_FROM,
|
||||
EQNPOS__MAX
|
||||
};
|
||||
|
||||
enum eqn_pilet {
|
||||
EQNPILE_NONE = 0,
|
||||
EQNPILE_PILE,
|
||||
EQNPILE_CPILE,
|
||||
EQNPILE_RPILE,
|
||||
EQNPILE_LPILE,
|
||||
EQNPILE_COL,
|
||||
EQNPILE_CCOL,
|
||||
EQNPILE_RCOL,
|
||||
EQNPILE_LCOL,
|
||||
EQNPILE__MAX
|
||||
};
|
||||
|
||||
/*
|
||||
* A "box" is a parsed mathematical expression as defined by the eqn.7
|
||||
* grammar.
|
||||
*/
|
||||
struct eqn_box {
|
||||
int size; /* font size of expression */
|
||||
#define EQN_DEFSIZE INT_MIN
|
||||
enum eqn_boxt type; /* type of node */
|
||||
struct eqn_box *first; /* first child node */
|
||||
struct eqn_box *last; /* last child node */
|
||||
struct eqn_box *next; /* node sibling */
|
||||
struct eqn_box *parent; /* node sibling */
|
||||
char *text; /* text (or NULL) */
|
||||
char *left;
|
||||
char *right;
|
||||
enum eqn_post pos; /* position of next box */
|
||||
enum eqn_markt mark; /* a mark about the box */
|
||||
enum eqn_fontt font; /* font of box */
|
||||
enum eqn_pilet pile; /* equation piling */
|
||||
};
|
||||
|
||||
/*
|
||||
* An equation consists of a tree of expressions starting at a given
|
||||
* line and position.
|
||||
*/
|
||||
struct eqn {
|
||||
char *name; /* identifier (or NULL) */
|
||||
struct eqn_box *root; /* root mathematical expression */
|
||||
int ln; /* invocation line */
|
||||
int pos; /* invocation position */
|
||||
};
|
||||
|
||||
/*
|
||||
* The type of parse sequence. This value is usually passed via the
|
||||
* mandoc(1) command line of -man and -mdoc. It's almost exclusively
|
||||
* -mandoc but the others have been retained for compatibility.
|
||||
*/
|
||||
enum mparset {
|
||||
MPARSE_AUTO, /* magically determine the document type */
|
||||
MPARSE_MDOC, /* assume -mdoc */
|
||||
MPARSE_MAN /* assume -man */
|
||||
};
|
||||
|
||||
enum mandoc_esc {
|
||||
ESCAPE_ERROR = 0, /* bail! unparsable escape */
|
||||
ESCAPE_IGNORE, /* escape to be ignored */
|
||||
ESCAPE_SPECIAL, /* a regular special character */
|
||||
ESCAPE_FONT, /* a generic font mode */
|
||||
ESCAPE_FONTBOLD, /* bold font mode */
|
||||
ESCAPE_FONTITALIC, /* italic font mode */
|
||||
ESCAPE_FONTROMAN, /* roman font mode */
|
||||
ESCAPE_FONTPREV, /* previous font mode */
|
||||
ESCAPE_NUMBERED, /* a numbered glyph */
|
||||
ESCAPE_UNICODE, /* a unicode codepoint */
|
||||
ESCAPE_NOSPACE /* suppress space if the last on a line */
|
||||
};
|
||||
|
||||
typedef void (*mandocmsg)(enum mandocerr, enum mandoclevel,
|
||||
const char *, int, int, const char *);
|
||||
|
||||
struct mparse;
|
||||
struct mchars;
|
||||
struct mdoc;
|
||||
struct man;
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
void *mandoc_calloc(size_t, size_t);
|
||||
enum mandoc_esc mandoc_escape(const char **, const char **, int *);
|
||||
void *mandoc_malloc(size_t);
|
||||
void *mandoc_realloc(void *, size_t);
|
||||
char *mandoc_strdup(const char *);
|
||||
char *mandoc_strndup(const char *, size_t);
|
||||
struct mchars *mchars_alloc(void);
|
||||
void mchars_free(struct mchars *);
|
||||
char mchars_num2char(const char *, size_t);
|
||||
int mchars_num2uc(const char *, size_t);
|
||||
int mchars_spec2cp(const struct mchars *,
|
||||
const char *, size_t);
|
||||
const char *mchars_spec2str(const struct mchars *,
|
||||
const char *, size_t, size_t *);
|
||||
struct mparse *mparse_alloc(enum mparset,
|
||||
enum mandoclevel, mandocmsg, void *);
|
||||
void mparse_free(struct mparse *);
|
||||
void mparse_keep(struct mparse *);
|
||||
enum mandoclevel mparse_readfd(struct mparse *, int, const char *);
|
||||
enum mandoclevel mparse_readmem(struct mparse *, const void *, size_t,
|
||||
const char *);
|
||||
void mparse_reset(struct mparse *);
|
||||
void mparse_result(struct mparse *,
|
||||
struct mdoc **, struct man **);
|
||||
const char *mparse_getkeep(const struct mparse *);
|
||||
const char *mparse_strerror(enum mandocerr);
|
||||
const char *mparse_strlevel(enum mandoclevel);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /*!MANDOC_H*/
|
743
contrib/mdocml/mandoc_char.7
Normal file
743
contrib/mdocml/mandoc_char.7
Normal file
@ -0,0 +1,743 @@
|
||||
.\" $Id: mandoc_char.7,v 1.51 2011/11/23 10:09:30 kristaps Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2003 Jason McIntyre <jmc@openbsd.org>
|
||||
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
.\" 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.
|
||||
.\"
|
||||
.Dd $Mdocdate: November 23 2011 $
|
||||
.Dt MANDOC_CHAR 7
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm mandoc_char
|
||||
.Nd mandoc special characters
|
||||
.Sh DESCRIPTION
|
||||
This page documents the
|
||||
.Xr roff 7
|
||||
escape sequences accepted by
|
||||
.Xr mandoc 1
|
||||
to represent special characters in
|
||||
.Xr mdoc 7
|
||||
and
|
||||
.Xr man 7
|
||||
documents.
|
||||
.Pp
|
||||
The rendering depends on the
|
||||
.Xr mandoc 1
|
||||
output mode; in ASCII output, most characters are completely
|
||||
unintelligible.
|
||||
For that reason, using any of the special characters documented here,
|
||||
except those discussed in the
|
||||
.Sx DESCRIPTION ,
|
||||
is strongly discouraged; they are supported merely for backwards
|
||||
compatibility with existing documents.
|
||||
.Pp
|
||||
In particular, in English manual pages, do not use special-character
|
||||
escape sequences to represent national language characters in author
|
||||
names; instead, provide ASCII transcriptions of the names.
|
||||
.Ss Dashes and Hyphens
|
||||
In typography there are different types of dashes of various width:
|
||||
the hyphen (-),
|
||||
the minus sign (\-),
|
||||
the en-dash (\(en),
|
||||
and the em-dash (\(em).
|
||||
.Pp
|
||||
Hyphens are used for adjectives;
|
||||
to separate the two parts of a compound word;
|
||||
or to separate a word across two successive lines of text.
|
||||
The hyphen does not need to be escaped:
|
||||
.Bd -unfilled -offset indent
|
||||
blue-eyed
|
||||
lorry-driver
|
||||
.Ed
|
||||
.Pp
|
||||
The mathematical minus sign is used for negative numbers or subtraction.
|
||||
It should be written as
|
||||
.Sq \e- :
|
||||
.Bd -unfilled -offset indent
|
||||
a = 3 \e- 1;
|
||||
b = \e-2;
|
||||
.Ed
|
||||
.Pp
|
||||
The en-dash is used to separate the two elements of a range,
|
||||
or can be used the same way as an em-dash.
|
||||
It should be written as
|
||||
.Sq \e(en :
|
||||
.Bd -unfilled -offset indent
|
||||
pp. 95\e(en97.
|
||||
Go away \e(en or else!
|
||||
.Ed
|
||||
.Pp
|
||||
The em-dash can be used to show an interruption
|
||||
or can be used the same way as colons, semi-colons, or parentheses.
|
||||
It should be written as
|
||||
.Sq \e(em :
|
||||
.Bd -unfilled -offset indent
|
||||
Three things \e(em apples, oranges, and bananas.
|
||||
This is not that \e(em rather, this is that.
|
||||
.Ed
|
||||
.Pp
|
||||
Note:
|
||||
hyphens, minus signs, and en-dashes look identical under normal ASCII output.
|
||||
Other formats, such as PostScript, render them correctly,
|
||||
with differing widths.
|
||||
.Ss Spaces
|
||||
To separate words in normal text, for indenting and alignment
|
||||
in literal context, and when none of the following special cases apply,
|
||||
just use the normal space character
|
||||
.Pq Sq \ .
|
||||
.Pp
|
||||
When filling text, lines may be broken between words, i.e. at space
|
||||
characters.
|
||||
To prevent a line break between two particular words,
|
||||
use the non-breaking space escape sequence
|
||||
.Pq Sq \e~
|
||||
instead of the normal space character.
|
||||
For example, the input string
|
||||
.Dq number\e~1
|
||||
will be kept together as
|
||||
.Dq number\~1
|
||||
on the same output line.
|
||||
.Pp
|
||||
On request and macro lines, the normal space character serves as an
|
||||
argument delimiter.
|
||||
To include whitespace into arguments, quoting is usually the best choice.
|
||||
In some cases, using either the non-breaking
|
||||
.Pq Sq \e~
|
||||
or the breaking
|
||||
.Pq Sq \e\ \&
|
||||
space escape sequence may be preferable.
|
||||
To escape macro names and to protect whitespace at the end
|
||||
of input lines, the zero-width space
|
||||
.Pq Sq \e&
|
||||
is often useful.
|
||||
For example, in
|
||||
.Xr mdoc 7 ,
|
||||
a normal space character can be displayed in single quotes in either
|
||||
of the following ways:
|
||||
.Pp
|
||||
.Dl .Sq \(dq \(dq
|
||||
.Dl .Sq \e \e&
|
||||
.Ss Quotes
|
||||
On request and macro lines, the double-quote character
|
||||
.Pq Sq \(dq
|
||||
is handled specially to allow quoting.
|
||||
One way to prevent this special handling is by using the
|
||||
.Sq \e(dq
|
||||
escape sequence.
|
||||
.Pp
|
||||
Note that on text lines, literal double-quote characters can be used
|
||||
verbatim.
|
||||
All other quote-like characters can be used verbatim as well,
|
||||
even on request and macro lines.
|
||||
.Ss Periods
|
||||
The period
|
||||
.Pq Sq \&.
|
||||
is handled specially at the beginning of an input line,
|
||||
where it introduces a
|
||||
.Xr roff 7
|
||||
request or a macro, and when appearing alone as a macro argument in
|
||||
.Xr mdoc 7 .
|
||||
In such situations, prepend a zero-width space
|
||||
.Pq Sq \e&.
|
||||
to make it behave like normal text.
|
||||
.Pp
|
||||
Do not use the
|
||||
.Sq \e.
|
||||
escape sequence.
|
||||
It does not prevent special handling of the period.
|
||||
.Ss Backslashes
|
||||
To include a literal backslash
|
||||
.Pq Sq \e
|
||||
into the output, use the
|
||||
.Pq Sq \ee
|
||||
escape sequence.
|
||||
.Pp
|
||||
Note that doubling it
|
||||
.Pq Sq \e\e
|
||||
is not the right way to output a backslash.
|
||||
Because
|
||||
.Xr mandoc 1
|
||||
does not implement full
|
||||
.Xr roff 7
|
||||
functionality, it may work with
|
||||
.Xr mandoc 1 ,
|
||||
but it may have weird effects on complete
|
||||
.Xr roff 7
|
||||
implementations.
|
||||
.Sh SPECIAL CHARACTERS
|
||||
Special characters are encoded as
|
||||
.Sq \eX
|
||||
.Pq for a one-character escape ,
|
||||
.Sq \e(XX
|
||||
.Pq two-character ,
|
||||
and
|
||||
.Sq \e[N]
|
||||
.Pq N-character .
|
||||
For details, see the
|
||||
.Em Special Characters
|
||||
subsection of the
|
||||
.Xr roff 7
|
||||
manual.
|
||||
.Pp
|
||||
Spacing:
|
||||
.Bl -column "Input" "Description" -offset indent -compact
|
||||
.It Em Input Ta Em Description
|
||||
.It \e~ Ta non-breaking, non-collapsing space
|
||||
.It \e Ta breaking, non-collapsing n-width space
|
||||
.It \e^ Ta zero-width space
|
||||
.It \e% Ta zero-width space
|
||||
.It \e& Ta zero-width space
|
||||
.It \e| Ta zero-width space
|
||||
.It \e0 Ta breaking, non-collapsing digit-width space
|
||||
.It \ec Ta removes any trailing space (if applicable)
|
||||
.El
|
||||
.Pp
|
||||
Lines:
|
||||
.Bl -column "Input" "Rendered" "Description" -offset indent -compact
|
||||
.It Em Input Ta Em Rendered Ta Em Description
|
||||
.It \e(ba Ta \(ba Ta bar
|
||||
.It \e(br Ta \(br Ta box rule
|
||||
.It \e(ul Ta \(ul Ta underscore
|
||||
.It \e(rl Ta \(rl Ta overline
|
||||
.It \e(bb Ta \(bb Ta broken bar
|
||||
.It \e(sl Ta \(sl Ta forward slash
|
||||
.It \e(rs Ta \(rs Ta backward slash
|
||||
.El
|
||||
.Pp
|
||||
Text markers:
|
||||
.Bl -column "Input" "Rendered" "Description" -offset indent -compact
|
||||
.It Em Input Ta Em Rendered Ta Em Description
|
||||
.It \e(ci Ta \(ci Ta circle
|
||||
.It \e(bu Ta \(bu Ta bullet
|
||||
.It \e(dd Ta \(dd Ta double dagger
|
||||
.It \e(dg Ta \(dg Ta dagger
|
||||
.It \e(lz Ta \(lz Ta lozenge
|
||||
.It \e(sq Ta \(sq Ta white square
|
||||
.It \e(ps Ta \(ps Ta paragraph
|
||||
.It \e(sc Ta \(sc Ta section
|
||||
.It \e(lh Ta \(lh Ta left hand
|
||||
.It \e(rh Ta \(rh Ta right hand
|
||||
.It \e(at Ta \(at Ta at
|
||||
.It \e(sh Ta \(sh Ta hash (pound)
|
||||
.It \e(CR Ta \(CR Ta carriage return
|
||||
.It \e(OK Ta \(OK Ta check mark
|
||||
.El
|
||||
.Pp
|
||||
Legal symbols:
|
||||
.Bl -column "Input" "Rendered" "Description" -offset indent -compact
|
||||
.It Em Input Ta Em Rendered Ta Em Description
|
||||
.It \e(co Ta \(co Ta copyright
|
||||
.It \e(rg Ta \(rg Ta registered
|
||||
.It \e(tm Ta \(tm Ta trademarked
|
||||
.El
|
||||
.Pp
|
||||
Punctuation:
|
||||
.Bl -column "Input" "Rendered" "Description" -offset indent -compact
|
||||
.It Em Input Ta Em Rendered Ta Em Description
|
||||
.It \e(em Ta \(em Ta em-dash
|
||||
.It \e(en Ta \(en Ta en-dash
|
||||
.It \e(hy Ta \(hy Ta hyphen
|
||||
.It \ee Ta \e Ta back-slash
|
||||
.It \e. Ta \. Ta period
|
||||
.It \e(r! Ta \(r! Ta upside-down exclamation
|
||||
.It \e(r? Ta \(r? Ta upside-down question
|
||||
.El
|
||||
.Pp
|
||||
Quotes:
|
||||
.Bl -column "Input" "Rendered" "Description" -offset indent -compact
|
||||
.It Em Input Ta Em Rendered Ta Em Description
|
||||
.It \e(Bq Ta \(Bq Ta right low double-quote
|
||||
.It \e(bq Ta \(bq Ta right low single-quote
|
||||
.It \e(lq Ta \(lq Ta left double-quote
|
||||
.It \e(rq Ta \(rq Ta right double-quote
|
||||
.It \e(oq Ta \(oq Ta left single-quote
|
||||
.It \e(cq Ta \(cq Ta right single-quote
|
||||
.It \e(aq Ta \(aq Ta apostrophe quote (text)
|
||||
.It \e(dq Ta \(dq Ta double quote (text)
|
||||
.It \e(Fo Ta \(Fo Ta left guillemet
|
||||
.It \e(Fc Ta \(Fc Ta right guillemet
|
||||
.It \e(fo Ta \(fo Ta left single guillemet
|
||||
.It \e(fc Ta \(fc Ta right single guillemet
|
||||
.El
|
||||
.Pp
|
||||
Brackets:
|
||||
.Bl -column "xxbracketrightbpx" Rendered Description -offset indent -compact
|
||||
.It Em Input Ta Em Rendered Ta Em Description
|
||||
.It \e(lB Ta \(lB Ta left bracket
|
||||
.It \e(rB Ta \(rB Ta right bracket
|
||||
.It \e(lC Ta \(lC Ta left brace
|
||||
.It \e(rC Ta \(rC Ta right brace
|
||||
.It \e(la Ta \(la Ta left angle
|
||||
.It \e(ra Ta \(ra Ta right angle
|
||||
.It \e(bv Ta \(bv Ta brace extension
|
||||
.It \e[braceex] Ta \[braceex] Ta brace extension
|
||||
.It \e[bracketlefttp] Ta \[bracketlefttp] Ta top-left hooked bracket
|
||||
.It \e[bracketleftbp] Ta \[bracketleftbp] Ta bottom-left hooked bracket
|
||||
.It \e[bracketleftex] Ta \[bracketleftex] Ta left hooked bracket extension
|
||||
.It \e[bracketrighttp] Ta \[bracketrighttp] Ta top-right hooked bracket
|
||||
.It \e[bracketrightbp] Ta \[bracketrightbp] Ta bottom-right hooked bracket
|
||||
.It \e[bracketrightex] Ta \[bracketrightex] Ta right hooked bracket extension
|
||||
.It \e(lt Ta \(lt Ta top-left hooked brace
|
||||
.It \e[bracelefttp] Ta \[bracelefttp] Ta top-left hooked brace
|
||||
.It \e(lk Ta \(lk Ta mid-left hooked brace
|
||||
.It \e[braceleftmid] Ta \[braceleftmid] Ta mid-left hooked brace
|
||||
.It \e(lb Ta \(lb Ta bottom-left hooked brace
|
||||
.It \e[braceleftbp] Ta \[braceleftbp] Ta bottom-left hooked brace
|
||||
.It \e[braceleftex] Ta \[braceleftex] Ta left hooked brace extension
|
||||
.It \e(rt Ta \(rt Ta top-left hooked brace
|
||||
.It \e[bracerighttp] Ta \[bracerighttp] Ta top-right hooked brace
|
||||
.It \e(rk Ta \(rk Ta mid-right hooked brace
|
||||
.It \e[bracerightmid] Ta \[bracerightmid] Ta mid-right hooked brace
|
||||
.It \e(rb Ta \(rb Ta bottom-right hooked brace
|
||||
.It \e[bracerightbp] Ta \[bracerightbp] Ta bottom-right hooked brace
|
||||
.It \e[bracerightex] Ta \[bracerightex] Ta right hooked brace extension
|
||||
.It \e[parenlefttp] Ta \[parenlefttp] Ta top-left hooked parenthesis
|
||||
.It \e[parenleftbp] Ta \[parenleftbp] Ta bottom-left hooked parenthesis
|
||||
.It \e[parenleftex] Ta \[parenleftex] Ta left hooked parenthesis extension
|
||||
.It \e[parenrighttp] Ta \[parenrighttp] Ta top-right hooked parenthesis
|
||||
.It \e[parenrightbp] Ta \[parenrightbp] Ta bottom-right hooked parenthesis
|
||||
.It \e[parenrightex] Ta \[parenrightex] Ta right hooked parenthesis extension
|
||||
.El
|
||||
.Pp
|
||||
Arrows:
|
||||
.Bl -column "Input" "Rendered" "Description" -offset indent -compact
|
||||
.It Em Input Ta Em Rendered Ta Em Description
|
||||
.It \e(<- Ta \(<- Ta left arrow
|
||||
.It \e(-> Ta \(-> Ta right arrow
|
||||
.It \e(<> Ta \(<> Ta left-right arrow
|
||||
.It \e(da Ta \(da Ta down arrow
|
||||
.It \e(ua Ta \(ua Ta up arrow
|
||||
.It \e(va Ta \(va Ta up-down arrow
|
||||
.It \e(lA Ta \(lA Ta left double-arrow
|
||||
.It \e(rA Ta \(rA Ta right double-arrow
|
||||
.It \e(hA Ta \(hA Ta left-right double-arrow
|
||||
.It \e(uA Ta \(uA Ta up double-arrow
|
||||
.It \e(dA Ta \(dA Ta down double-arrow
|
||||
.It \e(vA Ta \(vA Ta up-down double-arrow
|
||||
.El
|
||||
.Pp
|
||||
Logical:
|
||||
.Bl -column "Input" "Rendered" "Description" -offset indent -compact
|
||||
.It Em Input Ta Em Rendered Ta Em Description
|
||||
.It \e(AN Ta \(AN Ta logical and
|
||||
.It \e(OR Ta \(OR Ta logical or
|
||||
.It \e(no Ta \(no Ta logical not
|
||||
.It \e[tno] Ta \[tno] Ta logical not (text)
|
||||
.It \e(te Ta \(te Ta existential quantifier
|
||||
.It \e(fa Ta \(fa Ta universal quantifier
|
||||
.It \e(st Ta \(st Ta such that
|
||||
.It \e(tf Ta \(tf Ta therefore
|
||||
.It \e(3d Ta \(3d Ta therefore
|
||||
.It \e(or Ta \(or Ta bitwise or
|
||||
.El
|
||||
.Pp
|
||||
Mathematical:
|
||||
.Bl -column "xxcoproductxx" "Rendered" "Description" -offset indent -compact
|
||||
.It Em Input Ta Em Rendered Ta Em Description
|
||||
.It \e(pl Ta \(pl Ta plus
|
||||
.It \e(mi Ta \(mi Ta minus
|
||||
.It \e- Ta \- Ta minus (text)
|
||||
.It \e(-+ Ta \(-+ Ta minus-plus
|
||||
.It \e(+- Ta \(+- Ta plus-minus
|
||||
.It \e[t+-] Ta \[t+-] Ta plus-minus (text)
|
||||
.It \e(pc Ta \(pc Ta centre-dot
|
||||
.It \e(mu Ta \(mu Ta multiply
|
||||
.It \e[tmu] Ta \[tmu] Ta multiply (text)
|
||||
.It \e(c* Ta \(c* Ta circle-multiply
|
||||
.It \e(c+ Ta \(c+ Ta circle-plus
|
||||
.It \e(di Ta \(di Ta divide
|
||||
.It \e[tdi] Ta \[tdi] Ta divide (text)
|
||||
.It \e(f/ Ta \(f/ Ta fraction
|
||||
.It \e(** Ta \(** Ta asterisk
|
||||
.It \e(<= Ta \(<= Ta less-than-equal
|
||||
.It \e(>= Ta \(>= Ta greater-than-equal
|
||||
.It \e(<< Ta \(<< Ta much less
|
||||
.It \e(>> Ta \(>> Ta much greater
|
||||
.It \e(eq Ta \(eq Ta equal
|
||||
.It \e(!= Ta \(!= Ta not equal
|
||||
.It \e(== Ta \(== Ta equivalent
|
||||
.It \e(ne Ta \(ne Ta not equivalent
|
||||
.It \e(=~ Ta \(=~ Ta congruent
|
||||
.It \e(-~ Ta \(-~ Ta asymptotically congruent
|
||||
.It \e(ap Ta \(ap Ta asymptotically similar
|
||||
.It \e(~~ Ta \(~~ Ta approximately similar
|
||||
.It \e(~= Ta \(~= Ta approximately equal
|
||||
.It \e(pt Ta \(pt Ta proportionate
|
||||
.It \e(es Ta \(es Ta empty set
|
||||
.It \e(mo Ta \(mo Ta element
|
||||
.It \e(nm Ta \(nm Ta not element
|
||||
.It \e(sb Ta \(sb Ta proper subset
|
||||
.It \e(nb Ta \(nb Ta not subset
|
||||
.It \e(sp Ta \(sp Ta proper superset
|
||||
.It \e(nc Ta \(nc Ta not superset
|
||||
.It \e(ib Ta \(ib Ta reflexive subset
|
||||
.It \e(ip Ta \(ip Ta reflexive superset
|
||||
.It \e(ca Ta \(ca Ta intersection
|
||||
.It \e(cu Ta \(cu Ta union
|
||||
.It \e(/_ Ta \(/_ Ta angle
|
||||
.It \e(pp Ta \(pp Ta perpendicular
|
||||
.It \e(is Ta \(is Ta integral
|
||||
.It \e[integral] Ta \[integral] Ta integral
|
||||
.It \e[sum] Ta \[sum] Ta summation
|
||||
.It \e[product] Ta \[product] Ta product
|
||||
.It \e[coproduct] Ta \[coproduct] Ta coproduct
|
||||
.It \e(gr Ta \(gr Ta gradient
|
||||
.It \e(sr Ta \(sr Ta square root
|
||||
.It \e[sqrt] Ta \[sqrt] Ta square root
|
||||
.It \e(lc Ta \(lc Ta left-ceiling
|
||||
.It \e(rc Ta \(rc Ta right-ceiling
|
||||
.It \e(lf Ta \(lf Ta left-floor
|
||||
.It \e(rf Ta \(rf Ta right-floor
|
||||
.It \e(if Ta \(if Ta infinity
|
||||
.It \e(Ah Ta \(Ah Ta aleph
|
||||
.It \e(Im Ta \(Im Ta imaginary
|
||||
.It \e(Re Ta \(Re Ta real
|
||||
.It \e(pd Ta \(pd Ta partial differential
|
||||
.It \e(-h Ta \(-h Ta Planck constant over 2\(*p
|
||||
.It \e[12] Ta \[12] Ta one-half
|
||||
.It \e[14] Ta \[14] Ta one-fourth
|
||||
.It \e[34] Ta \[34] Ta three-fourths
|
||||
.El
|
||||
.Pp
|
||||
Ligatures:
|
||||
.Bl -column "Input" "Rendered" "Description" -offset indent -compact
|
||||
.It Em Input Ta Em Rendered Ta Em Description
|
||||
.It \e(ff Ta \(ff Ta ff ligature
|
||||
.It \e(fi Ta \(fi Ta fi ligature
|
||||
.It \e(fl Ta \(fl Ta fl ligature
|
||||
.It \e(Fi Ta \(Fi Ta ffi ligature
|
||||
.It \e(Fl Ta \(Fl Ta ffl ligature
|
||||
.It \e(AE Ta \(AE Ta AE
|
||||
.It \e(ae Ta \(ae Ta ae
|
||||
.It \e(OE Ta \(OE Ta OE
|
||||
.It \e(oe Ta \(oe Ta oe
|
||||
.It \e(ss Ta \(ss Ta German eszett
|
||||
.It \e(IJ Ta \(IJ Ta IJ ligature
|
||||
.It \e(ij Ta \(ij Ta ij ligature
|
||||
.El
|
||||
.Pp
|
||||
Accents:
|
||||
.Bl -column "Input" "Rendered" "Description" -offset indent -compact
|
||||
.It Em Input Ta Em Rendered Ta Em Description
|
||||
.It \e(a" Ta \(a" Ta Hungarian umlaut
|
||||
.It \e(a- Ta \(a- Ta macron
|
||||
.It \e(a. Ta \(a. Ta dotted
|
||||
.It \e(a^ Ta \(a^ Ta circumflex
|
||||
.It \e(aa Ta \(aa Ta acute
|
||||
.It \e' Ta \' Ta acute
|
||||
.It \e(ga Ta \(ga Ta grave
|
||||
.It \e` Ta \` Ta grave
|
||||
.It \e(ab Ta \(ab Ta breve
|
||||
.It \e(ac Ta \(ac Ta cedilla
|
||||
.It \e(ad Ta \(ad Ta dieresis
|
||||
.It \e(ah Ta \(ah Ta caron
|
||||
.It \e(ao Ta \(ao Ta ring
|
||||
.It \e(a~ Ta \(a~ Ta tilde
|
||||
.It \e(ho Ta \(ho Ta ogonek
|
||||
.It \e(ha Ta \(ha Ta hat (text)
|
||||
.It \e(ti Ta \(ti Ta tilde (text)
|
||||
.El
|
||||
.Pp
|
||||
Accented letters:
|
||||
.Bl -column "Input" "Rendered" "Description" -offset indent -compact
|
||||
.It Em Input Ta Em Rendered Ta Em Description
|
||||
.It \e('A Ta \('A Ta acute A
|
||||
.It \e('E Ta \('E Ta acute E
|
||||
.It \e('I Ta \('I Ta acute I
|
||||
.It \e('O Ta \('O Ta acute O
|
||||
.It \e('U Ta \('U Ta acute U
|
||||
.It \e('a Ta \('a Ta acute a
|
||||
.It \e('e Ta \('e Ta acute e
|
||||
.It \e('i Ta \('i Ta acute i
|
||||
.It \e('o Ta \('o Ta acute o
|
||||
.It \e('u Ta \('u Ta acute u
|
||||
.It \e(`A Ta \(`A Ta grave A
|
||||
.It \e(`E Ta \(`E Ta grave E
|
||||
.It \e(`I Ta \(`I Ta grave I
|
||||
.It \e(`O Ta \(`O Ta grave O
|
||||
.It \e(`U Ta \(`U Ta grave U
|
||||
.It \e(`a Ta \(`a Ta grave a
|
||||
.It \e(`e Ta \(`e Ta grave e
|
||||
.It \e(`i Ta \(`i Ta grave i
|
||||
.It \e(`o Ta \(`i Ta grave o
|
||||
.It \e(`u Ta \(`u Ta grave u
|
||||
.It \e(~A Ta \(~A Ta tilde A
|
||||
.It \e(~N Ta \(~N Ta tilde N
|
||||
.It \e(~O Ta \(~O Ta tilde O
|
||||
.It \e(~a Ta \(~a Ta tilde a
|
||||
.It \e(~n Ta \(~n Ta tilde n
|
||||
.It \e(~o Ta \(~o Ta tilde o
|
||||
.It \e(:A Ta \(:A Ta dieresis A
|
||||
.It \e(:E Ta \(:E Ta dieresis E
|
||||
.It \e(:I Ta \(:I Ta dieresis I
|
||||
.It \e(:O Ta \(:O Ta dieresis O
|
||||
.It \e(:U Ta \(:U Ta dieresis U
|
||||
.It \e(:a Ta \(:a Ta dieresis a
|
||||
.It \e(:e Ta \(:e Ta dieresis e
|
||||
.It \e(:i Ta \(:i Ta dieresis i
|
||||
.It \e(:o Ta \(:o Ta dieresis o
|
||||
.It \e(:u Ta \(:u Ta dieresis u
|
||||
.It \e(:y Ta \(:y Ta dieresis y
|
||||
.It \e(^A Ta \(^A Ta circumflex A
|
||||
.It \e(^E Ta \(^E Ta circumflex E
|
||||
.It \e(^I Ta \(^I Ta circumflex I
|
||||
.It \e(^O Ta \(^O Ta circumflex O
|
||||
.It \e(^U Ta \(^U Ta circumflex U
|
||||
.It \e(^a Ta \(^a Ta circumflex a
|
||||
.It \e(^e Ta \(^e Ta circumflex e
|
||||
.It \e(^i Ta \(^i Ta circumflex i
|
||||
.It \e(^o Ta \(^o Ta circumflex o
|
||||
.It \e(^u Ta \(^u Ta circumflex u
|
||||
.It \e(,C Ta \(,C Ta cedilla C
|
||||
.It \e(,c Ta \(,c Ta cedilla c
|
||||
.It \e(/L Ta \(/L Ta stroke L
|
||||
.It \e(/l Ta \(/l Ta stroke l
|
||||
.It \e(/O Ta \(/O Ta stroke O
|
||||
.It \e(/o Ta \(/o Ta stroke o
|
||||
.It \e(oA Ta \(oA Ta ring A
|
||||
.It \e(oa Ta \(oa Ta ring a
|
||||
.El
|
||||
.Pp
|
||||
Special letters:
|
||||
.Bl -column "Input" "Rendered" "Description" -offset indent -compact
|
||||
.It Em Input Ta Em Rendered Ta Em Description
|
||||
.It \e(-D Ta \(-D Ta Eth
|
||||
.It \e(Sd Ta \(Sd Ta eth
|
||||
.It \e(TP Ta \(TP Ta Thorn
|
||||
.It \e(Tp Ta \(Tp Ta thorn
|
||||
.It \e(.i Ta \(.i Ta dotless i
|
||||
.It \e(.j Ta \(.j Ta dotless j
|
||||
.El
|
||||
.Pp
|
||||
Currency:
|
||||
.Bl -column "Input" "Rendered" "Description" -offset indent -compact
|
||||
.It Em Input Ta Em Rendered Ta Em Description
|
||||
.It \e(Do Ta \(Do Ta dollar
|
||||
.It \e(ct Ta \(ct Ta cent
|
||||
.It \e(Eu Ta \(Eu Ta Euro symbol
|
||||
.It \e(eu Ta \(eu Ta Euro symbol
|
||||
.It \e(Ye Ta \(Ye Ta yen
|
||||
.It \e(Po Ta \(Po Ta pound
|
||||
.It \e(Cs Ta \(Cs Ta Scandinavian
|
||||
.It \e(Fn Ta \(Fn Ta florin
|
||||
.El
|
||||
.Pp
|
||||
Units:
|
||||
.Bl -column "Input" "Rendered" "Description" -offset indent -compact
|
||||
.It Em Input Ta Em Rendered Ta Em Description
|
||||
.It \e(de Ta \(de Ta degree
|
||||
.It \e(%0 Ta \(%0 Ta per-thousand
|
||||
.It \e(fm Ta \(fm Ta minute
|
||||
.It \e(sd Ta \(sd Ta second
|
||||
.It \e(mc Ta \(mc Ta micro
|
||||
.El
|
||||
.Pp
|
||||
Greek letters:
|
||||
.Bl -column "Input" "Rendered" "Description" -offset indent -compact
|
||||
.It Em Input Ta Em Rendered Ta Em Description
|
||||
.It \e(*A Ta \(*A Ta Alpha
|
||||
.It \e(*B Ta \(*B Ta Beta
|
||||
.It \e(*G Ta \(*G Ta Gamma
|
||||
.It \e(*D Ta \(*D Ta Delta
|
||||
.It \e(*E Ta \(*E Ta Epsilon
|
||||
.It \e(*Z Ta \(*Z Ta Zeta
|
||||
.It \e(*Y Ta \(*Y Ta Eta
|
||||
.It \e(*H Ta \(*H Ta Theta
|
||||
.It \e(*I Ta \(*I Ta Iota
|
||||
.It \e(*K Ta \(*K Ta Kappa
|
||||
.It \e(*L Ta \(*L Ta Lambda
|
||||
.It \e(*M Ta \(*M Ta Mu
|
||||
.It \e(*N Ta \(*N Ta Nu
|
||||
.It \e(*C Ta \(*C Ta Xi
|
||||
.It \e(*O Ta \(*O Ta Omicron
|
||||
.It \e(*P Ta \(*P Ta Pi
|
||||
.It \e(*R Ta \(*R Ta Rho
|
||||
.It \e(*S Ta \(*S Ta Sigma
|
||||
.It \e(*T Ta \(*T Ta Tau
|
||||
.It \e(*U Ta \(*U Ta Upsilon
|
||||
.It \e(*F Ta \(*F Ta Phi
|
||||
.It \e(*X Ta \(*X Ta Chi
|
||||
.It \e(*Q Ta \(*Q Ta Psi
|
||||
.It \e(*W Ta \(*W Ta Omega
|
||||
.It \e(*a Ta \(*a Ta alpha
|
||||
.It \e(*b Ta \(*b Ta beta
|
||||
.It \e(*g Ta \(*g Ta gamma
|
||||
.It \e(*d Ta \(*d Ta delta
|
||||
.It \e(*e Ta \(*e Ta epsilon
|
||||
.It \e(*z Ta \(*z Ta zeta
|
||||
.It \e(*y Ta \(*y Ta eta
|
||||
.It \e(*h Ta \(*h Ta theta
|
||||
.It \e(*i Ta \(*i Ta iota
|
||||
.It \e(*k Ta \(*k Ta kappa
|
||||
.It \e(*l Ta \(*l Ta lambda
|
||||
.It \e(*m Ta \(*m Ta mu
|
||||
.It \e(*n Ta \(*n Ta nu
|
||||
.It \e(*c Ta \(*c Ta xi
|
||||
.It \e(*o Ta \(*o Ta omicron
|
||||
.It \e(*p Ta \(*p Ta pi
|
||||
.It \e(*r Ta \(*r Ta rho
|
||||
.It \e(*s Ta \(*s Ta sigma
|
||||
.It \e(*t Ta \(*t Ta tau
|
||||
.It \e(*u Ta \(*u Ta upsilon
|
||||
.It \e(*f Ta \(*f Ta phi
|
||||
.It \e(*x Ta \(*x Ta chi
|
||||
.It \e(*q Ta \(*q Ta psi
|
||||
.It \e(*w Ta \(*w Ta omega
|
||||
.It \e(+h Ta \(+h Ta theta variant
|
||||
.It \e(+f Ta \(+f Ta phi variant
|
||||
.It \e(+p Ta \(+p Ta pi variant
|
||||
.It \e(+e Ta \(+e Ta epsilon variant
|
||||
.It \e(ts Ta \(ts Ta sigma terminal
|
||||
.El
|
||||
.Sh PREDEFINED STRINGS
|
||||
Predefined strings are inherited from the macro packages of historical
|
||||
troff implementations.
|
||||
They are
|
||||
.Em not recommended
|
||||
for use, as they differ across implementations.
|
||||
Manuals using these predefined strings are almost certainly not
|
||||
portable.
|
||||
.Pp
|
||||
Their syntax is similar to special characters, using
|
||||
.Sq \e*X
|
||||
.Pq for a one-character escape ,
|
||||
.Sq \e*(XX
|
||||
.Pq two-character ,
|
||||
and
|
||||
.Sq \e*[N]
|
||||
.Pq N-character .
|
||||
For details, see the
|
||||
.Em Predefined Strings
|
||||
subsection of the
|
||||
.Xr roff 7
|
||||
manual.
|
||||
.Bl -column "Input" "Rendered" "Description" -offset indent
|
||||
.It Em Input Ta Em Rendered Ta Em Description
|
||||
.It \e*(Ba Ta \*(Ba Ta vertical bar
|
||||
.It \e*(Ne Ta \*(Ne Ta not equal
|
||||
.It \e*(Ge Ta \*(Ge Ta greater-than-equal
|
||||
.It \e*(Le Ta \*(Le Ta less-than-equal
|
||||
.It \e*(Gt Ta \*(Gt Ta greater-than
|
||||
.It \e*(Lt Ta \*(Lt Ta less-than
|
||||
.It \e*(Pm Ta \*(Pm Ta plus-minus
|
||||
.It \e*(If Ta \*(If Ta infinity
|
||||
.It \e*(Pi Ta \*(Pi Ta pi
|
||||
.It \e*(Na Ta \*(Na Ta NaN
|
||||
.It \e*(Am Ta \*(Am Ta ampersand
|
||||
.It \e*R Ta \*R Ta restricted mark
|
||||
.It \e*(Tm Ta \*(Tm Ta trade mark
|
||||
.It \e*q Ta \*q Ta double-quote
|
||||
.It \e*(Rq Ta \*(Rq Ta right-double-quote
|
||||
.It \e*(Lq Ta \*(Lq Ta left-double-quote
|
||||
.It \e*(lp Ta \*(lp Ta right-parenthesis
|
||||
.It \e*(rp Ta \*(rp Ta left-parenthesis
|
||||
.It \e*(lq Ta \*(lq Ta left double-quote
|
||||
.It \e*(rq Ta \*(rq Ta right double-quote
|
||||
.It \e*(ua Ta \*(ua Ta up arrow
|
||||
.It \e*(va Ta \*(va Ta up-down arrow
|
||||
.It \e*(<= Ta \*(<= Ta less-than-equal
|
||||
.It \e*(>= Ta \*(>= Ta greater-than-equal
|
||||
.It \e*(aa Ta \*(aa Ta acute
|
||||
.It \e*(ga Ta \*(ga Ta grave
|
||||
.It \e*(Px Ta \*(Px Ta POSIX standard name
|
||||
.It \e*(Ai Ta \*(Ai Ta ANSI standard name
|
||||
.El
|
||||
.Sh UNICODE CHARACTERS
|
||||
The escape sequence
|
||||
.Pp
|
||||
.Dl \e[uXXXX]
|
||||
.Pp
|
||||
is interpreted as a Unicode codepoint.
|
||||
The codepoint must be in the range above U+0080 and less than U+10FFFF.
|
||||
For compatibility, points must be zero-padded to four characters; if
|
||||
greater than four characters, no zero padding is allowed.
|
||||
Unicode surrogates are not allowed.
|
||||
.\" .Pp
|
||||
.\" Unicode glyphs attenuate to the
|
||||
.\" .Sq \&?
|
||||
.\" character if invalid or not rendered by current output media.
|
||||
.Sh NUMBERED CHARACTERS
|
||||
For backward compatibility with existing manuals,
|
||||
.Xr mandoc 1
|
||||
also supports the
|
||||
.Pp
|
||||
.Dl \eN\(aq Ns Ar number Ns \(aq
|
||||
.Pp
|
||||
escape sequence, inserting the character
|
||||
.Ar number
|
||||
from the current character set into the output.
|
||||
Of course, this is inherently non-portable and is already marked
|
||||
as deprecated in the Heirloom roff manual.
|
||||
For example, do not use \eN'34', use \e(dq, or even the plain
|
||||
.Sq \(dq
|
||||
character where possible.
|
||||
.Sh COMPATIBILITY
|
||||
This section documents compatibility between mandoc and other other
|
||||
troff implementations, at this time limited to GNU troff
|
||||
.Pq Qq groff .
|
||||
.Pp
|
||||
.Bl -dash -compact
|
||||
.It
|
||||
The \eN\(aq\(aq escape sequence is limited to printable characters; in
|
||||
groff, it accepts arbitrary character numbers.
|
||||
.It
|
||||
In
|
||||
.Fl T Ns Cm ascii ,
|
||||
the
|
||||
\e(ss, \e(nm, \e(nb, \e(nc, \e(ib, \e(ip, \e(pp, \e[sum], \e[product],
|
||||
\e[coproduct], \e(gr, \e(\-h, and \e(a. special characters render
|
||||
differently between mandoc and groff.
|
||||
.It
|
||||
In
|
||||
.Fl T Ns Cm html
|
||||
and
|
||||
.Fl T Ns Cm xhtml ,
|
||||
the \e(~=, \e(nb, and \e(nc special characters render differently
|
||||
between mandoc and groff.
|
||||
.It
|
||||
The
|
||||
.Fl T Ns Cm ps
|
||||
and
|
||||
.Fl T Ns Cm pdf
|
||||
modes format like
|
||||
.Fl T Ns Cm ascii
|
||||
instead of rendering glyphs as in groff.
|
||||
.It
|
||||
The \e[radicalex], \e[sqrtex], and \e(ru special characters have been omitted
|
||||
from mandoc either because they are poorly documented or they have no
|
||||
known representation.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr mandoc 1 ,
|
||||
.Xr man 7 ,
|
||||
.Xr mdoc 7 ,
|
||||
.Xr roff 7
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Nm
|
||||
manual page was written by
|
||||
.An Kristaps Dzonsons ,
|
||||
.Mt kristaps@bsd.lv .
|
||||
.Sh CAVEATS
|
||||
The
|
||||
.Sq \e*(Ba
|
||||
escape mimics the behaviour of the
|
||||
.Sq \&|
|
||||
character in
|
||||
.Xr mdoc 7 ;
|
||||
thus, if you wish to render a vertical bar with no side effects, use
|
||||
the
|
||||
.Sq \e(ba
|
||||
escape.
|
3172
contrib/mdocml/mdoc.7
Normal file
3172
contrib/mdocml/mdoc.7
Normal file
File diff suppressed because it is too large
Load Diff
987
contrib/mdocml/mdoc.c
Normal file
987
contrib/mdocml/mdoc.c
Normal file
@ -0,0 +1,987 @@
|
||||
/* $Id: mdoc.c,v 1.196 2011/09/30 00:13:28 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 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
|
||||
* 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "mdoc.h"
|
||||
#include "mandoc.h"
|
||||
#include "libmdoc.h"
|
||||
#include "libmandoc.h"
|
||||
|
||||
const char *const __mdoc_macronames[MDOC_MAX] = {
|
||||
"Ap", "Dd", "Dt", "Os",
|
||||
"Sh", "Ss", "Pp", "D1",
|
||||
"Dl", "Bd", "Ed", "Bl",
|
||||
"El", "It", "Ad", "An",
|
||||
"Ar", "Cd", "Cm", "Dv",
|
||||
"Er", "Ev", "Ex", "Fa",
|
||||
"Fd", "Fl", "Fn", "Ft",
|
||||
"Ic", "In", "Li", "Nd",
|
||||
"Nm", "Op", "Ot", "Pa",
|
||||
"Rv", "St", "Va", "Vt",
|
||||
/* LINTED */
|
||||
"Xr", "%A", "%B", "%D",
|
||||
/* LINTED */
|
||||
"%I", "%J", "%N", "%O",
|
||||
/* LINTED */
|
||||
"%P", "%R", "%T", "%V",
|
||||
"Ac", "Ao", "Aq", "At",
|
||||
"Bc", "Bf", "Bo", "Bq",
|
||||
"Bsx", "Bx", "Db", "Dc",
|
||||
"Do", "Dq", "Ec", "Ef",
|
||||
"Em", "Eo", "Fx", "Ms",
|
||||
"No", "Ns", "Nx", "Ox",
|
||||
"Pc", "Pf", "Po", "Pq",
|
||||
"Qc", "Ql", "Qo", "Qq",
|
||||
"Re", "Rs", "Sc", "So",
|
||||
"Sq", "Sm", "Sx", "Sy",
|
||||
"Tn", "Ux", "Xc", "Xo",
|
||||
"Fo", "Fc", "Oo", "Oc",
|
||||
"Bk", "Ek", "Bt", "Hf",
|
||||
"Fr", "Ud", "Lb", "Lp",
|
||||
"Lk", "Mt", "Brq", "Bro",
|
||||
/* LINTED */
|
||||
"Brc", "%C", "Es", "En",
|
||||
/* LINTED */
|
||||
"Dx", "%Q", "br", "sp",
|
||||
/* LINTED */
|
||||
"%U", "Ta"
|
||||
};
|
||||
|
||||
const char *const __mdoc_argnames[MDOC_ARG_MAX] = {
|
||||
"split", "nosplit", "ragged",
|
||||
"unfilled", "literal", "file",
|
||||
"offset", "bullet", "dash",
|
||||
"hyphen", "item", "enum",
|
||||
"tag", "diag", "hang",
|
||||
"ohang", "inset", "column",
|
||||
"width", "compact", "std",
|
||||
"filled", "words", "emphasis",
|
||||
"symbolic", "nested", "centered"
|
||||
};
|
||||
|
||||
const char * const *mdoc_macronames = __mdoc_macronames;
|
||||
const char * const *mdoc_argnames = __mdoc_argnames;
|
||||
|
||||
static void mdoc_node_free(struct mdoc_node *);
|
||||
static void mdoc_node_unlink(struct mdoc *,
|
||||
struct mdoc_node *);
|
||||
static void mdoc_free1(struct mdoc *);
|
||||
static void mdoc_alloc1(struct mdoc *);
|
||||
static struct mdoc_node *node_alloc(struct mdoc *, int, int,
|
||||
enum mdoct, enum mdoc_type);
|
||||
static int node_append(struct mdoc *,
|
||||
struct mdoc_node *);
|
||||
#if 0
|
||||
static int mdoc_preptext(struct mdoc *, int, char *, int);
|
||||
#endif
|
||||
static int mdoc_ptext(struct mdoc *, int, char *, int);
|
||||
static int mdoc_pmacro(struct mdoc *, int, char *, int);
|
||||
|
||||
const struct mdoc_node *
|
||||
mdoc_node(const struct mdoc *m)
|
||||
{
|
||||
|
||||
assert( ! (MDOC_HALT & m->flags));
|
||||
return(m->first);
|
||||
}
|
||||
|
||||
|
||||
const struct mdoc_meta *
|
||||
mdoc_meta(const struct mdoc *m)
|
||||
{
|
||||
|
||||
assert( ! (MDOC_HALT & m->flags));
|
||||
return(&m->meta);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Frees volatile resources (parse tree, meta-data, fields).
|
||||
*/
|
||||
static void
|
||||
mdoc_free1(struct mdoc *mdoc)
|
||||
{
|
||||
|
||||
if (mdoc->first)
|
||||
mdoc_node_delete(mdoc, mdoc->first);
|
||||
if (mdoc->meta.title)
|
||||
free(mdoc->meta.title);
|
||||
if (mdoc->meta.os)
|
||||
free(mdoc->meta.os);
|
||||
if (mdoc->meta.name)
|
||||
free(mdoc->meta.name);
|
||||
if (mdoc->meta.arch)
|
||||
free(mdoc->meta.arch);
|
||||
if (mdoc->meta.vol)
|
||||
free(mdoc->meta.vol);
|
||||
if (mdoc->meta.msec)
|
||||
free(mdoc->meta.msec);
|
||||
if (mdoc->meta.date)
|
||||
free(mdoc->meta.date);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Allocate all volatile resources (parse tree, meta-data, fields).
|
||||
*/
|
||||
static void
|
||||
mdoc_alloc1(struct mdoc *mdoc)
|
||||
{
|
||||
|
||||
memset(&mdoc->meta, 0, sizeof(struct mdoc_meta));
|
||||
mdoc->flags = 0;
|
||||
mdoc->lastnamed = mdoc->lastsec = SEC_NONE;
|
||||
mdoc->last = mandoc_calloc(1, sizeof(struct mdoc_node));
|
||||
mdoc->first = mdoc->last;
|
||||
mdoc->last->type = MDOC_ROOT;
|
||||
mdoc->last->tok = MDOC_MAX;
|
||||
mdoc->next = MDOC_NEXT_CHILD;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Free up volatile resources (see mdoc_free1()) then re-initialises the
|
||||
* data with mdoc_alloc1(). After invocation, parse data has been reset
|
||||
* and the parser is ready for re-invocation on a new tree; however,
|
||||
* cross-parse non-volatile data is kept intact.
|
||||
*/
|
||||
void
|
||||
mdoc_reset(struct mdoc *mdoc)
|
||||
{
|
||||
|
||||
mdoc_free1(mdoc);
|
||||
mdoc_alloc1(mdoc);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Completely free up all volatile and non-volatile parse resources.
|
||||
* After invocation, the pointer is no longer usable.
|
||||
*/
|
||||
void
|
||||
mdoc_free(struct mdoc *mdoc)
|
||||
{
|
||||
|
||||
mdoc_free1(mdoc);
|
||||
free(mdoc);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Allocate volatile and non-volatile parse resources.
|
||||
*/
|
||||
struct mdoc *
|
||||
mdoc_alloc(struct roff *roff, struct mparse *parse)
|
||||
{
|
||||
struct mdoc *p;
|
||||
|
||||
p = mandoc_calloc(1, sizeof(struct mdoc));
|
||||
|
||||
p->parse = parse;
|
||||
p->roff = roff;
|
||||
|
||||
mdoc_hash_init();
|
||||
mdoc_alloc1(p);
|
||||
return(p);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Climb back up the parse tree, validating open scopes. Mostly calls
|
||||
* through to macro_end() in macro.c.
|
||||
*/
|
||||
int
|
||||
mdoc_endparse(struct mdoc *m)
|
||||
{
|
||||
|
||||
assert( ! (MDOC_HALT & m->flags));
|
||||
if (mdoc_macroend(m))
|
||||
return(1);
|
||||
m->flags |= MDOC_HALT;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
mdoc_addeqn(struct mdoc *m, const struct eqn *ep)
|
||||
{
|
||||
struct mdoc_node *n;
|
||||
|
||||
assert( ! (MDOC_HALT & m->flags));
|
||||
|
||||
/* No text before an initial macro. */
|
||||
|
||||
if (SEC_NONE == m->lastnamed) {
|
||||
mdoc_pmsg(m, ep->ln, ep->pos, MANDOCERR_NOTEXT);
|
||||
return(1);
|
||||
}
|
||||
|
||||
n = node_alloc(m, ep->ln, ep->pos, MDOC_MAX, MDOC_EQN);
|
||||
n->eqn = ep;
|
||||
|
||||
if ( ! node_append(m, n))
|
||||
return(0);
|
||||
|
||||
m->next = MDOC_NEXT_SIBLING;
|
||||
return(1);
|
||||
}
|
||||
|
||||
int
|
||||
mdoc_addspan(struct mdoc *m, const struct tbl_span *sp)
|
||||
{
|
||||
struct mdoc_node *n;
|
||||
|
||||
assert( ! (MDOC_HALT & m->flags));
|
||||
|
||||
/* No text before an initial macro. */
|
||||
|
||||
if (SEC_NONE == m->lastnamed) {
|
||||
mdoc_pmsg(m, sp->line, 0, MANDOCERR_NOTEXT);
|
||||
return(1);
|
||||
}
|
||||
|
||||
n = node_alloc(m, sp->line, 0, MDOC_MAX, MDOC_TBL);
|
||||
n->span = sp;
|
||||
|
||||
if ( ! node_append(m, n))
|
||||
return(0);
|
||||
|
||||
m->next = MDOC_NEXT_SIBLING;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Main parse routine. Parses a single line -- really just hands off to
|
||||
* the macro (mdoc_pmacro()) or text parser (mdoc_ptext()).
|
||||
*/
|
||||
int
|
||||
mdoc_parseln(struct mdoc *m, int ln, char *buf, int offs)
|
||||
{
|
||||
|
||||
assert( ! (MDOC_HALT & m->flags));
|
||||
|
||||
m->flags |= MDOC_NEWLINE;
|
||||
|
||||
/*
|
||||
* Let the roff nS register switch SYNOPSIS mode early,
|
||||
* such that the parser knows at all times
|
||||
* whether this mode is on or off.
|
||||
* Note that this mode is also switched by the Sh macro.
|
||||
*/
|
||||
if (roff_regisset(m->roff, REG_nS)) {
|
||||
if (roff_regget(m->roff, REG_nS))
|
||||
m->flags |= MDOC_SYNOPSIS;
|
||||
else
|
||||
m->flags &= ~MDOC_SYNOPSIS;
|
||||
}
|
||||
|
||||
return(mandoc_getcontrol(buf, &offs) ?
|
||||
mdoc_pmacro(m, ln, buf, offs) :
|
||||
mdoc_ptext(m, ln, buf, offs));
|
||||
}
|
||||
|
||||
int
|
||||
mdoc_macro(MACRO_PROT_ARGS)
|
||||
{
|
||||
assert(tok < MDOC_MAX);
|
||||
|
||||
/* If we're in the body, deny prologue calls. */
|
||||
|
||||
if (MDOC_PROLOGUE & mdoc_macros[tok].flags &&
|
||||
MDOC_PBODY & m->flags) {
|
||||
mdoc_pmsg(m, line, ppos, MANDOCERR_BADBODY);
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* If we're in the prologue, deny "body" macros. */
|
||||
|
||||
if ( ! (MDOC_PROLOGUE & mdoc_macros[tok].flags) &&
|
||||
! (MDOC_PBODY & m->flags)) {
|
||||
mdoc_pmsg(m, line, ppos, MANDOCERR_BADPROLOG);
|
||||
if (NULL == m->meta.msec)
|
||||
m->meta.msec = mandoc_strdup("1");
|
||||
if (NULL == m->meta.title)
|
||||
m->meta.title = mandoc_strdup("UNKNOWN");
|
||||
if (NULL == m->meta.vol)
|
||||
m->meta.vol = mandoc_strdup("LOCAL");
|
||||
if (NULL == m->meta.os)
|
||||
m->meta.os = mandoc_strdup("LOCAL");
|
||||
if (NULL == m->meta.date)
|
||||
m->meta.date = mandoc_normdate
|
||||
(m->parse, NULL, line, ppos);
|
||||
m->flags |= MDOC_PBODY;
|
||||
}
|
||||
|
||||
return((*mdoc_macros[tok].fp)(m, tok, line, ppos, pos, buf));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
node_append(struct mdoc *mdoc, struct mdoc_node *p)
|
||||
{
|
||||
|
||||
assert(mdoc->last);
|
||||
assert(mdoc->first);
|
||||
assert(MDOC_ROOT != p->type);
|
||||
|
||||
switch (mdoc->next) {
|
||||
case (MDOC_NEXT_SIBLING):
|
||||
mdoc->last->next = p;
|
||||
p->prev = mdoc->last;
|
||||
p->parent = mdoc->last->parent;
|
||||
break;
|
||||
case (MDOC_NEXT_CHILD):
|
||||
mdoc->last->child = p;
|
||||
p->parent = mdoc->last;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
p->parent->nchild++;
|
||||
|
||||
/*
|
||||
* Copy over the normalised-data pointer of our parent. Not
|
||||
* everybody has one, but copying a null pointer is fine.
|
||||
*/
|
||||
|
||||
switch (p->type) {
|
||||
case (MDOC_BODY):
|
||||
/* FALLTHROUGH */
|
||||
case (MDOC_TAIL):
|
||||
/* FALLTHROUGH */
|
||||
case (MDOC_HEAD):
|
||||
p->norm = p->parent->norm;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ( ! mdoc_valid_pre(mdoc, p))
|
||||
return(0);
|
||||
|
||||
switch (p->type) {
|
||||
case (MDOC_HEAD):
|
||||
assert(MDOC_BLOCK == p->parent->type);
|
||||
p->parent->head = p;
|
||||
break;
|
||||
case (MDOC_TAIL):
|
||||
assert(MDOC_BLOCK == p->parent->type);
|
||||
p->parent->tail = p;
|
||||
break;
|
||||
case (MDOC_BODY):
|
||||
if (p->end)
|
||||
break;
|
||||
assert(MDOC_BLOCK == p->parent->type);
|
||||
p->parent->body = p;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
mdoc->last = p;
|
||||
|
||||
switch (p->type) {
|
||||
case (MDOC_TBL):
|
||||
/* FALLTHROUGH */
|
||||
case (MDOC_TEXT):
|
||||
if ( ! mdoc_valid_post(mdoc))
|
||||
return(0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
static struct mdoc_node *
|
||||
node_alloc(struct mdoc *m, int line, int pos,
|
||||
enum mdoct tok, enum mdoc_type type)
|
||||
{
|
||||
struct mdoc_node *p;
|
||||
|
||||
p = mandoc_calloc(1, sizeof(struct mdoc_node));
|
||||
p->sec = m->lastsec;
|
||||
p->line = line;
|
||||
p->pos = pos;
|
||||
p->tok = tok;
|
||||
p->type = type;
|
||||
|
||||
/* Flag analysis. */
|
||||
|
||||
if (MDOC_SYNOPSIS & m->flags)
|
||||
p->flags |= MDOC_SYNPRETTY;
|
||||
else
|
||||
p->flags &= ~MDOC_SYNPRETTY;
|
||||
if (MDOC_NEWLINE & m->flags)
|
||||
p->flags |= MDOC_LINE;
|
||||
m->flags &= ~MDOC_NEWLINE;
|
||||
|
||||
return(p);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
mdoc_tail_alloc(struct mdoc *m, int line, int pos, enum mdoct tok)
|
||||
{
|
||||
struct mdoc_node *p;
|
||||
|
||||
p = node_alloc(m, line, pos, tok, MDOC_TAIL);
|
||||
if ( ! node_append(m, p))
|
||||
return(0);
|
||||
m->next = MDOC_NEXT_CHILD;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
mdoc_head_alloc(struct mdoc *m, int line, int pos, enum mdoct tok)
|
||||
{
|
||||
struct mdoc_node *p;
|
||||
|
||||
assert(m->first);
|
||||
assert(m->last);
|
||||
|
||||
p = node_alloc(m, line, pos, tok, MDOC_HEAD);
|
||||
if ( ! node_append(m, p))
|
||||
return(0);
|
||||
m->next = MDOC_NEXT_CHILD;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
mdoc_body_alloc(struct mdoc *m, int line, int pos, enum mdoct tok)
|
||||
{
|
||||
struct mdoc_node *p;
|
||||
|
||||
p = node_alloc(m, line, pos, tok, MDOC_BODY);
|
||||
if ( ! node_append(m, p))
|
||||
return(0);
|
||||
m->next = MDOC_NEXT_CHILD;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
mdoc_endbody_alloc(struct mdoc *m, int line, int pos, enum mdoct tok,
|
||||
struct mdoc_node *body, enum mdoc_endbody end)
|
||||
{
|
||||
struct mdoc_node *p;
|
||||
|
||||
p = node_alloc(m, line, pos, tok, MDOC_BODY);
|
||||
p->pending = body;
|
||||
p->end = end;
|
||||
if ( ! node_append(m, p))
|
||||
return(0);
|
||||
m->next = MDOC_NEXT_SIBLING;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
mdoc_block_alloc(struct mdoc *m, int line, int pos,
|
||||
enum mdoct tok, struct mdoc_arg *args)
|
||||
{
|
||||
struct mdoc_node *p;
|
||||
|
||||
p = node_alloc(m, line, pos, tok, MDOC_BLOCK);
|
||||
p->args = args;
|
||||
if (p->args)
|
||||
(args->refcnt)++;
|
||||
|
||||
switch (tok) {
|
||||
case (MDOC_Bd):
|
||||
/* FALLTHROUGH */
|
||||
case (MDOC_Bf):
|
||||
/* FALLTHROUGH */
|
||||
case (MDOC_Bl):
|
||||
/* FALLTHROUGH */
|
||||
case (MDOC_Rs):
|
||||
p->norm = mandoc_calloc(1, sizeof(union mdoc_data));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ( ! node_append(m, p))
|
||||
return(0);
|
||||
m->next = MDOC_NEXT_CHILD;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
mdoc_elem_alloc(struct mdoc *m, int line, int pos,
|
||||
enum mdoct tok, struct mdoc_arg *args)
|
||||
{
|
||||
struct mdoc_node *p;
|
||||
|
||||
p = node_alloc(m, line, pos, tok, MDOC_ELEM);
|
||||
p->args = args;
|
||||
if (p->args)
|
||||
(args->refcnt)++;
|
||||
|
||||
switch (tok) {
|
||||
case (MDOC_An):
|
||||
p->norm = mandoc_calloc(1, sizeof(union mdoc_data));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ( ! node_append(m, p))
|
||||
return(0);
|
||||
m->next = MDOC_NEXT_CHILD;
|
||||
return(1);
|
||||
}
|
||||
|
||||
int
|
||||
mdoc_word_alloc(struct mdoc *m, int line, int pos, const char *p)
|
||||
{
|
||||
struct mdoc_node *n;
|
||||
|
||||
n = node_alloc(m, line, pos, MDOC_MAX, MDOC_TEXT);
|
||||
n->string = roff_strdup(m->roff, p);
|
||||
|
||||
if ( ! node_append(m, n))
|
||||
return(0);
|
||||
|
||||
m->next = MDOC_NEXT_SIBLING;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
mdoc_node_free(struct mdoc_node *p)
|
||||
{
|
||||
|
||||
if (MDOC_BLOCK == p->type || MDOC_ELEM == p->type)
|
||||
free(p->norm);
|
||||
if (p->string)
|
||||
free(p->string);
|
||||
if (p->args)
|
||||
mdoc_argv_free(p->args);
|
||||
free(p);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
mdoc_node_unlink(struct mdoc *m, struct mdoc_node *n)
|
||||
{
|
||||
|
||||
/* Adjust siblings. */
|
||||
|
||||
if (n->prev)
|
||||
n->prev->next = n->next;
|
||||
if (n->next)
|
||||
n->next->prev = n->prev;
|
||||
|
||||
/* Adjust parent. */
|
||||
|
||||
if (n->parent) {
|
||||
n->parent->nchild--;
|
||||
if (n->parent->child == n)
|
||||
n->parent->child = n->prev ? n->prev : n->next;
|
||||
if (n->parent->last == n)
|
||||
n->parent->last = n->prev ? n->prev : NULL;
|
||||
}
|
||||
|
||||
/* Adjust parse point, if applicable. */
|
||||
|
||||
if (m && m->last == n) {
|
||||
if (n->prev) {
|
||||
m->last = n->prev;
|
||||
m->next = MDOC_NEXT_SIBLING;
|
||||
} else {
|
||||
m->last = n->parent;
|
||||
m->next = MDOC_NEXT_CHILD;
|
||||
}
|
||||
}
|
||||
|
||||
if (m && m->first == n)
|
||||
m->first = NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
mdoc_node_delete(struct mdoc *m, struct mdoc_node *p)
|
||||
{
|
||||
|
||||
while (p->child) {
|
||||
assert(p->nchild);
|
||||
mdoc_node_delete(m, p->child);
|
||||
}
|
||||
assert(0 == p->nchild);
|
||||
|
||||
mdoc_node_unlink(m, p);
|
||||
mdoc_node_free(p);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Pre-treat a text line.
|
||||
* Text lines can consist of equations, which must be handled apart from
|
||||
* the regular text.
|
||||
* Thus, use this function to step through a line checking if it has any
|
||||
* equations embedded in it.
|
||||
* This must handle multiple equations AND equations that do not end at
|
||||
* the end-of-line, i.e., will re-enter in the next roff parse.
|
||||
*/
|
||||
static int
|
||||
mdoc_preptext(struct mdoc *m, int line, char *buf, int offs)
|
||||
{
|
||||
char *start, *end;
|
||||
char delim;
|
||||
|
||||
while ('\0' != buf[offs]) {
|
||||
/* Mark starting position if eqn is set. */
|
||||
start = NULL;
|
||||
if ('\0' != (delim = roff_eqndelim(m->roff)))
|
||||
if (NULL != (start = strchr(buf + offs, delim)))
|
||||
*start++ = '\0';
|
||||
|
||||
/* Parse text as normal. */
|
||||
if ( ! mdoc_ptext(m, line, buf, offs))
|
||||
return(0);
|
||||
|
||||
/* Continue only if an equation exists. */
|
||||
if (NULL == start)
|
||||
break;
|
||||
|
||||
/* Read past the end of the equation. */
|
||||
offs += start - (buf + offs);
|
||||
assert(start == &buf[offs]);
|
||||
if (NULL != (end = strchr(buf + offs, delim))) {
|
||||
*end++ = '\0';
|
||||
while (' ' == *end)
|
||||
end++;
|
||||
}
|
||||
|
||||
/* Parse the equation itself. */
|
||||
roff_openeqn(m->roff, NULL, line, offs, buf);
|
||||
|
||||
/* Process a finished equation? */
|
||||
if (roff_closeeqn(m->roff))
|
||||
if ( ! mdoc_addeqn(m, roff_eqn(m->roff)))
|
||||
return(0);
|
||||
offs += (end - (buf + offs));
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Parse free-form text, that is, a line that does not begin with the
|
||||
* control character.
|
||||
*/
|
||||
static int
|
||||
mdoc_ptext(struct mdoc *m, int line, char *buf, int offs)
|
||||
{
|
||||
char *c, *ws, *end;
|
||||
struct mdoc_node *n;
|
||||
|
||||
/* No text before an initial macro. */
|
||||
|
||||
if (SEC_NONE == m->lastnamed) {
|
||||
mdoc_pmsg(m, line, offs, MANDOCERR_NOTEXT);
|
||||
return(1);
|
||||
}
|
||||
|
||||
assert(m->last);
|
||||
n = m->last;
|
||||
|
||||
/*
|
||||
* Divert directly to list processing if we're encountering a
|
||||
* columnar MDOC_BLOCK with or without a prior MDOC_BLOCK entry
|
||||
* (a MDOC_BODY means it's already open, in which case we should
|
||||
* process within its context in the normal way).
|
||||
*/
|
||||
|
||||
if (MDOC_Bl == n->tok && MDOC_BODY == n->type &&
|
||||
LIST_column == n->norm->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->norm->Bl.type) {
|
||||
/* `Bl' has block-level `It' children. */
|
||||
m->flags |= MDOC_FREECOL;
|
||||
return(mdoc_macro(m, MDOC_It, line, offs, &offs, buf));
|
||||
}
|
||||
|
||||
/*
|
||||
* Search for the beginning of unescaped trailing whitespace (ws)
|
||||
* and for the first character not to be output (end).
|
||||
*/
|
||||
|
||||
/* FIXME: replace with strcspn(). */
|
||||
ws = NULL;
|
||||
for (c = end = buf + offs; *c; c++) {
|
||||
switch (*c) {
|
||||
case ' ':
|
||||
if (NULL == ws)
|
||||
ws = c;
|
||||
continue;
|
||||
case '\t':
|
||||
/*
|
||||
* Always warn about trailing tabs,
|
||||
* even outside literal context,
|
||||
* where they should be put on the next line.
|
||||
*/
|
||||
if (NULL == ws)
|
||||
ws = c;
|
||||
/*
|
||||
* Strip trailing tabs in literal context only;
|
||||
* outside, they affect the next line.
|
||||
*/
|
||||
if (MDOC_LITERAL & m->flags)
|
||||
continue;
|
||||
break;
|
||||
case '\\':
|
||||
/* Skip the escaped character, too, if any. */
|
||||
if (c[1])
|
||||
c++;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
ws = NULL;
|
||||
break;
|
||||
}
|
||||
end = c + 1;
|
||||
}
|
||||
*end = '\0';
|
||||
|
||||
if (ws)
|
||||
mdoc_pmsg(m, line, (int)(ws-buf), MANDOCERR_EOLNSPACE);
|
||||
|
||||
if ('\0' == buf[offs] && ! (MDOC_LITERAL & m->flags)) {
|
||||
mdoc_pmsg(m, line, (int)(c-buf), MANDOCERR_NOBLANKLN);
|
||||
|
||||
/*
|
||||
* Insert a `sp' in the case of a blank line. Technically,
|
||||
* blank lines aren't allowed, but enough manuals assume this
|
||||
* behaviour that we want to work around it.
|
||||
*/
|
||||
if ( ! mdoc_elem_alloc(m, line, offs, MDOC_sp, NULL))
|
||||
return(0);
|
||||
|
||||
m->next = MDOC_NEXT_SIBLING;
|
||||
return(1);
|
||||
}
|
||||
|
||||
if ( ! mdoc_word_alloc(m, line, offs, buf+offs))
|
||||
return(0);
|
||||
|
||||
if (MDOC_LITERAL & m->flags)
|
||||
return(1);
|
||||
|
||||
/*
|
||||
* End-of-sentence check. If the last character is an unescaped
|
||||
* EOS character, then flag the node as being the end of a
|
||||
* sentence. The front-end will know how to interpret this.
|
||||
*/
|
||||
|
||||
assert(buf < end);
|
||||
|
||||
if (mandoc_eos(buf+offs, (size_t)(end-buf-offs), 0))
|
||||
m->last->flags |= MDOC_EOS;
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parse a macro line, that is, a line beginning with the control
|
||||
* character.
|
||||
*/
|
||||
static int
|
||||
mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs)
|
||||
{
|
||||
enum mdoct tok;
|
||||
int i, sv;
|
||||
char mac[5];
|
||||
struct mdoc_node *n;
|
||||
|
||||
/* Empty post-control lines are ignored. */
|
||||
|
||||
if ('"' == buf[offs]) {
|
||||
mdoc_pmsg(m, ln, offs, MANDOCERR_BADCOMMENT);
|
||||
return(1);
|
||||
} else if ('\0' == buf[offs])
|
||||
return(1);
|
||||
|
||||
sv = offs;
|
||||
|
||||
/*
|
||||
* Copy the first word into a nil-terminated buffer.
|
||||
* Stop copying when a tab, space, or eoln is encountered.
|
||||
*/
|
||||
|
||||
i = 0;
|
||||
while (i < 4 && '\0' != buf[offs] &&
|
||||
' ' != buf[offs] && '\t' != buf[offs])
|
||||
mac[i++] = buf[offs++];
|
||||
|
||||
mac[i] = '\0';
|
||||
|
||||
tok = (i > 1 || i < 4) ? mdoc_hash_find(mac) : MDOC_MAX;
|
||||
|
||||
if (MDOC_MAX == tok) {
|
||||
mandoc_vmsg(MANDOCERR_MACRO, m->parse,
|
||||
ln, sv, "%s", buf + sv - 1);
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* Disregard the first trailing tab, if applicable. */
|
||||
|
||||
if ('\t' == buf[offs])
|
||||
offs++;
|
||||
|
||||
/* Jump to the next non-whitespace word. */
|
||||
|
||||
while (buf[offs] && ' ' == buf[offs])
|
||||
offs++;
|
||||
|
||||
/*
|
||||
* Trailing whitespace. Note that tabs are allowed to be passed
|
||||
* into the parser as "text", so we only warn about spaces here.
|
||||
*/
|
||||
|
||||
if ('\0' == buf[offs] && ' ' == buf[offs - 1])
|
||||
mdoc_pmsg(m, ln, offs - 1, MANDOCERR_EOLNSPACE);
|
||||
|
||||
/*
|
||||
* If an initial macro or a list invocation, divert directly
|
||||
* into macro processing.
|
||||
*/
|
||||
|
||||
if (NULL == m->last || MDOC_It == tok || MDOC_El == tok) {
|
||||
if ( ! mdoc_macro(m, tok, ln, sv, &offs, buf))
|
||||
goto err;
|
||||
return(1);
|
||||
}
|
||||
|
||||
n = m->last;
|
||||
assert(m->last);
|
||||
|
||||
/*
|
||||
* If the first macro of a `Bl -column', open an `It' block
|
||||
* context around the parsed macro.
|
||||
*/
|
||||
|
||||
if (MDOC_Bl == n->tok && MDOC_BODY == n->type &&
|
||||
LIST_column == n->norm->Bl.type) {
|
||||
m->flags |= MDOC_FREECOL;
|
||||
if ( ! mdoc_macro(m, MDOC_It, ln, sv, &sv, buf))
|
||||
goto err;
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're following a block-level `It' within a `Bl -column'
|
||||
* context (perhaps opened in the above block or in ptext()),
|
||||
* then open an `It' block context around the parsed macro.
|
||||
*/
|
||||
|
||||
if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
|
||||
NULL != n->parent &&
|
||||
MDOC_Bl == n->parent->tok &&
|
||||
LIST_column == n->parent->norm->Bl.type) {
|
||||
m->flags |= MDOC_FREECOL;
|
||||
if ( ! mdoc_macro(m, MDOC_It, ln, sv, &sv, buf))
|
||||
goto err;
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* Normal processing of a macro. */
|
||||
|
||||
if ( ! mdoc_macro(m, tok, ln, sv, &offs, buf))
|
||||
goto err;
|
||||
|
||||
return(1);
|
||||
|
||||
err: /* Error out. */
|
||||
|
||||
m->flags |= MDOC_HALT;
|
||||
return(0);
|
||||
}
|
||||
|
||||
enum mdelim
|
||||
mdoc_isdelim(const char *p)
|
||||
{
|
||||
|
||||
if ('\0' == p[0])
|
||||
return(DELIM_NONE);
|
||||
|
||||
if ('\0' == p[1])
|
||||
switch (p[0]) {
|
||||
case('('):
|
||||
/* FALLTHROUGH */
|
||||
case('['):
|
||||
return(DELIM_OPEN);
|
||||
case('|'):
|
||||
return(DELIM_MIDDLE);
|
||||
case('.'):
|
||||
/* FALLTHROUGH */
|
||||
case(','):
|
||||
/* FALLTHROUGH */
|
||||
case(';'):
|
||||
/* FALLTHROUGH */
|
||||
case(':'):
|
||||
/* FALLTHROUGH */
|
||||
case('?'):
|
||||
/* FALLTHROUGH */
|
||||
case('!'):
|
||||
/* FALLTHROUGH */
|
||||
case(')'):
|
||||
/* FALLTHROUGH */
|
||||
case(']'):
|
||||
return(DELIM_CLOSE);
|
||||
default:
|
||||
return(DELIM_NONE);
|
||||
}
|
||||
|
||||
if ('\\' != p[0])
|
||||
return(DELIM_NONE);
|
||||
|
||||
if (0 == strcmp(p + 1, "."))
|
||||
return(DELIM_CLOSE);
|
||||
if (0 == strcmp(p + 1, "*(Ba"))
|
||||
return(DELIM_MIDDLE);
|
||||
|
||||
return(DELIM_NONE);
|
||||
}
|
392
contrib/mdocml/mdoc.h
Normal file
392
contrib/mdocml/mdoc.h
Normal file
@ -0,0 +1,392 @@
|
||||
/* $Id: mdoc.h,v 1.122 2011/03/22 14:05:45 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 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 MDOC_H
|
||||
#define MDOC_H
|
||||
|
||||
enum mdoct {
|
||||
MDOC_Ap = 0,
|
||||
MDOC_Dd,
|
||||
MDOC_Dt,
|
||||
MDOC_Os,
|
||||
MDOC_Sh,
|
||||
MDOC_Ss,
|
||||
MDOC_Pp,
|
||||
MDOC_D1,
|
||||
MDOC_Dl,
|
||||
MDOC_Bd,
|
||||
MDOC_Ed,
|
||||
MDOC_Bl,
|
||||
MDOC_El,
|
||||
MDOC_It,
|
||||
MDOC_Ad,
|
||||
MDOC_An,
|
||||
MDOC_Ar,
|
||||
MDOC_Cd,
|
||||
MDOC_Cm,
|
||||
MDOC_Dv,
|
||||
MDOC_Er,
|
||||
MDOC_Ev,
|
||||
MDOC_Ex,
|
||||
MDOC_Fa,
|
||||
MDOC_Fd,
|
||||
MDOC_Fl,
|
||||
MDOC_Fn,
|
||||
MDOC_Ft,
|
||||
MDOC_Ic,
|
||||
MDOC_In,
|
||||
MDOC_Li,
|
||||
MDOC_Nd,
|
||||
MDOC_Nm,
|
||||
MDOC_Op,
|
||||
MDOC_Ot,
|
||||
MDOC_Pa,
|
||||
MDOC_Rv,
|
||||
MDOC_St,
|
||||
MDOC_Va,
|
||||
MDOC_Vt,
|
||||
MDOC_Xr,
|
||||
MDOC__A,
|
||||
MDOC__B,
|
||||
MDOC__D,
|
||||
MDOC__I,
|
||||
MDOC__J,
|
||||
MDOC__N,
|
||||
MDOC__O,
|
||||
MDOC__P,
|
||||
MDOC__R,
|
||||
MDOC__T,
|
||||
MDOC__V,
|
||||
MDOC_Ac,
|
||||
MDOC_Ao,
|
||||
MDOC_Aq,
|
||||
MDOC_At,
|
||||
MDOC_Bc,
|
||||
MDOC_Bf,
|
||||
MDOC_Bo,
|
||||
MDOC_Bq,
|
||||
MDOC_Bsx,
|
||||
MDOC_Bx,
|
||||
MDOC_Db,
|
||||
MDOC_Dc,
|
||||
MDOC_Do,
|
||||
MDOC_Dq,
|
||||
MDOC_Ec,
|
||||
MDOC_Ef,
|
||||
MDOC_Em,
|
||||
MDOC_Eo,
|
||||
MDOC_Fx,
|
||||
MDOC_Ms,
|
||||
MDOC_No,
|
||||
MDOC_Ns,
|
||||
MDOC_Nx,
|
||||
MDOC_Ox,
|
||||
MDOC_Pc,
|
||||
MDOC_Pf,
|
||||
MDOC_Po,
|
||||
MDOC_Pq,
|
||||
MDOC_Qc,
|
||||
MDOC_Ql,
|
||||
MDOC_Qo,
|
||||
MDOC_Qq,
|
||||
MDOC_Re,
|
||||
MDOC_Rs,
|
||||
MDOC_Sc,
|
||||
MDOC_So,
|
||||
MDOC_Sq,
|
||||
MDOC_Sm,
|
||||
MDOC_Sx,
|
||||
MDOC_Sy,
|
||||
MDOC_Tn,
|
||||
MDOC_Ux,
|
||||
MDOC_Xc,
|
||||
MDOC_Xo,
|
||||
MDOC_Fo,
|
||||
MDOC_Fc,
|
||||
MDOC_Oo,
|
||||
MDOC_Oc,
|
||||
MDOC_Bk,
|
||||
MDOC_Ek,
|
||||
MDOC_Bt,
|
||||
MDOC_Hf,
|
||||
MDOC_Fr,
|
||||
MDOC_Ud,
|
||||
MDOC_Lb,
|
||||
MDOC_Lp,
|
||||
MDOC_Lk,
|
||||
MDOC_Mt,
|
||||
MDOC_Brq,
|
||||
MDOC_Bro,
|
||||
MDOC_Brc,
|
||||
MDOC__C,
|
||||
MDOC_Es,
|
||||
MDOC_En,
|
||||
MDOC_Dx,
|
||||
MDOC__Q,
|
||||
MDOC_br,
|
||||
MDOC_sp,
|
||||
MDOC__U,
|
||||
MDOC_Ta,
|
||||
MDOC_MAX
|
||||
};
|
||||
|
||||
enum mdocargt {
|
||||
MDOC_Split, /* -split */
|
||||
MDOC_Nosplit, /* -nospli */
|
||||
MDOC_Ragged, /* -ragged */
|
||||
MDOC_Unfilled, /* -unfilled */
|
||||
MDOC_Literal, /* -literal */
|
||||
MDOC_File, /* -file */
|
||||
MDOC_Offset, /* -offset */
|
||||
MDOC_Bullet, /* -bullet */
|
||||
MDOC_Dash, /* -dash */
|
||||
MDOC_Hyphen, /* -hyphen */
|
||||
MDOC_Item, /* -item */
|
||||
MDOC_Enum, /* -enum */
|
||||
MDOC_Tag, /* -tag */
|
||||
MDOC_Diag, /* -diag */
|
||||
MDOC_Hang, /* -hang */
|
||||
MDOC_Ohang, /* -ohang */
|
||||
MDOC_Inset, /* -inset */
|
||||
MDOC_Column, /* -column */
|
||||
MDOC_Width, /* -width */
|
||||
MDOC_Compact, /* -compact */
|
||||
MDOC_Std, /* -std */
|
||||
MDOC_Filled, /* -filled */
|
||||
MDOC_Words, /* -words */
|
||||
MDOC_Emphasis, /* -emphasis */
|
||||
MDOC_Symbolic, /* -symbolic */
|
||||
MDOC_Nested, /* -nested */
|
||||
MDOC_Centred, /* -centered */
|
||||
MDOC_ARG_MAX
|
||||
};
|
||||
|
||||
enum mdoc_type {
|
||||
MDOC_TEXT,
|
||||
MDOC_ELEM,
|
||||
MDOC_HEAD,
|
||||
MDOC_TAIL,
|
||||
MDOC_BODY,
|
||||
MDOC_BLOCK,
|
||||
MDOC_TBL,
|
||||
MDOC_EQN,
|
||||
MDOC_ROOT
|
||||
};
|
||||
|
||||
/*
|
||||
* Section (named/unnamed) of `Sh'. Note that these appear in the
|
||||
* conventional order imposed by mdoc.7. In the case of SEC_NONE, no
|
||||
* section has been invoked (this shouldn't happen). SEC_CUSTOM refers
|
||||
* to other sections.
|
||||
*/
|
||||
enum mdoc_sec {
|
||||
SEC_NONE = 0,
|
||||
SEC_NAME, /* NAME */
|
||||
SEC_LIBRARY, /* LIBRARY */
|
||||
SEC_SYNOPSIS, /* SYNOPSIS */
|
||||
SEC_DESCRIPTION, /* DESCRIPTION */
|
||||
SEC_IMPLEMENTATION, /* IMPLEMENTATION NOTES */
|
||||
SEC_RETURN_VALUES, /* RETURN VALUES */
|
||||
SEC_ENVIRONMENT, /* ENVIRONMENT */
|
||||
SEC_FILES, /* FILES */
|
||||
SEC_EXIT_STATUS, /* EXIT STATUS */
|
||||
SEC_EXAMPLES, /* EXAMPLES */
|
||||
SEC_DIAGNOSTICS, /* DIAGNOSTICS */
|
||||
SEC_COMPATIBILITY, /* COMPATIBILITY */
|
||||
SEC_ERRORS, /* ERRORS */
|
||||
SEC_SEE_ALSO, /* SEE ALSO */
|
||||
SEC_STANDARDS, /* STANDARDS */
|
||||
SEC_HISTORY, /* HISTORY */
|
||||
SEC_AUTHORS, /* AUTHORS */
|
||||
SEC_CAVEATS, /* CAVEATS */
|
||||
SEC_BUGS, /* BUGS */
|
||||
SEC_SECURITY, /* SECURITY */
|
||||
SEC_CUSTOM,
|
||||
SEC__MAX
|
||||
};
|
||||
|
||||
struct mdoc_meta {
|
||||
char *msec; /* `Dt' section (1, 3p, etc.) */
|
||||
char *vol; /* `Dt' volume (implied) */
|
||||
char *arch; /* `Dt' arch (i386, etc.) */
|
||||
char *date; /* `Dd' normalised date */
|
||||
char *title; /* `Dt' title (FOO, etc.) */
|
||||
char *os; /* `Os' system (OpenBSD, etc.) */
|
||||
char *name; /* leading `Nm' name */
|
||||
};
|
||||
|
||||
/*
|
||||
* An argument to a macro (multiple values = `-column xxx yyy').
|
||||
*/
|
||||
struct mdoc_argv {
|
||||
enum mdocargt arg; /* type of argument */
|
||||
int line;
|
||||
int pos;
|
||||
size_t sz; /* elements in "value" */
|
||||
char **value; /* argument strings */
|
||||
};
|
||||
|
||||
/*
|
||||
* Reference-counted macro arguments. These are refcounted because
|
||||
* blocks have multiple instances of the same arguments spread across
|
||||
* the HEAD, BODY, TAIL, and BLOCK node types.
|
||||
*/
|
||||
struct mdoc_arg {
|
||||
size_t argc;
|
||||
struct mdoc_argv *argv;
|
||||
unsigned int refcnt;
|
||||
};
|
||||
|
||||
/*
|
||||
* Indicates that a BODY's formatting has ended, but the scope is still
|
||||
* open. Used for syntax-broken blocks.
|
||||
*/
|
||||
enum mdoc_endbody {
|
||||
ENDBODY_NOT = 0,
|
||||
ENDBODY_SPACE, /* is broken: append a space */
|
||||
ENDBODY_NOSPACE /* is broken: don't append a space */
|
||||
};
|
||||
|
||||
enum mdoc_list {
|
||||
LIST__NONE = 0,
|
||||
LIST_bullet, /* -bullet */
|
||||
LIST_column, /* -column */
|
||||
LIST_dash, /* -dash */
|
||||
LIST_diag, /* -diag */
|
||||
LIST_enum, /* -enum */
|
||||
LIST_hang, /* -hang */
|
||||
LIST_hyphen, /* -hyphen */
|
||||
LIST_inset, /* -inset */
|
||||
LIST_item, /* -item */
|
||||
LIST_ohang, /* -ohang */
|
||||
LIST_tag, /* -tag */
|
||||
LIST_MAX
|
||||
};
|
||||
|
||||
enum mdoc_disp {
|
||||
DISP__NONE = 0,
|
||||
DISP_centred, /* -centered */
|
||||
DISP_ragged, /* -ragged */
|
||||
DISP_unfilled, /* -unfilled */
|
||||
DISP_filled, /* -filled */
|
||||
DISP_literal /* -literal */
|
||||
};
|
||||
|
||||
enum mdoc_auth {
|
||||
AUTH__NONE = 0,
|
||||
AUTH_split, /* -split */
|
||||
AUTH_nosplit /* -nosplit */
|
||||
};
|
||||
|
||||
enum mdoc_font {
|
||||
FONT__NONE = 0,
|
||||
FONT_Em, /* Em, -emphasis */
|
||||
FONT_Li, /* Li, -literal */
|
||||
FONT_Sy /* Sy, -symbolic */
|
||||
};
|
||||
|
||||
struct mdoc_bd {
|
||||
const char *offs; /* -offset */
|
||||
enum mdoc_disp type; /* -ragged, etc. */
|
||||
int comp; /* -compact */
|
||||
};
|
||||
|
||||
struct mdoc_bl {
|
||||
const char *width; /* -width */
|
||||
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. */
|
||||
};
|
||||
|
||||
struct mdoc_rs {
|
||||
int quote_T; /* whether to quote %T */
|
||||
};
|
||||
|
||||
/*
|
||||
* Consists of normalised node arguments. These should be used instead
|
||||
* of iterating through the mdoc_arg pointers of a node: defaults are
|
||||
* provided, etc.
|
||||
*/
|
||||
union mdoc_data {
|
||||
struct mdoc_an An;
|
||||
struct mdoc_bd Bd;
|
||||
struct mdoc_bf Bf;
|
||||
struct mdoc_bl Bl;
|
||||
struct mdoc_rs Rs;
|
||||
};
|
||||
|
||||
/*
|
||||
* Single node in tree-linked AST.
|
||||
*/
|
||||
struct mdoc_node {
|
||||
struct mdoc_node *parent; /* parent AST node */
|
||||
struct mdoc_node *child; /* first child AST node */
|
||||
struct mdoc_node *last; /* last child AST node */
|
||||
struct mdoc_node *next; /* sibling AST node */
|
||||
struct mdoc_node *prev; /* prior sibling AST node */
|
||||
int nchild; /* number children */
|
||||
int line; /* parse line */
|
||||
int pos; /* parse column */
|
||||
enum mdoct tok; /* tok or MDOC__MAX if none */
|
||||
int flags;
|
||||
#define MDOC_VALID (1 << 0) /* has been validated */
|
||||
#define MDOC_EOS (1 << 2) /* at sentence boundary */
|
||||
#define MDOC_LINE (1 << 3) /* first macro/text on line */
|
||||
#define MDOC_SYNPRETTY (1 << 4) /* SYNOPSIS-style formatting */
|
||||
#define MDOC_ENDED (1 << 5) /* rendering has been ended */
|
||||
#define MDOC_DELIMO (1 << 6)
|
||||
#define MDOC_DELIMC (1 << 7)
|
||||
enum mdoc_type type; /* AST node type */
|
||||
enum mdoc_sec sec; /* current named section */
|
||||
union mdoc_data *norm; /* normalised args */
|
||||
/* FIXME: these can be union'd to shave a few bytes. */
|
||||
struct mdoc_arg *args; /* BLOCK/ELEM */
|
||||
struct mdoc_node *pending; /* BLOCK */
|
||||
struct mdoc_node *head; /* BLOCK */
|
||||
struct mdoc_node *body; /* BLOCK */
|
||||
struct mdoc_node *tail; /* BLOCK */
|
||||
char *string; /* TEXT */
|
||||
const struct tbl_span *span; /* TBL */
|
||||
const struct eqn *eqn; /* EQN */
|
||||
enum mdoc_endbody end; /* BODY */
|
||||
};
|
||||
|
||||
/* Names of macros. Index is enum mdoct. */
|
||||
extern const char *const *mdoc_macronames;
|
||||
|
||||
/* Names of macro args. Index is enum mdocargt. */
|
||||
extern const char *const *mdoc_argnames;
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
struct mdoc;
|
||||
|
||||
const struct mdoc_node *mdoc_node(const struct mdoc *);
|
||||
const struct mdoc_meta *mdoc_meta(const struct mdoc *);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /*!MDOC_H*/
|
716
contrib/mdocml/mdoc_argv.c
Normal file
716
contrib/mdocml/mdoc_argv.c
Normal file
@ -0,0 +1,716 @@
|
||||
/* $Id: mdoc_argv.c,v 1.82 2012/03/23 05:50:24 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mdoc.h"
|
||||
#include "mandoc.h"
|
||||
#include "libmdoc.h"
|
||||
#include "libmandoc.h"
|
||||
|
||||
#define MULTI_STEP 5 /* pre-allocate argument values */
|
||||
#define DELIMSZ 6 /* max possible size of a delimiter */
|
||||
|
||||
enum argsflag {
|
||||
ARGSFL_NONE = 0,
|
||||
ARGSFL_DELIM, /* handle delimiters of [[::delim::][ ]+]+ */
|
||||
ARGSFL_TABSEP /* handle tab/`Ta' separated phrases */
|
||||
};
|
||||
|
||||
enum argvflag {
|
||||
ARGV_NONE, /* no args to flag (e.g., -split) */
|
||||
ARGV_SINGLE, /* one arg to flag (e.g., -file xxx) */
|
||||
ARGV_MULTI, /* multiple args (e.g., -column xxx yyy) */
|
||||
ARGV_OPT_SINGLE /* optional arg (e.g., -offset [xxx]) */
|
||||
};
|
||||
|
||||
struct mdocarg {
|
||||
enum argsflag flags;
|
||||
const enum mdocargt *argvs;
|
||||
};
|
||||
|
||||
static void argn_free(struct mdoc_arg *, int);
|
||||
static enum margserr args(struct mdoc *, int, int *,
|
||||
char *, enum argsflag, char **);
|
||||
static int args_checkpunct(const char *, int);
|
||||
static int argv_multi(struct mdoc *, int,
|
||||
struct mdoc_argv *, int *, char *);
|
||||
static int argv_opt_single(struct mdoc *, int,
|
||||
struct mdoc_argv *, int *, char *);
|
||||
static int argv_single(struct mdoc *, int,
|
||||
struct mdoc_argv *, int *, char *);
|
||||
|
||||
static const enum argvflag argvflags[MDOC_ARG_MAX] = {
|
||||
ARGV_NONE, /* MDOC_Split */
|
||||
ARGV_NONE, /* MDOC_Nosplit */
|
||||
ARGV_NONE, /* MDOC_Ragged */
|
||||
ARGV_NONE, /* MDOC_Unfilled */
|
||||
ARGV_NONE, /* MDOC_Literal */
|
||||
ARGV_SINGLE, /* MDOC_File */
|
||||
ARGV_OPT_SINGLE, /* MDOC_Offset */
|
||||
ARGV_NONE, /* MDOC_Bullet */
|
||||
ARGV_NONE, /* MDOC_Dash */
|
||||
ARGV_NONE, /* MDOC_Hyphen */
|
||||
ARGV_NONE, /* MDOC_Item */
|
||||
ARGV_NONE, /* MDOC_Enum */
|
||||
ARGV_NONE, /* MDOC_Tag */
|
||||
ARGV_NONE, /* MDOC_Diag */
|
||||
ARGV_NONE, /* MDOC_Hang */
|
||||
ARGV_NONE, /* MDOC_Ohang */
|
||||
ARGV_NONE, /* MDOC_Inset */
|
||||
ARGV_MULTI, /* MDOC_Column */
|
||||
ARGV_OPT_SINGLE, /* MDOC_Width */
|
||||
ARGV_NONE, /* MDOC_Compact */
|
||||
ARGV_NONE, /* MDOC_Std */
|
||||
ARGV_NONE, /* MDOC_Filled */
|
||||
ARGV_NONE, /* MDOC_Words */
|
||||
ARGV_NONE, /* MDOC_Emphasis */
|
||||
ARGV_NONE, /* MDOC_Symbolic */
|
||||
ARGV_NONE /* MDOC_Symbolic */
|
||||
};
|
||||
|
||||
static const enum mdocargt args_Ex[] = {
|
||||
MDOC_Std,
|
||||
MDOC_ARG_MAX
|
||||
};
|
||||
|
||||
static const enum mdocargt args_An[] = {
|
||||
MDOC_Split,
|
||||
MDOC_Nosplit,
|
||||
MDOC_ARG_MAX
|
||||
};
|
||||
|
||||
static const enum mdocargt args_Bd[] = {
|
||||
MDOC_Ragged,
|
||||
MDOC_Unfilled,
|
||||
MDOC_Filled,
|
||||
MDOC_Literal,
|
||||
MDOC_File,
|
||||
MDOC_Offset,
|
||||
MDOC_Compact,
|
||||
MDOC_Centred,
|
||||
MDOC_ARG_MAX
|
||||
};
|
||||
|
||||
static const enum mdocargt args_Bf[] = {
|
||||
MDOC_Emphasis,
|
||||
MDOC_Literal,
|
||||
MDOC_Symbolic,
|
||||
MDOC_ARG_MAX
|
||||
};
|
||||
|
||||
static const enum mdocargt args_Bk[] = {
|
||||
MDOC_Words,
|
||||
MDOC_ARG_MAX
|
||||
};
|
||||
|
||||
static const enum mdocargt args_Bl[] = {
|
||||
MDOC_Bullet,
|
||||
MDOC_Dash,
|
||||
MDOC_Hyphen,
|
||||
MDOC_Item,
|
||||
MDOC_Enum,
|
||||
MDOC_Tag,
|
||||
MDOC_Diag,
|
||||
MDOC_Hang,
|
||||
MDOC_Ohang,
|
||||
MDOC_Inset,
|
||||
MDOC_Column,
|
||||
MDOC_Width,
|
||||
MDOC_Offset,
|
||||
MDOC_Compact,
|
||||
MDOC_Nested,
|
||||
MDOC_ARG_MAX
|
||||
};
|
||||
|
||||
static const struct mdocarg mdocargs[MDOC_MAX] = {
|
||||
{ ARGSFL_NONE, NULL }, /* Ap */
|
||||
{ ARGSFL_NONE, NULL }, /* Dd */
|
||||
{ ARGSFL_NONE, NULL }, /* Dt */
|
||||
{ ARGSFL_NONE, NULL }, /* Os */
|
||||
{ ARGSFL_NONE, NULL }, /* Sh */
|
||||
{ ARGSFL_NONE, NULL }, /* Ss */
|
||||
{ ARGSFL_NONE, NULL }, /* Pp */
|
||||
{ ARGSFL_DELIM, NULL }, /* D1 */
|
||||
{ ARGSFL_DELIM, NULL }, /* Dl */
|
||||
{ ARGSFL_NONE, args_Bd }, /* Bd */
|
||||
{ ARGSFL_NONE, NULL }, /* Ed */
|
||||
{ ARGSFL_NONE, args_Bl }, /* Bl */
|
||||
{ ARGSFL_NONE, NULL }, /* El */
|
||||
{ ARGSFL_NONE, NULL }, /* It */
|
||||
{ ARGSFL_DELIM, NULL }, /* Ad */
|
||||
{ ARGSFL_DELIM, args_An }, /* An */
|
||||
{ ARGSFL_DELIM, NULL }, /* Ar */
|
||||
{ ARGSFL_NONE, NULL }, /* Cd */
|
||||
{ ARGSFL_DELIM, NULL }, /* Cm */
|
||||
{ ARGSFL_DELIM, NULL }, /* Dv */
|
||||
{ ARGSFL_DELIM, NULL }, /* Er */
|
||||
{ ARGSFL_DELIM, NULL }, /* Ev */
|
||||
{ ARGSFL_NONE, args_Ex }, /* Ex */
|
||||
{ ARGSFL_DELIM, NULL }, /* Fa */
|
||||
{ ARGSFL_NONE, NULL }, /* Fd */
|
||||
{ ARGSFL_DELIM, NULL }, /* Fl */
|
||||
{ ARGSFL_DELIM, NULL }, /* Fn */
|
||||
{ ARGSFL_DELIM, NULL }, /* Ft */
|
||||
{ ARGSFL_DELIM, NULL }, /* Ic */
|
||||
{ ARGSFL_NONE, NULL }, /* In */
|
||||
{ ARGSFL_DELIM, NULL }, /* Li */
|
||||
{ ARGSFL_NONE, NULL }, /* Nd */
|
||||
{ ARGSFL_DELIM, NULL }, /* Nm */
|
||||
{ ARGSFL_DELIM, NULL }, /* Op */
|
||||
{ ARGSFL_NONE, NULL }, /* Ot */
|
||||
{ ARGSFL_DELIM, NULL }, /* Pa */
|
||||
{ ARGSFL_NONE, args_Ex }, /* Rv */
|
||||
{ ARGSFL_DELIM, NULL }, /* St */
|
||||
{ ARGSFL_DELIM, NULL }, /* Va */
|
||||
{ ARGSFL_DELIM, NULL }, /* Vt */
|
||||
{ ARGSFL_DELIM, NULL }, /* Xr */
|
||||
{ ARGSFL_NONE, NULL }, /* %A */
|
||||
{ ARGSFL_NONE, NULL }, /* %B */
|
||||
{ ARGSFL_NONE, NULL }, /* %D */
|
||||
{ ARGSFL_NONE, NULL }, /* %I */
|
||||
{ ARGSFL_NONE, NULL }, /* %J */
|
||||
{ ARGSFL_NONE, NULL }, /* %N */
|
||||
{ ARGSFL_NONE, NULL }, /* %O */
|
||||
{ ARGSFL_NONE, NULL }, /* %P */
|
||||
{ ARGSFL_NONE, NULL }, /* %R */
|
||||
{ ARGSFL_NONE, NULL }, /* %T */
|
||||
{ ARGSFL_NONE, NULL }, /* %V */
|
||||
{ ARGSFL_DELIM, NULL }, /* Ac */
|
||||
{ ARGSFL_NONE, NULL }, /* Ao */
|
||||
{ ARGSFL_DELIM, NULL }, /* Aq */
|
||||
{ ARGSFL_DELIM, NULL }, /* At */
|
||||
{ ARGSFL_DELIM, NULL }, /* Bc */
|
||||
{ ARGSFL_NONE, args_Bf }, /* Bf */
|
||||
{ ARGSFL_NONE, NULL }, /* Bo */
|
||||
{ ARGSFL_DELIM, NULL }, /* Bq */
|
||||
{ ARGSFL_DELIM, NULL }, /* Bsx */
|
||||
{ ARGSFL_DELIM, NULL }, /* Bx */
|
||||
{ ARGSFL_NONE, NULL }, /* Db */
|
||||
{ ARGSFL_DELIM, NULL }, /* Dc */
|
||||
{ ARGSFL_NONE, NULL }, /* Do */
|
||||
{ ARGSFL_DELIM, NULL }, /* Dq */
|
||||
{ ARGSFL_DELIM, NULL }, /* Ec */
|
||||
{ ARGSFL_NONE, NULL }, /* Ef */
|
||||
{ ARGSFL_DELIM, NULL }, /* Em */
|
||||
{ ARGSFL_NONE, NULL }, /* Eo */
|
||||
{ ARGSFL_DELIM, NULL }, /* Fx */
|
||||
{ ARGSFL_DELIM, NULL }, /* Ms */
|
||||
{ ARGSFL_DELIM, NULL }, /* No */
|
||||
{ ARGSFL_DELIM, NULL }, /* Ns */
|
||||
{ ARGSFL_DELIM, NULL }, /* Nx */
|
||||
{ ARGSFL_DELIM, NULL }, /* Ox */
|
||||
{ ARGSFL_DELIM, NULL }, /* Pc */
|
||||
{ ARGSFL_DELIM, NULL }, /* Pf */
|
||||
{ ARGSFL_NONE, NULL }, /* Po */
|
||||
{ ARGSFL_DELIM, NULL }, /* Pq */
|
||||
{ ARGSFL_DELIM, NULL }, /* Qc */
|
||||
{ ARGSFL_DELIM, NULL }, /* Ql */
|
||||
{ ARGSFL_NONE, NULL }, /* Qo */
|
||||
{ ARGSFL_DELIM, NULL }, /* Qq */
|
||||
{ ARGSFL_NONE, NULL }, /* Re */
|
||||
{ ARGSFL_NONE, NULL }, /* Rs */
|
||||
{ ARGSFL_DELIM, NULL }, /* Sc */
|
||||
{ ARGSFL_NONE, NULL }, /* So */
|
||||
{ ARGSFL_DELIM, NULL }, /* Sq */
|
||||
{ ARGSFL_NONE, NULL }, /* Sm */
|
||||
{ ARGSFL_DELIM, NULL }, /* Sx */
|
||||
{ ARGSFL_DELIM, NULL }, /* Sy */
|
||||
{ ARGSFL_DELIM, NULL }, /* Tn */
|
||||
{ ARGSFL_DELIM, NULL }, /* Ux */
|
||||
{ ARGSFL_DELIM, NULL }, /* Xc */
|
||||
{ ARGSFL_NONE, NULL }, /* Xo */
|
||||
{ ARGSFL_NONE, NULL }, /* Fo */
|
||||
{ ARGSFL_NONE, NULL }, /* Fc */
|
||||
{ ARGSFL_NONE, NULL }, /* Oo */
|
||||
{ ARGSFL_DELIM, NULL }, /* Oc */
|
||||
{ ARGSFL_NONE, args_Bk }, /* Bk */
|
||||
{ ARGSFL_NONE, NULL }, /* Ek */
|
||||
{ ARGSFL_NONE, NULL }, /* Bt */
|
||||
{ ARGSFL_NONE, NULL }, /* Hf */
|
||||
{ ARGSFL_NONE, NULL }, /* Fr */
|
||||
{ ARGSFL_NONE, NULL }, /* Ud */
|
||||
{ ARGSFL_NONE, NULL }, /* Lb */
|
||||
{ ARGSFL_NONE, NULL }, /* Lp */
|
||||
{ ARGSFL_DELIM, NULL }, /* Lk */
|
||||
{ ARGSFL_DELIM, NULL }, /* Mt */
|
||||
{ ARGSFL_DELIM, NULL }, /* Brq */
|
||||
{ ARGSFL_NONE, NULL }, /* Bro */
|
||||
{ ARGSFL_DELIM, NULL }, /* Brc */
|
||||
{ ARGSFL_NONE, NULL }, /* %C */
|
||||
{ ARGSFL_NONE, NULL }, /* Es */
|
||||
{ ARGSFL_NONE, NULL }, /* En */
|
||||
{ ARGSFL_NONE, NULL }, /* Dx */
|
||||
{ ARGSFL_NONE, NULL }, /* %Q */
|
||||
{ ARGSFL_NONE, NULL }, /* br */
|
||||
{ ARGSFL_NONE, NULL }, /* sp */
|
||||
{ ARGSFL_NONE, NULL }, /* %U */
|
||||
{ ARGSFL_NONE, NULL }, /* Ta */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Parse an argument from line text. This comes in the form of -key
|
||||
* [value0...], which may either have a single mandatory value, at least
|
||||
* one mandatory value, an optional single value, or no value.
|
||||
*/
|
||||
enum margverr
|
||||
mdoc_argv(struct mdoc *m, int line, enum mdoct tok,
|
||||
struct mdoc_arg **v, int *pos, char *buf)
|
||||
{
|
||||
char *p, sv;
|
||||
struct mdoc_argv tmp;
|
||||
struct mdoc_arg *arg;
|
||||
const enum mdocargt *ap;
|
||||
|
||||
if ('\0' == buf[*pos])
|
||||
return(ARGV_EOLN);
|
||||
else if (NULL == (ap = mdocargs[tok].argvs))
|
||||
return(ARGV_WORD);
|
||||
else if ('-' != buf[*pos])
|
||||
return(ARGV_WORD);
|
||||
|
||||
/* Seek to the first unescaped space. */
|
||||
|
||||
p = &buf[++(*pos)];
|
||||
|
||||
assert(*pos > 0);
|
||||
|
||||
for ( ; buf[*pos] ; (*pos)++)
|
||||
if (' ' == buf[*pos] && '\\' != buf[*pos - 1])
|
||||
break;
|
||||
|
||||
/*
|
||||
* We want to nil-terminate the word to look it up (it's easier
|
||||
* that way). But we may not have a flag, in which case we need
|
||||
* to restore the line as-is. So keep around the stray byte,
|
||||
* which we'll reset upon exiting (if necessary).
|
||||
*/
|
||||
|
||||
if ('\0' != (sv = buf[*pos]))
|
||||
buf[(*pos)++] = '\0';
|
||||
|
||||
/*
|
||||
* Now look up the word as a flag. Use temporary storage that
|
||||
* we'll copy into the node's flags, if necessary.
|
||||
*/
|
||||
|
||||
memset(&tmp, 0, sizeof(struct mdoc_argv));
|
||||
|
||||
tmp.line = line;
|
||||
tmp.pos = *pos;
|
||||
tmp.arg = MDOC_ARG_MAX;
|
||||
|
||||
while (MDOC_ARG_MAX != (tmp.arg = *ap++))
|
||||
if (0 == strcmp(p, mdoc_argnames[tmp.arg]))
|
||||
break;
|
||||
|
||||
if (MDOC_ARG_MAX == tmp.arg) {
|
||||
/*
|
||||
* The flag was not found.
|
||||
* Restore saved zeroed byte and return as a word.
|
||||
*/
|
||||
if (sv)
|
||||
buf[*pos - 1] = sv;
|
||||
return(ARGV_WORD);
|
||||
}
|
||||
|
||||
/* Read to the next word (the argument). */
|
||||
|
||||
while (buf[*pos] && ' ' == buf[*pos])
|
||||
(*pos)++;
|
||||
|
||||
switch (argvflags[tmp.arg]) {
|
||||
case (ARGV_SINGLE):
|
||||
if ( ! argv_single(m, line, &tmp, pos, buf))
|
||||
return(ARGV_ERROR);
|
||||
break;
|
||||
case (ARGV_MULTI):
|
||||
if ( ! argv_multi(m, line, &tmp, pos, buf))
|
||||
return(ARGV_ERROR);
|
||||
break;
|
||||
case (ARGV_OPT_SINGLE):
|
||||
if ( ! argv_opt_single(m, line, &tmp, pos, buf))
|
||||
return(ARGV_ERROR);
|
||||
break;
|
||||
case (ARGV_NONE):
|
||||
break;
|
||||
}
|
||||
|
||||
if (NULL == (arg = *v))
|
||||
arg = *v = mandoc_calloc(1, sizeof(struct mdoc_arg));
|
||||
|
||||
arg->argc++;
|
||||
arg->argv = mandoc_realloc
|
||||
(arg->argv, arg->argc * sizeof(struct mdoc_argv));
|
||||
|
||||
memcpy(&arg->argv[(int)arg->argc - 1],
|
||||
&tmp, sizeof(struct mdoc_argv));
|
||||
|
||||
return(ARGV_ARG);
|
||||
}
|
||||
|
||||
void
|
||||
mdoc_argv_free(struct mdoc_arg *p)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (NULL == p)
|
||||
return;
|
||||
|
||||
if (p->refcnt) {
|
||||
--(p->refcnt);
|
||||
if (p->refcnt)
|
||||
return;
|
||||
}
|
||||
assert(p->argc);
|
||||
|
||||
for (i = (int)p->argc - 1; i >= 0; i--)
|
||||
argn_free(p, i);
|
||||
|
||||
free(p->argv);
|
||||
free(p);
|
||||
}
|
||||
|
||||
static void
|
||||
argn_free(struct mdoc_arg *p, int iarg)
|
||||
{
|
||||
struct mdoc_argv *arg;
|
||||
int j;
|
||||
|
||||
arg = &p->argv[iarg];
|
||||
|
||||
if (arg->sz && arg->value) {
|
||||
for (j = (int)arg->sz - 1; j >= 0; j--)
|
||||
free(arg->value[j]);
|
||||
free(arg->value);
|
||||
}
|
||||
|
||||
for (--p->argc; iarg < (int)p->argc; iarg++)
|
||||
p->argv[iarg] = p->argv[iarg+1];
|
||||
}
|
||||
|
||||
enum margserr
|
||||
mdoc_zargs(struct mdoc *m, int line, int *pos, char *buf, char **v)
|
||||
{
|
||||
|
||||
return(args(m, line, pos, buf, ARGSFL_NONE, v));
|
||||
}
|
||||
|
||||
enum margserr
|
||||
mdoc_args(struct mdoc *m, int line, int *pos,
|
||||
char *buf, enum mdoct tok, char **v)
|
||||
{
|
||||
enum argsflag fl;
|
||||
struct mdoc_node *n;
|
||||
|
||||
fl = mdocargs[tok].flags;
|
||||
|
||||
if (MDOC_It != tok)
|
||||
return(args(m, line, pos, buf, fl, v));
|
||||
|
||||
/*
|
||||
* We know that we're in an `It', so it's reasonable to expect
|
||||
* us to be sitting in a `Bl'. Someday this may not be the case
|
||||
* (if we allow random `It's sitting out there), so provide a
|
||||
* safe fall-back into the default behaviour.
|
||||
*/
|
||||
|
||||
for (n = m->last; n; n = n->parent)
|
||||
if (MDOC_Bl == n->tok)
|
||||
if (LIST_column == n->norm->Bl.type) {
|
||||
fl = ARGSFL_TABSEP;
|
||||
break;
|
||||
}
|
||||
|
||||
return(args(m, line, pos, buf, fl, v));
|
||||
}
|
||||
|
||||
static enum margserr
|
||||
args(struct mdoc *m, int line, int *pos,
|
||||
char *buf, enum argsflag fl, char **v)
|
||||
{
|
||||
char *p, *pp;
|
||||
enum margserr rc;
|
||||
|
||||
if ('\0' == buf[*pos]) {
|
||||
if (MDOC_PPHRASE & m->flags)
|
||||
return(ARGS_EOLN);
|
||||
/*
|
||||
* If we're not in a partial phrase and the flag for
|
||||
* being a phrase literal is still set, the punctuation
|
||||
* is unterminated.
|
||||
*/
|
||||
if (MDOC_PHRASELIT & m->flags)
|
||||
mdoc_pmsg(m, line, *pos, MANDOCERR_BADQUOTE);
|
||||
|
||||
m->flags &= ~MDOC_PHRASELIT;
|
||||
return(ARGS_EOLN);
|
||||
}
|
||||
|
||||
*v = &buf[*pos];
|
||||
|
||||
if (ARGSFL_DELIM == fl)
|
||||
if (args_checkpunct(buf, *pos))
|
||||
return(ARGS_PUNCT);
|
||||
|
||||
/*
|
||||
* First handle TABSEP items, restricted to `Bl -column'. This
|
||||
* ignores conventional token parsing and instead uses tabs or
|
||||
* `Ta' macros to separate phrases. Phrases are parsed again
|
||||
* for arguments at a later phase.
|
||||
*/
|
||||
|
||||
if (ARGSFL_TABSEP == fl) {
|
||||
/* Scan ahead to tab (can't be escaped). */
|
||||
p = strchr(*v, '\t');
|
||||
pp = NULL;
|
||||
|
||||
/* Scan ahead to unescaped `Ta'. */
|
||||
if ( ! (MDOC_PHRASELIT & m->flags))
|
||||
for (pp = *v; ; pp++) {
|
||||
if (NULL == (pp = strstr(pp, "Ta")))
|
||||
break;
|
||||
if (pp > *v && ' ' != *(pp - 1))
|
||||
continue;
|
||||
if (' ' == *(pp + 2) || '\0' == *(pp + 2))
|
||||
break;
|
||||
}
|
||||
|
||||
/* By default, assume a phrase. */
|
||||
rc = ARGS_PHRASE;
|
||||
|
||||
/*
|
||||
* Adjust new-buffer position to be beyond delimiter
|
||||
* mark (e.g., Ta -> end + 2).
|
||||
*/
|
||||
if (p && pp) {
|
||||
*pos += pp < p ? 2 : 1;
|
||||
rc = pp < p ? ARGS_PHRASE : ARGS_PPHRASE;
|
||||
p = pp < p ? pp : p;
|
||||
} else if (p && ! pp) {
|
||||
rc = ARGS_PPHRASE;
|
||||
*pos += 1;
|
||||
} else if (pp && ! p) {
|
||||
p = pp;
|
||||
*pos += 2;
|
||||
} else {
|
||||
rc = ARGS_PEND;
|
||||
p = strchr(*v, 0);
|
||||
}
|
||||
|
||||
/* Whitespace check for eoln case... */
|
||||
if ('\0' == *p && ' ' == *(p - 1))
|
||||
mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE);
|
||||
|
||||
*pos += (int)(p - *v);
|
||||
|
||||
/* Strip delimiter's preceding whitespace. */
|
||||
pp = p - 1;
|
||||
while (pp > *v && ' ' == *pp) {
|
||||
if (pp > *v && '\\' == *(pp - 1))
|
||||
break;
|
||||
pp--;
|
||||
}
|
||||
*(pp + 1) = 0;
|
||||
|
||||
/* Strip delimiter's proceeding whitespace. */
|
||||
for (pp = &buf[*pos]; ' ' == *pp; pp++, (*pos)++)
|
||||
/* Skip ahead. */ ;
|
||||
|
||||
return(rc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a quoted literal. A quote begins with a double-quote
|
||||
* and ends with a double-quote NOT preceded by a double-quote.
|
||||
* Whitespace is NOT involved in literal termination.
|
||||
*/
|
||||
|
||||
if (MDOC_PHRASELIT & m->flags || '\"' == buf[*pos]) {
|
||||
if ( ! (MDOC_PHRASELIT & m->flags))
|
||||
*v = &buf[++(*pos)];
|
||||
|
||||
if (MDOC_PPHRASE & m->flags)
|
||||
m->flags |= MDOC_PHRASELIT;
|
||||
|
||||
for ( ; buf[*pos]; (*pos)++) {
|
||||
if ('\"' != buf[*pos])
|
||||
continue;
|
||||
if ('\"' != buf[*pos + 1])
|
||||
break;
|
||||
(*pos)++;
|
||||
}
|
||||
|
||||
if ('\0' == buf[*pos]) {
|
||||
if (MDOC_PPHRASE & m->flags)
|
||||
return(ARGS_QWORD);
|
||||
mdoc_pmsg(m, line, *pos, MANDOCERR_BADQUOTE);
|
||||
return(ARGS_QWORD);
|
||||
}
|
||||
|
||||
m->flags &= ~MDOC_PHRASELIT;
|
||||
buf[(*pos)++] = '\0';
|
||||
|
||||
if ('\0' == buf[*pos])
|
||||
return(ARGS_QWORD);
|
||||
|
||||
while (' ' == buf[*pos])
|
||||
(*pos)++;
|
||||
|
||||
if ('\0' == buf[*pos])
|
||||
mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE);
|
||||
|
||||
return(ARGS_QWORD);
|
||||
}
|
||||
|
||||
p = &buf[*pos];
|
||||
*v = mandoc_getarg(m->parse, &p, line, pos);
|
||||
|
||||
return(ARGS_WORD);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the string consists only of space-separated closing
|
||||
* delimiters. This is a bit of a dance: the first must be a close
|
||||
* delimiter, but it may be followed by middle delimiters. Arbitrary
|
||||
* whitespace may separate these tokens.
|
||||
*/
|
||||
static int
|
||||
args_checkpunct(const char *buf, int i)
|
||||
{
|
||||
int j;
|
||||
char dbuf[DELIMSZ];
|
||||
enum mdelim d;
|
||||
|
||||
/* First token must be a close-delimiter. */
|
||||
|
||||
for (j = 0; buf[i] && ' ' != buf[i] && j < DELIMSZ; j++, i++)
|
||||
dbuf[j] = buf[i];
|
||||
|
||||
if (DELIMSZ == j)
|
||||
return(0);
|
||||
|
||||
dbuf[j] = '\0';
|
||||
if (DELIM_CLOSE != mdoc_isdelim(dbuf))
|
||||
return(0);
|
||||
|
||||
while (' ' == buf[i])
|
||||
i++;
|
||||
|
||||
/* Remaining must NOT be open/none. */
|
||||
|
||||
while (buf[i]) {
|
||||
j = 0;
|
||||
while (buf[i] && ' ' != buf[i] && j < DELIMSZ)
|
||||
dbuf[j++] = buf[i++];
|
||||
|
||||
if (DELIMSZ == j)
|
||||
return(0);
|
||||
|
||||
dbuf[j] = '\0';
|
||||
d = mdoc_isdelim(dbuf);
|
||||
if (DELIM_NONE == d || DELIM_OPEN == d)
|
||||
return(0);
|
||||
|
||||
while (' ' == buf[i])
|
||||
i++;
|
||||
}
|
||||
|
||||
return('\0' == buf[i]);
|
||||
}
|
||||
|
||||
static int
|
||||
argv_multi(struct mdoc *m, int line,
|
||||
struct mdoc_argv *v, int *pos, char *buf)
|
||||
{
|
||||
enum margserr ac;
|
||||
char *p;
|
||||
|
||||
for (v->sz = 0; ; v->sz++) {
|
||||
if ('-' == buf[*pos])
|
||||
break;
|
||||
ac = args(m, line, pos, buf, ARGSFL_NONE, &p);
|
||||
if (ARGS_ERROR == ac)
|
||||
return(0);
|
||||
else if (ARGS_EOLN == ac)
|
||||
break;
|
||||
|
||||
if (0 == v->sz % MULTI_STEP)
|
||||
v->value = mandoc_realloc(v->value,
|
||||
(v->sz + MULTI_STEP) * sizeof(char *));
|
||||
|
||||
v->value[(int)v->sz] = mandoc_strdup(p);
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int
|
||||
argv_opt_single(struct mdoc *m, int line,
|
||||
struct mdoc_argv *v, int *pos, char *buf)
|
||||
{
|
||||
enum margserr ac;
|
||||
char *p;
|
||||
|
||||
if ('-' == buf[*pos])
|
||||
return(1);
|
||||
|
||||
ac = args(m, line, pos, buf, ARGSFL_NONE, &p);
|
||||
if (ARGS_ERROR == ac)
|
||||
return(0);
|
||||
if (ARGS_EOLN == ac)
|
||||
return(1);
|
||||
|
||||
v->sz = 1;
|
||||
v->value = mandoc_malloc(sizeof(char *));
|
||||
v->value[0] = mandoc_strdup(p);
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int
|
||||
argv_single(struct mdoc *m, int line,
|
||||
struct mdoc_argv *v, int *pos, char *buf)
|
||||
{
|
||||
int ppos;
|
||||
enum margserr ac;
|
||||
char *p;
|
||||
|
||||
ppos = *pos;
|
||||
|
||||
ac = args(m, line, pos, buf, ARGSFL_NONE, &p);
|
||||
if (ARGS_EOLN == ac) {
|
||||
mdoc_pmsg(m, line, ppos, MANDOCERR_SYNTARGVCOUNT);
|
||||
return(0);
|
||||
} else if (ARGS_ERROR == ac)
|
||||
return(0);
|
||||
|
||||
v->sz = 1;
|
||||
v->value = mandoc_malloc(sizeof(char *));
|
||||
v->value[0] = mandoc_strdup(p);
|
||||
|
||||
return(1);
|
||||
}
|
94
contrib/mdocml/mdoc_hash.c
Normal file
94
contrib/mdocml/mdoc_hash.c
Normal file
@ -0,0 +1,94 @@
|
||||
/* $Id: mdoc_hash.c,v 1.18 2011/07/24 18:15:14 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mdoc.h"
|
||||
#include "mandoc.h"
|
||||
#include "libmdoc.h"
|
||||
|
||||
static unsigned char table[27 * 12];
|
||||
|
||||
/*
|
||||
* XXX - this hash has global scope, so if intended for use as a library
|
||||
* with multiple callers, it will need re-invocation protection.
|
||||
*/
|
||||
void
|
||||
mdoc_hash_init(void)
|
||||
{
|
||||
int i, j, major;
|
||||
const char *p;
|
||||
|
||||
memset(table, UCHAR_MAX, sizeof(table));
|
||||
|
||||
for (i = 0; i < (int)MDOC_MAX; i++) {
|
||||
p = mdoc_macronames[i];
|
||||
|
||||
if (isalpha((unsigned char)p[1]))
|
||||
major = 12 * (tolower((unsigned char)p[1]) - 97);
|
||||
else
|
||||
major = 12 * 26;
|
||||
|
||||
for (j = 0; j < 12; j++)
|
||||
if (UCHAR_MAX == table[major + j]) {
|
||||
table[major + j] = (unsigned char)i;
|
||||
break;
|
||||
}
|
||||
|
||||
assert(j < 12);
|
||||
}
|
||||
}
|
||||
|
||||
enum mdoct
|
||||
mdoc_hash_find(const char *p)
|
||||
{
|
||||
int major, i, j;
|
||||
|
||||
if (0 == p[0])
|
||||
return(MDOC_MAX);
|
||||
if ( ! isalpha((unsigned char)p[0]) && '%' != p[0])
|
||||
return(MDOC_MAX);
|
||||
|
||||
if (isalpha((unsigned char)p[1]))
|
||||
major = 12 * (tolower((unsigned char)p[1]) - 97);
|
||||
else if ('1' == p[1])
|
||||
major = 12 * 26;
|
||||
else
|
||||
return(MDOC_MAX);
|
||||
|
||||
if (p[2] && p[3])
|
||||
return(MDOC_MAX);
|
||||
|
||||
for (j = 0; j < 12; j++) {
|
||||
if (UCHAR_MAX == (i = table[major + j]))
|
||||
break;
|
||||
if (0 == strcmp(p, mdoc_macronames[i]))
|
||||
return((enum mdoct)i);
|
||||
}
|
||||
|
||||
return(MDOC_MAX);
|
||||
}
|
2284
contrib/mdocml/mdoc_html.c
Normal file
2284
contrib/mdocml/mdoc_html.c
Normal file
File diff suppressed because it is too large
Load Diff
1787
contrib/mdocml/mdoc_macro.c
Normal file
1787
contrib/mdocml/mdoc_macro.c
Normal file
File diff suppressed because it is too large
Load Diff
637
contrib/mdocml/mdoc_man.c
Normal file
637
contrib/mdocml/mdoc_man.c
Normal file
@ -0,0 +1,637 @@
|
||||
/* $Id: mdoc_man.c,v 1.9 2011/10/24 21:47:59 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "man.h"
|
||||
#include "mdoc.h"
|
||||
#include "main.h"
|
||||
|
||||
#define DECL_ARGS const struct mdoc_meta *m, \
|
||||
const struct mdoc_node *n, \
|
||||
struct mman *mm
|
||||
|
||||
struct mman {
|
||||
int need_space; /* next word needs prior ws */
|
||||
int need_nl; /* next word needs prior nl */
|
||||
};
|
||||
|
||||
struct manact {
|
||||
int (*cond)(DECL_ARGS); /* DON'T run actions */
|
||||
int (*pre)(DECL_ARGS); /* pre-node action */
|
||||
void (*post)(DECL_ARGS); /* post-node action */
|
||||
const char *prefix; /* pre-node string constant */
|
||||
const char *suffix; /* post-node string constant */
|
||||
};
|
||||
|
||||
static int cond_body(DECL_ARGS);
|
||||
static int cond_head(DECL_ARGS);
|
||||
static void post_bd(DECL_ARGS);
|
||||
static void post_dl(DECL_ARGS);
|
||||
static void post_enc(DECL_ARGS);
|
||||
static void post_nm(DECL_ARGS);
|
||||
static void post_percent(DECL_ARGS);
|
||||
static void post_pf(DECL_ARGS);
|
||||
static void post_sect(DECL_ARGS);
|
||||
static void post_sp(DECL_ARGS);
|
||||
static int pre_ap(DECL_ARGS);
|
||||
static int pre_bd(DECL_ARGS);
|
||||
static int pre_br(DECL_ARGS);
|
||||
static int pre_bx(DECL_ARGS);
|
||||
static int pre_dl(DECL_ARGS);
|
||||
static int pre_enc(DECL_ARGS);
|
||||
static int pre_it(DECL_ARGS);
|
||||
static int pre_nm(DECL_ARGS);
|
||||
static int pre_ns(DECL_ARGS);
|
||||
static int pre_pp(DECL_ARGS);
|
||||
static int pre_sp(DECL_ARGS);
|
||||
static int pre_sect(DECL_ARGS);
|
||||
static int pre_ux(DECL_ARGS);
|
||||
static int pre_xr(DECL_ARGS);
|
||||
static void print_word(struct mman *, const char *);
|
||||
static void print_node(DECL_ARGS);
|
||||
|
||||
static const struct manact manacts[MDOC_MAX + 1] = {
|
||||
{ NULL, pre_ap, NULL, NULL, NULL }, /* Ap */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Dd */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Dt */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Os */
|
||||
{ NULL, pre_sect, post_sect, ".SH", NULL }, /* Sh */
|
||||
{ NULL, pre_sect, post_sect, ".SS", NULL }, /* Ss */
|
||||
{ NULL, pre_pp, NULL, NULL, NULL }, /* Pp */
|
||||
{ cond_body, pre_dl, post_dl, NULL, NULL }, /* D1 */
|
||||
{ cond_body, pre_dl, post_dl, NULL, NULL }, /* Dl */
|
||||
{ cond_body, pre_bd, post_bd, 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, pre_enc, post_enc, "\\fI", "\\fP" }, /* Ad */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* _An */
|
||||
{ NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Ar */
|
||||
{ NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Cd */
|
||||
{ NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Cm */
|
||||
{ NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Dv */
|
||||
{ NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Er */
|
||||
{ NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* 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, pre_enc, post_enc, "\\fB", "\\fP" }, /* Ic */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* _In */
|
||||
{ NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* 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, pre_enc, post_enc, "The \\fB",
|
||||
"\\fP\nfunction returns the value 0 if successful;\n"
|
||||
"otherwise the value -1 is returned and the global\n"
|
||||
"variable \\fIerrno\\fP is set to indicate the error."
|
||||
}, /* 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 */
|
||||
{ cond_body, pre_enc, post_enc, "<", ">" }, /* 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 */
|
||||
{ cond_body, pre_enc, post_enc, "[", "]" }, /* Bo */
|
||||
{ cond_body, pre_enc, post_enc, "[", "]" }, /* Bq */
|
||||
{ NULL, pre_ux, NULL, "BSD/OS", NULL }, /* Bsx */
|
||||
{ NULL, pre_bx, NULL, NULL, NULL }, /* Bx */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Db */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Dc */
|
||||
{ cond_body, pre_enc, post_enc, "``", "''" }, /* 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, pre_ux, NULL, "FreeBSD", NULL }, /* Fx */
|
||||
{ NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Ms */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* No */
|
||||
{ NULL, pre_ns, NULL, NULL, NULL }, /* Ns */
|
||||
{ NULL, pre_ux, NULL, "NetBSD", NULL }, /* Nx */
|
||||
{ NULL, pre_ux, NULL, "OpenBSD", NULL }, /* Ox */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Pc */
|
||||
{ NULL, NULL, post_pf, NULL, NULL }, /* Pf */
|
||||
{ cond_body, pre_enc, post_enc, "(", ")" }, /* Po */
|
||||
{ cond_body, pre_enc, post_enc, "(", ")" }, /* Pq */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Qc */
|
||||
{ cond_body, pre_enc, post_enc, "`", "'" }, /* Ql */
|
||||
{ cond_body, pre_enc, post_enc, "\"", "\"" }, /* Qo */
|
||||
{ cond_body, pre_enc, post_enc, "\"", "\"" }, /* Qq */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Re */
|
||||
{ cond_body, pre_pp, NULL, NULL, NULL }, /* Rs */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Sc */
|
||||
{ cond_body, pre_enc, post_enc, "`", "'" }, /* So */
|
||||
{ cond_body, pre_enc, post_enc, "`", "'" }, /* Sq */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* _Sm */
|
||||
{ NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Sx */
|
||||
{ NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Sy */
|
||||
{ NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Tn */
|
||||
{ NULL, pre_ux, NULL, "UNIX", 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 */
|
||||
{ cond_body, pre_enc, post_enc, "[", "]" }, /* Oo */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Oc */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* _Bk */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* _Ek */
|
||||
{ NULL, pre_ux, NULL, "is currently in beta test.", NULL }, /* Bt */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Hf */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Fr */
|
||||
{ NULL, pre_ux, NULL, "currently under development.", NULL }, /* Ud */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* _Lb */
|
||||
{ NULL, pre_pp, NULL, NULL, NULL }, /* Lp */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* _Lk */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* _Mt */
|
||||
{ cond_body, pre_enc, post_enc, "{", "}" }, /* Brq */
|
||||
{ cond_body, pre_enc, post_enc, "{", "}" }, /* 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, pre_ux, NULL, "DragonFly", NULL }, /* Dx */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* _%Q */
|
||||
{ NULL, pre_br, NULL, NULL, NULL }, /* br */
|
||||
{ NULL, pre_sp, post_sp, NULL, NULL }, /* sp */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* _%U */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* _Ta */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* ROOT */
|
||||
};
|
||||
|
||||
static void
|
||||
print_word(struct mman *mm, const char *s)
|
||||
{
|
||||
|
||||
if (mm->need_nl) {
|
||||
/*
|
||||
* If we need a newline, print it now and start afresh.
|
||||
*/
|
||||
putchar('\n');
|
||||
mm->need_space = 0;
|
||||
mm->need_nl = 0;
|
||||
} else if (mm->need_space && '\0' != s[0])
|
||||
/*
|
||||
* If we need a space, only print it before
|
||||
* (1) a nonzero length word;
|
||||
* (2) a word that is non-punctuation; and
|
||||
* (3) if punctuation, non-terminating puncutation.
|
||||
*/
|
||||
if (NULL == strchr(".,:;)]?!", s[0]) || '\0' != s[1])
|
||||
putchar(' ');
|
||||
|
||||
/*
|
||||
* Reassign needing space if we're not following opening
|
||||
* punctuation.
|
||||
*/
|
||||
mm->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((unsigned char)*s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
man_man(void *arg, const struct man *man)
|
||||
{
|
||||
|
||||
/*
|
||||
* Dump the keep buffer.
|
||||
* We're guaranteed by now that this exists (is non-NULL).
|
||||
* Flush stdout afterward, just in case.
|
||||
*/
|
||||
fputs(mparse_getkeep(man_mparse(man)), stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void
|
||||
man_mdoc(void *arg, const struct mdoc *mdoc)
|
||||
{
|
||||
const struct mdoc_meta *m;
|
||||
const struct mdoc_node *n;
|
||||
struct mman mm;
|
||||
|
||||
m = mdoc_meta(mdoc);
|
||||
n = mdoc_node(mdoc);
|
||||
|
||||
printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"",
|
||||
m->title, m->msec, m->date, m->os, m->vol);
|
||||
|
||||
memset(&mm, 0, sizeof(struct mman));
|
||||
|
||||
mm.need_nl = 1;
|
||||
print_node(m, n, &mm);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
static void
|
||||
print_node(DECL_ARGS)
|
||||
{
|
||||
const struct mdoc_node *prev, *sub;
|
||||
const struct manact *act;
|
||||
int cond, do_sub;
|
||||
|
||||
/*
|
||||
* Break the line if we were parsed subsequent the current node.
|
||||
* This makes the page structure be more consistent.
|
||||
*/
|
||||
prev = n->prev ? n->prev : n->parent;
|
||||
if (prev && prev->line < n->line)
|
||||
mm->need_nl = 1;
|
||||
|
||||
act = NULL;
|
||||
cond = 0;
|
||||
do_sub = 1;
|
||||
|
||||
if (MDOC_TEXT == n->type) {
|
||||
/*
|
||||
* Make sure that we don't happen to start with a
|
||||
* control character at the start of a line.
|
||||
*/
|
||||
if (mm->need_nl && ('.' == *n->string ||
|
||||
'\'' == *n->string)) {
|
||||
print_word(mm, "\\&");
|
||||
mm->need_space = 0;
|
||||
}
|
||||
print_word(mm, n->string);
|
||||
} else {
|
||||
/*
|
||||
* Conditionally run the pre-node action handler for a
|
||||
* node.
|
||||
*/
|
||||
act = manacts + n->tok;
|
||||
cond = NULL == act->cond || (*act->cond)(m, n, mm);
|
||||
if (cond && act->pre)
|
||||
do_sub = (*act->pre)(m, n, mm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Conditionally run all child nodes.
|
||||
* Note that this iterates over children instead of using
|
||||
* recursion. This prevents unnecessary depth in the stack.
|
||||
*/
|
||||
if (do_sub)
|
||||
for (sub = n->child; sub; sub = sub->next)
|
||||
print_node(m, sub, mm);
|
||||
|
||||
/*
|
||||
* Lastly, conditionally run the post-node handler.
|
||||
*/
|
||||
if (cond && act->post)
|
||||
(*act->post)(m, n, mm);
|
||||
}
|
||||
|
||||
static int
|
||||
cond_head(DECL_ARGS)
|
||||
{
|
||||
|
||||
return(MDOC_HEAD == n->type);
|
||||
}
|
||||
|
||||
static int
|
||||
cond_body(DECL_ARGS)
|
||||
{
|
||||
|
||||
return(MDOC_BODY == n->type);
|
||||
}
|
||||
|
||||
/*
|
||||
* Output a font encoding before a node, e.g., \fR.
|
||||
* This obviously has no trailing space.
|
||||
*/
|
||||
static int
|
||||
pre_enc(DECL_ARGS)
|
||||
{
|
||||
const char *prefix;
|
||||
|
||||
prefix = manacts[n->tok].prefix;
|
||||
if (NULL == prefix)
|
||||
return(1);
|
||||
print_word(mm, prefix);
|
||||
mm->need_space = 0;
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Output a font encoding subsequent a node, e.g., \fP.
|
||||
*/
|
||||
static void
|
||||
post_enc(DECL_ARGS)
|
||||
{
|
||||
const char *suffix;
|
||||
|
||||
suffix = manacts[n->tok].suffix;
|
||||
if (NULL == suffix)
|
||||
return;
|
||||
mm->need_space = 0;
|
||||
print_word(mm, suffix);
|
||||
}
|
||||
|
||||
/*
|
||||
* Used in listings (percent = %A, e.g.).
|
||||
* FIXME: this is incomplete.
|
||||
* It doesn't print a nice ", and" for lists.
|
||||
*/
|
||||
static void
|
||||
post_percent(DECL_ARGS)
|
||||
{
|
||||
|
||||
post_enc(m, n, mm);
|
||||
if (n->next)
|
||||
print_word(mm, ",");
|
||||
else {
|
||||
print_word(mm, ".");
|
||||
mm->need_nl = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Print before a section header.
|
||||
*/
|
||||
static int
|
||||
pre_sect(DECL_ARGS)
|
||||
{
|
||||
|
||||
if (MDOC_HEAD != n->type)
|
||||
return(1);
|
||||
mm->need_nl = 1;
|
||||
print_word(mm, manacts[n->tok].prefix);
|
||||
print_word(mm, "\"");
|
||||
mm->need_space = 0;
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print subsequent a section header.
|
||||
*/
|
||||
static void
|
||||
post_sect(DECL_ARGS)
|
||||
{
|
||||
|
||||
if (MDOC_HEAD != n->type)
|
||||
return;
|
||||
mm->need_space = 0;
|
||||
print_word(mm, "\"");
|
||||
mm->need_nl = 1;
|
||||
}
|
||||
|
||||
static int
|
||||
pre_ap(DECL_ARGS)
|
||||
{
|
||||
|
||||
mm->need_space = 0;
|
||||
print_word(mm, "'");
|
||||
mm->need_space = 0;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
pre_bd(DECL_ARGS)
|
||||
{
|
||||
|
||||
if (DISP_unfilled == n->norm->Bd.type ||
|
||||
DISP_literal == n->norm->Bd.type) {
|
||||
mm->need_nl = 1;
|
||||
print_word(mm, ".nf");
|
||||
}
|
||||
mm->need_nl = 1;
|
||||
return(1);
|
||||
}
|
||||
|
||||
static void
|
||||
post_bd(DECL_ARGS)
|
||||
{
|
||||
|
||||
if (DISP_unfilled == n->norm->Bd.type ||
|
||||
DISP_literal == n->norm->Bd.type) {
|
||||
mm->need_nl = 1;
|
||||
print_word(mm, ".fi");
|
||||
}
|
||||
mm->need_nl = 1;
|
||||
}
|
||||
|
||||
static int
|
||||
pre_br(DECL_ARGS)
|
||||
{
|
||||
|
||||
mm->need_nl = 1;
|
||||
print_word(mm, ".br");
|
||||
mm->need_nl = 1;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
pre_bx(DECL_ARGS)
|
||||
{
|
||||
|
||||
n = n->child;
|
||||
if (n) {
|
||||
print_word(mm, n->string);
|
||||
mm->need_space = 0;
|
||||
n = n->next;
|
||||
}
|
||||
print_word(mm, "BSD");
|
||||
if (NULL == n)
|
||||
return(0);
|
||||
mm->need_space = 0;
|
||||
print_word(mm, "-");
|
||||
mm->need_space = 0;
|
||||
print_word(mm, n->string);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
pre_dl(DECL_ARGS)
|
||||
{
|
||||
|
||||
mm->need_nl = 1;
|
||||
print_word(mm, ".RS 6n");
|
||||
mm->need_nl = 1;
|
||||
return(1);
|
||||
}
|
||||
|
||||
static void
|
||||
post_dl(DECL_ARGS)
|
||||
{
|
||||
|
||||
mm->need_nl = 1;
|
||||
print_word(mm, ".RE");
|
||||
mm->need_nl = 1;
|
||||
}
|
||||
|
||||
static int
|
||||
pre_it(DECL_ARGS)
|
||||
{
|
||||
const struct mdoc_node *bln;
|
||||
|
||||
if (MDOC_HEAD == n->type) {
|
||||
mm->need_nl = 1;
|
||||
print_word(mm, ".TP");
|
||||
bln = n->parent->parent->prev;
|
||||
switch (bln->norm->Bl.type) {
|
||||
case (LIST_bullet):
|
||||
print_word(mm, "4n");
|
||||
mm->need_nl = 1;
|
||||
print_word(mm, "\\fBo\\fP");
|
||||
break;
|
||||
default:
|
||||
if (bln->norm->Bl.width)
|
||||
print_word(mm, bln->norm->Bl.width);
|
||||
break;
|
||||
}
|
||||
mm->need_nl = 1;
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int
|
||||
pre_nm(DECL_ARGS)
|
||||
{
|
||||
|
||||
if (MDOC_ELEM != n->type && MDOC_HEAD != n->type)
|
||||
return(1);
|
||||
print_word(mm, "\\fB");
|
||||
mm->need_space = 0;
|
||||
if (NULL == n->child)
|
||||
print_word(mm, m->name);
|
||||
return(1);
|
||||
}
|
||||
|
||||
static void
|
||||
post_nm(DECL_ARGS)
|
||||
{
|
||||
|
||||
if (MDOC_ELEM != n->type && MDOC_HEAD != n->type)
|
||||
return;
|
||||
mm->need_space = 0;
|
||||
print_word(mm, "\\fP");
|
||||
}
|
||||
|
||||
static int
|
||||
pre_ns(DECL_ARGS)
|
||||
{
|
||||
|
||||
mm->need_space = 0;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void
|
||||
post_pf(DECL_ARGS)
|
||||
{
|
||||
|
||||
mm->need_space = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
pre_pp(DECL_ARGS)
|
||||
{
|
||||
|
||||
mm->need_nl = 1;
|
||||
if (MDOC_It == n->parent->tok)
|
||||
print_word(mm, ".sp");
|
||||
else
|
||||
print_word(mm, ".PP");
|
||||
mm->need_nl = 1;
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int
|
||||
pre_sp(DECL_ARGS)
|
||||
{
|
||||
|
||||
mm->need_nl = 1;
|
||||
print_word(mm, ".sp");
|
||||
return(1);
|
||||
}
|
||||
|
||||
static void
|
||||
post_sp(DECL_ARGS)
|
||||
{
|
||||
|
||||
mm->need_nl = 1;
|
||||
}
|
||||
|
||||
static int
|
||||
pre_xr(DECL_ARGS)
|
||||
{
|
||||
|
||||
n = n->child;
|
||||
if (NULL == n)
|
||||
return(0);
|
||||
print_node(m, n, mm);
|
||||
n = n->next;
|
||||
if (NULL == n)
|
||||
return(0);
|
||||
mm->need_space = 0;
|
||||
print_word(mm, "(");
|
||||
print_node(m, n, mm);
|
||||
print_word(mm, ")");
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
pre_ux(DECL_ARGS)
|
||||
{
|
||||
|
||||
print_word(mm, manacts[n->tok].prefix);
|
||||
if (NULL == n->child)
|
||||
return(0);
|
||||
mm->need_space = 0;
|
||||
print_word(mm, "\\~");
|
||||
mm->need_space = 0;
|
||||
return(1);
|
||||
}
|
2257
contrib/mdocml/mdoc_term.c
Normal file
2257
contrib/mdocml/mdoc_term.c
Normal file
File diff suppressed because it is too large
Load Diff
2403
contrib/mdocml/mdoc_validate.c
Normal file
2403
contrib/mdocml/mdoc_validate.c
Normal file
File diff suppressed because it is too large
Load Diff
37
contrib/mdocml/msec.c
Normal file
37
contrib/mdocml/msec.c
Normal file
@ -0,0 +1,37 @@
|
||||
/* $Id: msec.c,v 1.10 2011/12/02 01:37:14 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "libmandoc.h"
|
||||
|
||||
#define LINE(x, y) \
|
||||
if (0 == strcmp(p, x)) return(y);
|
||||
|
||||
const char *
|
||||
mandoc_a2msec(const char *p)
|
||||
{
|
||||
|
||||
#include "msec.in"
|
||||
|
||||
return(NULL);
|
||||
}
|
40
contrib/mdocml/msec.in
Normal file
40
contrib/mdocml/msec.in
Normal file
@ -0,0 +1,40 @@
|
||||
/* $Id: msec.in,v 1.6 2010/06/19 20:46:28 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* These are all possible manual-section macros and what they correspond
|
||||
* to when rendered as the volume title.
|
||||
*
|
||||
* Be sure to escape strings.
|
||||
*/
|
||||
|
||||
LINE("1", "General Commands Manual")
|
||||
LINE("2", "System Calls Manual")
|
||||
LINE("3", "Library Functions Manual")
|
||||
LINE("3p", "Perl Library Functions Manual")
|
||||
LINE("4", "Kernel Interfaces Manual")
|
||||
LINE("5", "File Formats Manual")
|
||||
LINE("6", "Games Manual")
|
||||
LINE("7", "Miscellaneous Information Manual")
|
||||
LINE("8", "System Manager\'s Manual")
|
||||
LINE("9", "Kernel Developer\'s Manual")
|
||||
LINE("X11", "X11 Developer\'s Manual")
|
||||
LINE("X11R6", "X11 Developer\'s Manual")
|
||||
LINE("unass", "Unassociated")
|
||||
LINE("local", "Local")
|
||||
LINE("draft", "Draft")
|
||||
LINE("paper", "Paper")
|
303
contrib/mdocml/out.c
Normal file
303
contrib/mdocml/out.c
Normal file
@ -0,0 +1,303 @@
|
||||
/* $Id: out.c,v 1.43 2011/09/20 23:05:49 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "out.h"
|
||||
|
||||
static void tblcalc_data(struct rofftbl *, struct roffcol *,
|
||||
const struct tbl *, const struct tbl_dat *);
|
||||
static void tblcalc_literal(struct rofftbl *, struct roffcol *,
|
||||
const struct tbl_dat *);
|
||||
static void tblcalc_number(struct rofftbl *, struct roffcol *,
|
||||
const struct tbl *, const struct tbl_dat *);
|
||||
|
||||
/*
|
||||
* Convert a `scaling unit' to a consistent form, or fail. Scaling
|
||||
* units are documented in groff.7, mdoc.7, man.7.
|
||||
*/
|
||||
int
|
||||
a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
|
||||
{
|
||||
char buf[BUFSIZ], hasd;
|
||||
int i;
|
||||
enum roffscale unit;
|
||||
|
||||
if ('\0' == *src)
|
||||
return(0);
|
||||
|
||||
i = hasd = 0;
|
||||
|
||||
switch (*src) {
|
||||
case ('+'):
|
||||
src++;
|
||||
break;
|
||||
case ('-'):
|
||||
buf[i++] = *src++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ('\0' == *src)
|
||||
return(0);
|
||||
|
||||
while (i < BUFSIZ) {
|
||||
if ( ! isdigit((unsigned char)*src)) {
|
||||
if ('.' != *src)
|
||||
break;
|
||||
else if (hasd)
|
||||
break;
|
||||
else
|
||||
hasd = 1;
|
||||
}
|
||||
buf[i++] = *src++;
|
||||
}
|
||||
|
||||
if (BUFSIZ == i || (*src && *(src + 1)))
|
||||
return(0);
|
||||
|
||||
buf[i] = '\0';
|
||||
|
||||
switch (*src) {
|
||||
case ('c'):
|
||||
unit = SCALE_CM;
|
||||
break;
|
||||
case ('i'):
|
||||
unit = SCALE_IN;
|
||||
break;
|
||||
case ('P'):
|
||||
unit = SCALE_PC;
|
||||
break;
|
||||
case ('p'):
|
||||
unit = SCALE_PT;
|
||||
break;
|
||||
case ('f'):
|
||||
unit = SCALE_FS;
|
||||
break;
|
||||
case ('v'):
|
||||
unit = SCALE_VS;
|
||||
break;
|
||||
case ('m'):
|
||||
unit = SCALE_EM;
|
||||
break;
|
||||
case ('\0'):
|
||||
if (SCALE_MAX == def)
|
||||
return(0);
|
||||
unit = SCALE_BU;
|
||||
break;
|
||||
case ('u'):
|
||||
unit = SCALE_BU;
|
||||
break;
|
||||
case ('M'):
|
||||
unit = SCALE_MM;
|
||||
break;
|
||||
case ('n'):
|
||||
unit = SCALE_EN;
|
||||
break;
|
||||
default:
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* FIXME: do this in the caller. */
|
||||
if ((dst->scale = atof(buf)) < 0)
|
||||
dst->scale = 0;
|
||||
dst->unit = unit;
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the abstract widths and decimal positions of columns in a
|
||||
* table. This routine allocates the columns structures then runs over
|
||||
* all rows and cells in the table. The function pointers in "tbl" are
|
||||
* used for the actual width calculations.
|
||||
*/
|
||||
void
|
||||
tblcalc(struct rofftbl *tbl, const struct tbl_span *sp)
|
||||
{
|
||||
const struct tbl_dat *dp;
|
||||
const struct tbl_head *hp;
|
||||
struct roffcol *col;
|
||||
int spans;
|
||||
|
||||
/*
|
||||
* Allocate the master column specifiers. These will hold the
|
||||
* widths and decimal positions for all cells in the column. It
|
||||
* must be freed and nullified by the caller.
|
||||
*/
|
||||
|
||||
assert(NULL == tbl->cols);
|
||||
tbl->cols = mandoc_calloc
|
||||
((size_t)sp->tbl->cols, sizeof(struct roffcol));
|
||||
|
||||
hp = sp->head;
|
||||
|
||||
for ( ; sp; sp = sp->next) {
|
||||
if (TBL_SPAN_DATA != sp->pos)
|
||||
continue;
|
||||
spans = 1;
|
||||
/*
|
||||
* Account for the data cells in the layout, matching it
|
||||
* to data cells in the data section.
|
||||
*/
|
||||
for (dp = sp->first; dp; dp = dp->next) {
|
||||
/* Do not used spanned cells in the calculation. */
|
||||
if (0 < --spans)
|
||||
continue;
|
||||
spans = dp->spans;
|
||||
if (1 < spans)
|
||||
continue;
|
||||
assert(dp->layout);
|
||||
col = &tbl->cols[dp->layout->head->ident];
|
||||
tblcalc_data(tbl, col, sp->tbl, dp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate width of the spanners. These get one space for a
|
||||
* vertical line, two for a double-vertical line.
|
||||
*/
|
||||
|
||||
for ( ; hp; hp = hp->next) {
|
||||
col = &tbl->cols[hp->ident];
|
||||
switch (hp->pos) {
|
||||
case (TBL_HEAD_VERT):
|
||||
col->width = (*tbl->len)(1, tbl->arg);
|
||||
break;
|
||||
case (TBL_HEAD_DVERT):
|
||||
col->width = (*tbl->len)(2, tbl->arg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
|
||||
const struct tbl *tp, const struct tbl_dat *dp)
|
||||
{
|
||||
size_t sz;
|
||||
|
||||
/* Branch down into data sub-types. */
|
||||
|
||||
switch (dp->layout->pos) {
|
||||
case (TBL_CELL_HORIZ):
|
||||
/* FALLTHROUGH */
|
||||
case (TBL_CELL_DHORIZ):
|
||||
sz = (*tbl->len)(1, tbl->arg);
|
||||
if (col->width < sz)
|
||||
col->width = sz;
|
||||
break;
|
||||
case (TBL_CELL_LONG):
|
||||
/* FALLTHROUGH */
|
||||
case (TBL_CELL_CENTRE):
|
||||
/* FALLTHROUGH */
|
||||
case (TBL_CELL_LEFT):
|
||||
/* FALLTHROUGH */
|
||||
case (TBL_CELL_RIGHT):
|
||||
tblcalc_literal(tbl, col, dp);
|
||||
break;
|
||||
case (TBL_CELL_NUMBER):
|
||||
tblcalc_number(tbl, col, tp, dp);
|
||||
break;
|
||||
case (TBL_CELL_DOWN):
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
|
||||
const struct tbl_dat *dp)
|
||||
{
|
||||
size_t sz;
|
||||
const char *str;
|
||||
|
||||
str = dp->string ? dp->string : "";
|
||||
sz = (*tbl->slen)(str, tbl->arg);
|
||||
|
||||
if (col->width < sz)
|
||||
col->width = sz;
|
||||
}
|
||||
|
||||
static void
|
||||
tblcalc_number(struct rofftbl *tbl, struct roffcol *col,
|
||||
const struct tbl *tp, const struct tbl_dat *dp)
|
||||
{
|
||||
int i;
|
||||
size_t sz, psz, ssz, d;
|
||||
const char *str;
|
||||
char *cp;
|
||||
char buf[2];
|
||||
|
||||
/*
|
||||
* First calculate number width and decimal place (last + 1 for
|
||||
* non-decimal numbers). If the stored decimal is subsequent to
|
||||
* ours, make our size longer by that difference
|
||||
* (right-"shifting"); similarly, if ours is subsequent the
|
||||
* stored, then extend the stored size by the difference.
|
||||
* Finally, re-assign the stored values.
|
||||
*/
|
||||
|
||||
str = dp->string ? dp->string : "";
|
||||
sz = (*tbl->slen)(str, tbl->arg);
|
||||
|
||||
/* FIXME: TBL_DATA_HORIZ et al.? */
|
||||
|
||||
buf[0] = tp->decimal;
|
||||
buf[1] = '\0';
|
||||
|
||||
psz = (*tbl->slen)(buf, tbl->arg);
|
||||
|
||||
if (NULL != (cp = strrchr(str, tp->decimal))) {
|
||||
buf[1] = '\0';
|
||||
for (ssz = 0, i = 0; cp != &str[i]; i++) {
|
||||
buf[0] = str[i];
|
||||
ssz += (*tbl->slen)(buf, tbl->arg);
|
||||
}
|
||||
d = ssz + psz;
|
||||
} else
|
||||
d = sz + psz;
|
||||
|
||||
/* Adjust the settings for this column. */
|
||||
|
||||
if (col->decimal > d) {
|
||||
sz += col->decimal - d;
|
||||
d = col->decimal;
|
||||
} else
|
||||
col->width += d - col->decimal;
|
||||
|
||||
if (sz > col->width)
|
||||
col->width = sz;
|
||||
if (d > col->decimal)
|
||||
col->decimal = d;
|
||||
}
|
71
contrib/mdocml/out.h
Normal file
71
contrib/mdocml/out.h
Normal file
@ -0,0 +1,71 @@
|
||||
/* $Id: out.h,v 1.21 2011/07/17 15:24:25 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 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 OUT_H
|
||||
#define OUT_H
|
||||
|
||||
enum roffscale {
|
||||
SCALE_CM, /* centimeters (c) */
|
||||
SCALE_IN, /* inches (i) */
|
||||
SCALE_PC, /* pica (P) */
|
||||
SCALE_PT, /* points (p) */
|
||||
SCALE_EM, /* ems (m) */
|
||||
SCALE_MM, /* mini-ems (M) */
|
||||
SCALE_EN, /* ens (n) */
|
||||
SCALE_BU, /* default horizontal (u) */
|
||||
SCALE_VS, /* default vertical (v) */
|
||||
SCALE_FS, /* syn. for u (f) */
|
||||
SCALE_MAX
|
||||
};
|
||||
|
||||
struct roffcol {
|
||||
size_t width; /* width of cell */
|
||||
size_t decimal; /* decimal position in cell */
|
||||
};
|
||||
|
||||
struct roffsu {
|
||||
enum roffscale unit;
|
||||
double scale;
|
||||
};
|
||||
|
||||
typedef size_t (*tbl_strlen)(const char *, void *);
|
||||
typedef size_t (*tbl_len)(size_t, void *);
|
||||
|
||||
struct rofftbl {
|
||||
tbl_strlen slen; /* calculate string length */
|
||||
tbl_len len; /* produce width of empty space */
|
||||
struct roffcol *cols; /* master column specifiers */
|
||||
void *arg; /* passed to slen and len */
|
||||
};
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define SCALE_VS_INIT(p, v) \
|
||||
do { (p)->unit = SCALE_VS; \
|
||||
(p)->scale = (v); } \
|
||||
while (/* CONSTCOND */ 0)
|
||||
|
||||
#define SCALE_HS_INIT(p, v) \
|
||||
do { (p)->unit = SCALE_BU; \
|
||||
(p)->scale = (v); } \
|
||||
while (/* CONSTCOND */ 0)
|
||||
|
||||
int a2roffsu(const char *, struct roffsu *, enum roffscale);
|
||||
void tblcalc(struct rofftbl *tbl, const struct tbl_span *);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /*!OUT_H*/
|
65
contrib/mdocml/predefs.in
Normal file
65
contrib/mdocml/predefs.in
Normal file
@ -0,0 +1,65 @@
|
||||
/* $Id: predefs.in,v 1.3 2011/07/31 11:36:49 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The predefined-string translation tables. Each corresponds to a
|
||||
* predefined strings from (e.g.) tmac/mdoc/doc-nroff. The left-hand
|
||||
* side corresponds to the input sequence (\*x, \*(xx and so on). The
|
||||
* right-hand side is what's produced by libroff.
|
||||
*
|
||||
* XXX - C-escape strings!
|
||||
* XXX - update PREDEF_MAX in roff.c if adding more!
|
||||
*/
|
||||
|
||||
PREDEF("Am", "&")
|
||||
PREDEF("Ba", "|")
|
||||
PREDEF("Ge", "\\(>=")
|
||||
PREDEF("Gt", ">")
|
||||
PREDEF("If", "infinity")
|
||||
PREDEF("Le", "\\(<=")
|
||||
PREDEF("Lq", "\\(lq")
|
||||
PREDEF("Lt", "<")
|
||||
PREDEF("Na", "NaN")
|
||||
PREDEF("Ne", "\\(!=")
|
||||
PREDEF("Pi", "pi")
|
||||
PREDEF("Pm", "\\(+-")
|
||||
PREDEF("Rq", "\\(rq")
|
||||
PREDEF("left-bracket", "[")
|
||||
PREDEF("left-parenthesis", "(")
|
||||
PREDEF("lp", "(")
|
||||
PREDEF("left-singlequote", "\\(oq")
|
||||
PREDEF("q", "\\(dq")
|
||||
PREDEF("quote-left", "\\(oq")
|
||||
PREDEF("quote-right", "\\(cq")
|
||||
PREDEF("R", "\\(rg")
|
||||
PREDEF("right-bracket", "]")
|
||||
PREDEF("right-parenthesis", ")")
|
||||
PREDEF("rp", ")")
|
||||
PREDEF("right-singlequote", "\\(cq")
|
||||
PREDEF("Tm", "(Tm)")
|
||||
PREDEF("Px", "POSIX")
|
||||
PREDEF("Ai", "ANSI")
|
||||
PREDEF("\'", "\\\'")
|
||||
PREDEF("aa", "\\(aa")
|
||||
PREDEF("ga", "\\(ga")
|
||||
PREDEF("`", "\\`")
|
||||
PREDEF("lq", "\\(lq")
|
||||
PREDEF("rq", "\\(rq")
|
||||
PREDEF("ua", "\\(ua")
|
||||
PREDEF("va", "\\(va")
|
||||
PREDEF("<=", "\\(<=")
|
||||
PREDEF(">=", "\\(>=")
|
846
contrib/mdocml/read.c
Normal file
846
contrib/mdocml/read.c
Normal file
@ -0,0 +1,846 @@
|
||||
/* $Id: read.c,v 1.28 2012/02/16 20:51:31 joerg Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2010, 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
# include <sys/stat.h>
|
||||
# include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "libmandoc.h"
|
||||
#include "mdoc.h"
|
||||
#include "man.h"
|
||||
#include "main.h"
|
||||
|
||||
#ifndef MAP_FILE
|
||||
#define MAP_FILE 0
|
||||
#endif
|
||||
|
||||
#define REPARSE_LIMIT 1000
|
||||
|
||||
struct buf {
|
||||
char *buf; /* binary input buffer */
|
||||
size_t sz; /* size of binary buffer */
|
||||
};
|
||||
|
||||
struct mparse {
|
||||
enum mandoclevel file_status; /* status of current parse */
|
||||
enum mandoclevel wlevel; /* ignore messages below this */
|
||||
int line; /* line number in the file */
|
||||
enum mparset inttype; /* which parser to use */
|
||||
struct man *pman; /* persistent man parser */
|
||||
struct mdoc *pmdoc; /* persistent mdoc parser */
|
||||
struct man *man; /* man parser */
|
||||
struct mdoc *mdoc; /* mdoc parser */
|
||||
struct roff *roff; /* roff parser (!NULL) */
|
||||
int reparse_count; /* finite interp. stack */
|
||||
mandocmsg mmsg; /* warning/error message handler */
|
||||
void *arg; /* argument to mmsg */
|
||||
const char *file;
|
||||
struct buf *secondary;
|
||||
};
|
||||
|
||||
static void resize_buf(struct buf *, size_t);
|
||||
static void mparse_buf_r(struct mparse *, struct buf, int);
|
||||
static void mparse_readfd_r(struct mparse *, int, const char *, int);
|
||||
static void pset(const char *, int, struct mparse *);
|
||||
static int read_whole_file(const char *, int, struct buf *, int *);
|
||||
static void mparse_end(struct mparse *);
|
||||
|
||||
static const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = {
|
||||
MANDOCERR_OK,
|
||||
MANDOCERR_WARNING,
|
||||
MANDOCERR_WARNING,
|
||||
MANDOCERR_ERROR,
|
||||
MANDOCERR_FATAL,
|
||||
MANDOCERR_MAX,
|
||||
MANDOCERR_MAX
|
||||
};
|
||||
|
||||
static const char * const mandocerrs[MANDOCERR_MAX] = {
|
||||
"ok",
|
||||
|
||||
"generic warning",
|
||||
|
||||
/* related to the prologue */
|
||||
"no title in document",
|
||||
"document title should be all caps",
|
||||
"unknown manual section",
|
||||
"date missing, using today's date",
|
||||
"cannot parse date, using it verbatim",
|
||||
"prologue macros out of order",
|
||||
"duplicate prologue macro",
|
||||
"macro not allowed in prologue",
|
||||
"macro not allowed in body",
|
||||
|
||||
/* related to document structure */
|
||||
".so is fragile, better use ln(1)",
|
||||
"NAME section must come first",
|
||||
"bad NAME section contents",
|
||||
"manual name not yet set",
|
||||
"sections out of conventional order",
|
||||
"duplicate section name",
|
||||
"section not in conventional manual section",
|
||||
|
||||
/* related to macros and nesting */
|
||||
"skipping obsolete macro",
|
||||
"skipping paragraph macro",
|
||||
"skipping no-space macro",
|
||||
"blocks badly nested",
|
||||
"child violates parent syntax",
|
||||
"nested displays are not portable",
|
||||
"already in literal mode",
|
||||
"line scope broken",
|
||||
|
||||
/* related to missing macro arguments */
|
||||
"skipping empty macro",
|
||||
"argument count wrong",
|
||||
"missing display type",
|
||||
"list type must come first",
|
||||
"tag lists require a width argument",
|
||||
"missing font type",
|
||||
"skipping end of block that is not open",
|
||||
|
||||
/* related to bad macro arguments */
|
||||
"skipping argument",
|
||||
"duplicate argument",
|
||||
"duplicate display type",
|
||||
"duplicate list type",
|
||||
"unknown AT&T UNIX version",
|
||||
"bad Boolean value",
|
||||
"unknown font",
|
||||
"unknown standard specifier",
|
||||
"bad width argument",
|
||||
|
||||
/* related to plain text */
|
||||
"blank line in non-literal context",
|
||||
"tab in non-literal context",
|
||||
"end of line whitespace",
|
||||
"bad comment style",
|
||||
"bad escape sequence",
|
||||
"unterminated quoted string",
|
||||
|
||||
/* related to equations */
|
||||
"unexpected literal in equation",
|
||||
|
||||
"generic error",
|
||||
|
||||
/* related to equations */
|
||||
"unexpected equation scope closure",
|
||||
"equation scope open on exit",
|
||||
"overlapping equation scopes",
|
||||
"unexpected end of equation",
|
||||
"equation syntax error",
|
||||
|
||||
/* related to tables */
|
||||
"bad table syntax",
|
||||
"bad table option",
|
||||
"bad table layout",
|
||||
"no table layout cells specified",
|
||||
"no table data cells specified",
|
||||
"ignore data in cell",
|
||||
"data block still open",
|
||||
"ignoring extra data cells",
|
||||
|
||||
"input stack limit exceeded, infinite loop?",
|
||||
"skipping bad character",
|
||||
"escaped character not allowed in a name",
|
||||
"skipping text before the first section header",
|
||||
"skipping unknown macro",
|
||||
"NOT IMPLEMENTED, please use groff: skipping request",
|
||||
"argument count wrong",
|
||||
"skipping end of block that is not open",
|
||||
"missing end of block",
|
||||
"scope open on exit",
|
||||
"uname(3) system call failed",
|
||||
"macro requires line argument(s)",
|
||||
"macro requires body argument(s)",
|
||||
"macro requires argument(s)",
|
||||
"missing list type",
|
||||
"line argument(s) will be lost",
|
||||
"body argument(s) will be lost",
|
||||
|
||||
"generic fatal error",
|
||||
|
||||
"not a manual",
|
||||
"column syntax is inconsistent",
|
||||
"NOT IMPLEMENTED: .Bd -file",
|
||||
"argument count wrong, violates syntax",
|
||||
"child violates parent syntax",
|
||||
"argument count wrong, violates syntax",
|
||||
"NOT IMPLEMENTED: .so with absolute path or \"..\"",
|
||||
"no document body",
|
||||
"no document prologue",
|
||||
"static buffer exhausted",
|
||||
};
|
||||
|
||||
static const char * const mandoclevels[MANDOCLEVEL_MAX] = {
|
||||
"SUCCESS",
|
||||
"RESERVED",
|
||||
"WARNING",
|
||||
"ERROR",
|
||||
"FATAL",
|
||||
"BADARG",
|
||||
"SYSERR"
|
||||
};
|
||||
|
||||
static void
|
||||
resize_buf(struct buf *buf, size_t initial)
|
||||
{
|
||||
|
||||
buf->sz = buf->sz > initial/2 ? 2 * buf->sz : initial;
|
||||
buf->buf = mandoc_realloc(buf->buf, buf->sz);
|
||||
}
|
||||
|
||||
static void
|
||||
pset(const char *buf, int pos, struct mparse *curp)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Try to intuit which kind of manual parser should be used. If
|
||||
* passed in by command-line (-man, -mdoc), then use that
|
||||
* explicitly. If passed as -mandoc, then try to guess from the
|
||||
* line: either skip dot-lines, use -mdoc when finding `.Dt', or
|
||||
* default to -man, which is more lenient.
|
||||
*
|
||||
* Separate out pmdoc/pman from mdoc/man: the first persists
|
||||
* through all parsers, while the latter is used per-parse.
|
||||
*/
|
||||
|
||||
if ('.' == buf[0] || '\'' == buf[0]) {
|
||||
for (i = 1; buf[i]; i++)
|
||||
if (' ' != buf[i] && '\t' != buf[i])
|
||||
break;
|
||||
if ('\0' == buf[i])
|
||||
return;
|
||||
}
|
||||
|
||||
switch (curp->inttype) {
|
||||
case (MPARSE_MDOC):
|
||||
if (NULL == curp->pmdoc)
|
||||
curp->pmdoc = mdoc_alloc(curp->roff, curp);
|
||||
assert(curp->pmdoc);
|
||||
curp->mdoc = curp->pmdoc;
|
||||
return;
|
||||
case (MPARSE_MAN):
|
||||
if (NULL == curp->pman)
|
||||
curp->pman = man_alloc(curp->roff, curp);
|
||||
assert(curp->pman);
|
||||
curp->man = curp->pman;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3)) {
|
||||
if (NULL == curp->pmdoc)
|
||||
curp->pmdoc = mdoc_alloc(curp->roff, curp);
|
||||
assert(curp->pmdoc);
|
||||
curp->mdoc = curp->pmdoc;
|
||||
return;
|
||||
}
|
||||
|
||||
if (NULL == curp->pman)
|
||||
curp->pman = man_alloc(curp->roff, curp);
|
||||
assert(curp->pman);
|
||||
curp->man = curp->pman;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main parse routine for an opened file. This is called for each
|
||||
* opened file and simply loops around the full input file, possibly
|
||||
* nesting (i.e., with `so').
|
||||
*/
|
||||
static void
|
||||
mparse_buf_r(struct mparse *curp, struct buf blk, int start)
|
||||
{
|
||||
const struct tbl_span *span;
|
||||
struct buf ln;
|
||||
enum rofferr rr;
|
||||
int i, of, rc;
|
||||
int pos; /* byte number in the ln buffer */
|
||||
int lnn; /* line number in the real file */
|
||||
unsigned char c;
|
||||
|
||||
memset(&ln, 0, sizeof(struct buf));
|
||||
|
||||
lnn = curp->line;
|
||||
pos = 0;
|
||||
|
||||
for (i = 0; i < (int)blk.sz; ) {
|
||||
if (0 == pos && '\0' == blk.buf[i])
|
||||
break;
|
||||
|
||||
if (start) {
|
||||
curp->line = lnn;
|
||||
curp->reparse_count = 0;
|
||||
}
|
||||
|
||||
while (i < (int)blk.sz && (start || '\0' != blk.buf[i])) {
|
||||
|
||||
/*
|
||||
* When finding an unescaped newline character,
|
||||
* leave the character loop to process the line.
|
||||
* Skip a preceding carriage return, if any.
|
||||
*/
|
||||
|
||||
if ('\r' == blk.buf[i] && i + 1 < (int)blk.sz &&
|
||||
'\n' == blk.buf[i + 1])
|
||||
++i;
|
||||
if ('\n' == blk.buf[i]) {
|
||||
++i;
|
||||
++lnn;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Warn about bogus characters. If you're using
|
||||
* non-ASCII encoding, you're screwing your
|
||||
* readers. Since I'd rather this not happen,
|
||||
* I'll be helpful and replace these characters
|
||||
* with "?", so we don't display gibberish.
|
||||
* Note to manual writers: use special characters.
|
||||
*/
|
||||
|
||||
c = (unsigned char) blk.buf[i];
|
||||
|
||||
if ( ! (isascii(c) &&
|
||||
(isgraph(c) || isblank(c)))) {
|
||||
mandoc_msg(MANDOCERR_BADCHAR, curp,
|
||||
curp->line, pos, NULL);
|
||||
i++;
|
||||
if (pos >= (int)ln.sz)
|
||||
resize_buf(&ln, 256);
|
||||
ln.buf[pos++] = '?';
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Trailing backslash = a plain char. */
|
||||
|
||||
if ('\\' != blk.buf[i] || i + 1 == (int)blk.sz) {
|
||||
if (pos >= (int)ln.sz)
|
||||
resize_buf(&ln, 256);
|
||||
ln.buf[pos++] = blk.buf[i++];
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Found escape and at least one other character.
|
||||
* When it's a newline character, skip it.
|
||||
* When there is a carriage return in between,
|
||||
* skip that one as well.
|
||||
*/
|
||||
|
||||
if ('\r' == blk.buf[i + 1] && i + 2 < (int)blk.sz &&
|
||||
'\n' == blk.buf[i + 2])
|
||||
++i;
|
||||
if ('\n' == blk.buf[i + 1]) {
|
||||
i += 2;
|
||||
++lnn;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ('"' == blk.buf[i + 1] || '#' == blk.buf[i + 1]) {
|
||||
i += 2;
|
||||
/* Comment, skip to end of line */
|
||||
for (; i < (int)blk.sz; ++i) {
|
||||
if ('\n' == blk.buf[i]) {
|
||||
++i;
|
||||
++lnn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Backout trailing whitespaces */
|
||||
for (; pos > 0; --pos) {
|
||||
if (ln.buf[pos - 1] != ' ')
|
||||
break;
|
||||
if (pos > 2 && ln.buf[pos - 2] == '\\')
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Some other escape sequence, copy & cont. */
|
||||
|
||||
if (pos + 1 >= (int)ln.sz)
|
||||
resize_buf(&ln, 256);
|
||||
|
||||
ln.buf[pos++] = blk.buf[i++];
|
||||
ln.buf[pos++] = blk.buf[i++];
|
||||
}
|
||||
|
||||
if (pos >= (int)ln.sz)
|
||||
resize_buf(&ln, 256);
|
||||
|
||||
ln.buf[pos] = '\0';
|
||||
|
||||
/*
|
||||
* A significant amount of complexity is contained by
|
||||
* the roff preprocessor. It's line-oriented but can be
|
||||
* expressed on one line, so we need at times to
|
||||
* readjust our starting point and re-run it. The roff
|
||||
* preprocessor can also readjust the buffers with new
|
||||
* data, so we pass them in wholesale.
|
||||
*/
|
||||
|
||||
of = 0;
|
||||
|
||||
/*
|
||||
* Maintain a lookaside buffer of all parsed lines. We
|
||||
* only do this if mparse_keep() has been invoked (the
|
||||
* buffer may be accessed with mparse_getkeep()).
|
||||
*/
|
||||
|
||||
if (curp->secondary) {
|
||||
curp->secondary->buf =
|
||||
mandoc_realloc
|
||||
(curp->secondary->buf,
|
||||
curp->secondary->sz + pos + 2);
|
||||
memcpy(curp->secondary->buf +
|
||||
curp->secondary->sz,
|
||||
ln.buf, pos);
|
||||
curp->secondary->sz += pos;
|
||||
curp->secondary->buf
|
||||
[curp->secondary->sz] = '\n';
|
||||
curp->secondary->sz++;
|
||||
curp->secondary->buf
|
||||
[curp->secondary->sz] = '\0';
|
||||
}
|
||||
rerun:
|
||||
rr = roff_parseln
|
||||
(curp->roff, curp->line,
|
||||
&ln.buf, &ln.sz, of, &of);
|
||||
|
||||
switch (rr) {
|
||||
case (ROFF_REPARSE):
|
||||
if (REPARSE_LIMIT >= ++curp->reparse_count)
|
||||
mparse_buf_r(curp, ln, 0);
|
||||
else
|
||||
mandoc_msg(MANDOCERR_ROFFLOOP, curp,
|
||||
curp->line, pos, NULL);
|
||||
pos = 0;
|
||||
continue;
|
||||
case (ROFF_APPEND):
|
||||
pos = (int)strlen(ln.buf);
|
||||
continue;
|
||||
case (ROFF_RERUN):
|
||||
goto rerun;
|
||||
case (ROFF_IGN):
|
||||
pos = 0;
|
||||
continue;
|
||||
case (ROFF_ERR):
|
||||
assert(MANDOCLEVEL_FATAL <= curp->file_status);
|
||||
break;
|
||||
case (ROFF_SO):
|
||||
/*
|
||||
* We remove `so' clauses from our lookaside
|
||||
* buffer because we're going to descend into
|
||||
* the file recursively.
|
||||
*/
|
||||
if (curp->secondary)
|
||||
curp->secondary->sz -= pos + 1;
|
||||
mparse_readfd_r(curp, -1, ln.buf + of, 1);
|
||||
if (MANDOCLEVEL_FATAL <= curp->file_status)
|
||||
break;
|
||||
pos = 0;
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we encounter errors in the recursive parse, make
|
||||
* sure we don't continue parsing.
|
||||
*/
|
||||
|
||||
if (MANDOCLEVEL_FATAL <= curp->file_status)
|
||||
break;
|
||||
|
||||
/*
|
||||
* If input parsers have not been allocated, do so now.
|
||||
* We keep these instanced between parsers, but set them
|
||||
* locally per parse routine since we can use different
|
||||
* parsers with each one.
|
||||
*/
|
||||
|
||||
if ( ! (curp->man || curp->mdoc))
|
||||
pset(ln.buf + of, pos - of, curp);
|
||||
|
||||
/*
|
||||
* Lastly, push down into the parsers themselves. One
|
||||
* of these will have already been set in the pset()
|
||||
* routine.
|
||||
* If libroff returns ROFF_TBL, then add it to the
|
||||
* currently open parse. Since we only get here if
|
||||
* there does exist data (see tbl_data.c), we're
|
||||
* guaranteed that something's been allocated.
|
||||
* Do the same for ROFF_EQN.
|
||||
*/
|
||||
|
||||
rc = -1;
|
||||
|
||||
if (ROFF_TBL == rr)
|
||||
while (NULL != (span = roff_span(curp->roff))) {
|
||||
rc = curp->man ?
|
||||
man_addspan(curp->man, span) :
|
||||
mdoc_addspan(curp->mdoc, span);
|
||||
if (0 == rc)
|
||||
break;
|
||||
}
|
||||
else if (ROFF_EQN == rr)
|
||||
rc = curp->mdoc ?
|
||||
mdoc_addeqn(curp->mdoc,
|
||||
roff_eqn(curp->roff)) :
|
||||
man_addeqn(curp->man,
|
||||
roff_eqn(curp->roff));
|
||||
else if (curp->man || curp->mdoc)
|
||||
rc = curp->man ?
|
||||
man_parseln(curp->man,
|
||||
curp->line, ln.buf, of) :
|
||||
mdoc_parseln(curp->mdoc,
|
||||
curp->line, ln.buf, of);
|
||||
|
||||
if (0 == rc) {
|
||||
assert(MANDOCLEVEL_FATAL <= curp->file_status);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Temporary buffers typically are not full. */
|
||||
|
||||
if (0 == start && '\0' == blk.buf[i])
|
||||
break;
|
||||
|
||||
/* Start the next input line. */
|
||||
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
free(ln.buf);
|
||||
}
|
||||
|
||||
static int
|
||||
read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
|
||||
{
|
||||
size_t off;
|
||||
ssize_t ssz;
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
struct stat st;
|
||||
if (-1 == fstat(fd, &st)) {
|
||||
perror(file);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're a regular file, try just reading in the whole entry
|
||||
* via mmap(). This is faster than reading it into blocks, and
|
||||
* since each file is only a few bytes to begin with, I'm not
|
||||
* concerned that this is going to tank any machines.
|
||||
*/
|
||||
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
if (st.st_size >= (1U << 31)) {
|
||||
fprintf(stderr, "%s: input too large\n", file);
|
||||
return(0);
|
||||
}
|
||||
*with_mmap = 1;
|
||||
fb->sz = (size_t)st.st_size;
|
||||
fb->buf = mmap(NULL, fb->sz, PROT_READ,
|
||||
MAP_FILE|MAP_SHARED, fd, 0);
|
||||
if (fb->buf != MAP_FAILED)
|
||||
return(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If this isn't a regular file (like, say, stdin), then we must
|
||||
* go the old way and just read things in bit by bit.
|
||||
*/
|
||||
|
||||
*with_mmap = 0;
|
||||
off = 0;
|
||||
fb->sz = 0;
|
||||
fb->buf = NULL;
|
||||
for (;;) {
|
||||
if (off == fb->sz) {
|
||||
if (fb->sz == (1U << 31)) {
|
||||
fprintf(stderr, "%s: input too large\n", file);
|
||||
break;
|
||||
}
|
||||
resize_buf(fb, 65536);
|
||||
}
|
||||
ssz = read(fd, fb->buf + (int)off, fb->sz - off);
|
||||
if (ssz == 0) {
|
||||
fb->sz = off;
|
||||
return(1);
|
||||
}
|
||||
if (ssz == -1) {
|
||||
perror(file);
|
||||
break;
|
||||
}
|
||||
off += (size_t)ssz;
|
||||
}
|
||||
|
||||
free(fb->buf);
|
||||
fb->buf = NULL;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void
|
||||
mparse_end(struct mparse *curp)
|
||||
{
|
||||
|
||||
if (MANDOCLEVEL_FATAL <= curp->file_status)
|
||||
return;
|
||||
|
||||
if (curp->mdoc && ! mdoc_endparse(curp->mdoc)) {
|
||||
assert(MANDOCLEVEL_FATAL <= curp->file_status);
|
||||
return;
|
||||
}
|
||||
|
||||
if (curp->man && ! man_endparse(curp->man)) {
|
||||
assert(MANDOCLEVEL_FATAL <= curp->file_status);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! (curp->man || curp->mdoc)) {
|
||||
mandoc_msg(MANDOCERR_NOTMANUAL, curp, 1, 0, NULL);
|
||||
curp->file_status = MANDOCLEVEL_FATAL;
|
||||
return;
|
||||
}
|
||||
|
||||
roff_endparse(curp->roff);
|
||||
}
|
||||
|
||||
static void
|
||||
mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file,
|
||||
int re)
|
||||
{
|
||||
const char *svfile;
|
||||
|
||||
/* Line number is per-file. */
|
||||
svfile = curp->file;
|
||||
curp->file = file;
|
||||
curp->line = 1;
|
||||
|
||||
mparse_buf_r(curp, blk, 1);
|
||||
|
||||
if (0 == re && MANDOCLEVEL_FATAL > curp->file_status)
|
||||
mparse_end(curp);
|
||||
|
||||
curp->file = svfile;
|
||||
}
|
||||
|
||||
enum mandoclevel
|
||||
mparse_readmem(struct mparse *curp, const void *buf, size_t len,
|
||||
const char *file)
|
||||
{
|
||||
struct buf blk;
|
||||
|
||||
blk.buf = UNCONST(buf);
|
||||
blk.sz = len;
|
||||
|
||||
mparse_parse_buffer(curp, blk, file, 0);
|
||||
return(curp->file_status);
|
||||
}
|
||||
|
||||
static void
|
||||
mparse_readfd_r(struct mparse *curp, int fd, const char *file, int re)
|
||||
{
|
||||
struct buf blk;
|
||||
int with_mmap;
|
||||
|
||||
if (-1 == fd)
|
||||
if (-1 == (fd = open(file, O_RDONLY, 0))) {
|
||||
perror(file);
|
||||
curp->file_status = MANDOCLEVEL_SYSERR;
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Run for each opened file; may be called more than once for
|
||||
* each full parse sequence if the opened file is nested (i.e.,
|
||||
* from `so'). Simply sucks in the whole file and moves into
|
||||
* the parse phase for the file.
|
||||
*/
|
||||
|
||||
if ( ! read_whole_file(file, fd, &blk, &with_mmap)) {
|
||||
curp->file_status = MANDOCLEVEL_SYSERR;
|
||||
return;
|
||||
}
|
||||
|
||||
mparse_parse_buffer(curp, blk, file, re);
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
if (with_mmap)
|
||||
munmap(blk.buf, blk.sz);
|
||||
else
|
||||
#endif
|
||||
free(blk.buf);
|
||||
|
||||
if (STDIN_FILENO != fd && -1 == close(fd))
|
||||
perror(file);
|
||||
}
|
||||
|
||||
enum mandoclevel
|
||||
mparse_readfd(struct mparse *curp, int fd, const char *file)
|
||||
{
|
||||
|
||||
mparse_readfd_r(curp, fd, file, 0);
|
||||
return(curp->file_status);
|
||||
}
|
||||
|
||||
struct mparse *
|
||||
mparse_alloc(enum mparset inttype, enum mandoclevel wlevel, mandocmsg mmsg, void *arg)
|
||||
{
|
||||
struct mparse *curp;
|
||||
|
||||
assert(wlevel <= MANDOCLEVEL_FATAL);
|
||||
|
||||
curp = mandoc_calloc(1, sizeof(struct mparse));
|
||||
|
||||
curp->wlevel = wlevel;
|
||||
curp->mmsg = mmsg;
|
||||
curp->arg = arg;
|
||||
curp->inttype = inttype;
|
||||
|
||||
curp->roff = roff_alloc(curp);
|
||||
return(curp);
|
||||
}
|
||||
|
||||
void
|
||||
mparse_reset(struct mparse *curp)
|
||||
{
|
||||
|
||||
roff_reset(curp->roff);
|
||||
|
||||
if (curp->mdoc)
|
||||
mdoc_reset(curp->mdoc);
|
||||
if (curp->man)
|
||||
man_reset(curp->man);
|
||||
if (curp->secondary)
|
||||
curp->secondary->sz = 0;
|
||||
|
||||
curp->file_status = MANDOCLEVEL_OK;
|
||||
curp->mdoc = NULL;
|
||||
curp->man = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
mparse_free(struct mparse *curp)
|
||||
{
|
||||
|
||||
if (curp->pmdoc)
|
||||
mdoc_free(curp->pmdoc);
|
||||
if (curp->pman)
|
||||
man_free(curp->pman);
|
||||
if (curp->roff)
|
||||
roff_free(curp->roff);
|
||||
if (curp->secondary)
|
||||
free(curp->secondary->buf);
|
||||
|
||||
free(curp->secondary);
|
||||
free(curp);
|
||||
}
|
||||
|
||||
void
|
||||
mparse_result(struct mparse *curp, struct mdoc **mdoc, struct man **man)
|
||||
{
|
||||
|
||||
if (mdoc)
|
||||
*mdoc = curp->mdoc;
|
||||
if (man)
|
||||
*man = curp->man;
|
||||
}
|
||||
|
||||
void
|
||||
mandoc_vmsg(enum mandocerr t, struct mparse *m,
|
||||
int ln, int pos, const char *fmt, ...)
|
||||
{
|
||||
char buf[256];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
mandoc_msg(t, m, ln, pos, buf);
|
||||
}
|
||||
|
||||
void
|
||||
mandoc_msg(enum mandocerr er, struct mparse *m,
|
||||
int ln, int col, const char *msg)
|
||||
{
|
||||
enum mandoclevel level;
|
||||
|
||||
level = MANDOCLEVEL_FATAL;
|
||||
while (er < mandoclimits[level])
|
||||
level--;
|
||||
|
||||
if (level < m->wlevel)
|
||||
return;
|
||||
|
||||
if (m->mmsg)
|
||||
(*m->mmsg)(er, level, m->file, ln, col, msg);
|
||||
|
||||
if (m->file_status < level)
|
||||
m->file_status = level;
|
||||
}
|
||||
|
||||
const char *
|
||||
mparse_strerror(enum mandocerr er)
|
||||
{
|
||||
|
||||
return(mandocerrs[er]);
|
||||
}
|
||||
|
||||
const char *
|
||||
mparse_strlevel(enum mandoclevel lvl)
|
||||
{
|
||||
return(mandoclevels[lvl]);
|
||||
}
|
||||
|
||||
void
|
||||
mparse_keep(struct mparse *p)
|
||||
{
|
||||
|
||||
assert(NULL == p->secondary);
|
||||
p->secondary = mandoc_calloc(1, sizeof(struct buf));
|
||||
}
|
||||
|
||||
const char *
|
||||
mparse_getkeep(const struct mparse *p)
|
||||
{
|
||||
|
||||
assert(p->secondary);
|
||||
return(p->secondary->sz ? p->secondary->buf : NULL);
|
||||
}
|
989
contrib/mdocml/roff.7
Normal file
989
contrib/mdocml/roff.7
Normal file
@ -0,0 +1,989 @@
|
||||
.\" $Id: roff.7,v 1.37 2011/12/11 00:38:11 schwarze Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
.\" Copyright (c) 2010, 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.
|
||||
.\"
|
||||
.Dd $Mdocdate: December 11 2011 $
|
||||
.Dt ROFF 7
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm roff
|
||||
.Nd roff language reference for mandoc
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm roff
|
||||
language is a general purpose text formatting language.
|
||||
Since traditional implementations of the
|
||||
.Xr mdoc 7
|
||||
and
|
||||
.Xr man 7
|
||||
manual formatting languages are based on it,
|
||||
many real-world manuals use small numbers of
|
||||
.Nm
|
||||
requests intermixed with their
|
||||
.Xr mdoc 7
|
||||
or
|
||||
.Xr man 7
|
||||
code.
|
||||
To properly format such manuals, the
|
||||
.Xr mandoc 1
|
||||
utility supports a tiny subset of
|
||||
.Nm
|
||||
requests.
|
||||
Only these requests supported by
|
||||
.Xr mandoc 1
|
||||
are documented in the present manual,
|
||||
together with the basic language syntax shared by
|
||||
.Nm ,
|
||||
.Xr mdoc 7 ,
|
||||
and
|
||||
.Xr man 7 .
|
||||
For complete
|
||||
.Nm
|
||||
manuals, consult the
|
||||
.Sx SEE ALSO
|
||||
section.
|
||||
.Pp
|
||||
Input lines beginning with the control character
|
||||
.Sq \&.
|
||||
are parsed for requests and macros.
|
||||
Such lines are called
|
||||
.Dq request lines
|
||||
or
|
||||
.Dq macro lines ,
|
||||
respectively.
|
||||
Requests change the processing state and manipulate the formatting;
|
||||
some macros also define the document structure and produce formatted
|
||||
output.
|
||||
The single quote
|
||||
.Pq Qq \(aq
|
||||
is accepted as an alternative control character,
|
||||
treated by
|
||||
.Xr mandoc 1
|
||||
just like
|
||||
.Ql \&.
|
||||
.Pp
|
||||
Lines not beginning with control characters are called
|
||||
.Dq text lines .
|
||||
They provide free-form text to be printed; the formatting of the text
|
||||
depends on the respective processing context.
|
||||
.Sh LANGUAGE SYNTAX
|
||||
.Nm
|
||||
documents may contain only graphable 7-bit ASCII characters, the space
|
||||
character, and, in certain circumstances, the tab character.
|
||||
The back-space character
|
||||
.Sq \e
|
||||
indicates the start of an escape sequence for
|
||||
.Sx Comments ,
|
||||
.Sx Special Characters ,
|
||||
.Sx Predefined Strings ,
|
||||
and
|
||||
user-defined strings defined using the
|
||||
.Sx ds
|
||||
request.
|
||||
.Ss Comments
|
||||
Text following an escaped double-quote
|
||||
.Sq \e\(dq ,
|
||||
whether in a request, macro, or text line, is ignored to the end of the line.
|
||||
A request line beginning with a control character and comment escape
|
||||
.Sq \&.\e\(dq
|
||||
is also ignored.
|
||||
Furthermore, request lines with only a control character and optional
|
||||
trailing whitespace are stripped from input.
|
||||
.Pp
|
||||
Examples:
|
||||
.Bd -literal -offset indent -compact
|
||||
\&.\e\(dq This is a comment line.
|
||||
\&.\e\(dq The next line is ignored:
|
||||
\&.
|
||||
\&.Sh EXAMPLES \e\(dq This is a comment, too.
|
||||
\&example text \e\(dq And so is this.
|
||||
.Ed
|
||||
.Ss Special Characters
|
||||
Special characters are used to encode special glyphs and are rendered
|
||||
differently across output media.
|
||||
They may occur in request, macro, and text lines.
|
||||
Sequences begin with the escape character
|
||||
.Sq \e
|
||||
followed by either an open-parenthesis
|
||||
.Sq \&(
|
||||
for two-character sequences; an open-bracket
|
||||
.Sq \&[
|
||||
for n-character sequences (terminated at a close-bracket
|
||||
.Sq \&] ) ;
|
||||
or a single one character sequence.
|
||||
.Pp
|
||||
Examples:
|
||||
.Bl -tag -width Ds -offset indent -compact
|
||||
.It Li \e(em
|
||||
Two-letter em dash escape.
|
||||
.It Li \ee
|
||||
One-letter backslash escape.
|
||||
.El
|
||||
.Pp
|
||||
See
|
||||
.Xr mandoc_char 7
|
||||
for a complete list.
|
||||
.Ss Text Decoration
|
||||
Terms may be text-decorated using the
|
||||
.Sq \ef
|
||||
escape followed by an indicator: B (bold), I (italic), R (regular), or P
|
||||
(revert to previous mode).
|
||||
A numerical representation 3, 2, or 1 (bold, italic, and regular,
|
||||
respectively) may be used instead.
|
||||
The indicator or numerical representative may be preceded by C
|
||||
(constant-width), which is ignored.
|
||||
.Pp
|
||||
Examples:
|
||||
.Bl -tag -width Ds -offset indent -compact
|
||||
.It Li \efBbold\efR
|
||||
Write in bold, then switch to regular font mode.
|
||||
.It Li \efIitalic\efP
|
||||
Write in italic, then return to previous font mode.
|
||||
.El
|
||||
.Pp
|
||||
Text decoration is
|
||||
.Em not
|
||||
recommended for
|
||||
.Xr mdoc 7 ,
|
||||
which encourages semantic annotation.
|
||||
.Ss Predefined Strings
|
||||
Predefined strings, like
|
||||
.Sx Special Characters ,
|
||||
mark special output glyphs.
|
||||
Predefined strings are escaped with the slash-asterisk,
|
||||
.Sq \e* :
|
||||
single-character
|
||||
.Sq \e*X ,
|
||||
two-character
|
||||
.Sq \e*(XX ,
|
||||
and N-character
|
||||
.Sq \e*[N] .
|
||||
.Pp
|
||||
Examples:
|
||||
.Bl -tag -width Ds -offset indent -compact
|
||||
.It Li \e*(Am
|
||||
Two-letter ampersand predefined string.
|
||||
.It Li \e*q
|
||||
One-letter double-quote predefined string.
|
||||
.El
|
||||
.Pp
|
||||
Predefined strings are not recommended for use,
|
||||
as they differ across implementations.
|
||||
Those supported by
|
||||
.Xr mandoc 1
|
||||
are listed in
|
||||
.Xr mandoc_char 7 .
|
||||
Manuals using these predefined strings are almost certainly not portable.
|
||||
.Ss Whitespace
|
||||
Whitespace consists of the space character.
|
||||
In text lines, whitespace is preserved within a line.
|
||||
In request and macro lines, whitespace delimits arguments and is discarded.
|
||||
.Pp
|
||||
Unescaped trailing spaces are stripped from text line input unless in a
|
||||
literal context.
|
||||
In general, trailing whitespace on any input line is discouraged for
|
||||
reasons of portability.
|
||||
In the rare case that a blank character is needed at the end of an
|
||||
input line, it may be forced by
|
||||
.Sq \e\ \e& .
|
||||
.Pp
|
||||
Literal space characters can be produced in the output
|
||||
using escape sequences.
|
||||
In macro lines, they can also be included in arguments using quotation; see
|
||||
.Sx MACRO SYNTAX
|
||||
for details.
|
||||
.Pp
|
||||
Blank text lines, which may include whitespace, are only permitted
|
||||
within literal contexts.
|
||||
If the first character of a text line is a space, that line is printed
|
||||
with a leading newline.
|
||||
.Ss Scaling Widths
|
||||
Many requests and macros support scaled widths for their arguments.
|
||||
The syntax for a scaled width is
|
||||
.Sq Li [+-]?[0-9]*.[0-9]*[:unit:] ,
|
||||
where a decimal must be preceded or followed by at least one digit.
|
||||
Negative numbers, while accepted, are truncated to zero.
|
||||
.Pp
|
||||
The following scaling units are accepted:
|
||||
.Pp
|
||||
.Bl -tag -width Ds -offset indent -compact
|
||||
.It c
|
||||
centimetre
|
||||
.It i
|
||||
inch
|
||||
.It P
|
||||
pica (~1/6 inch)
|
||||
.It p
|
||||
point (~1/72 inch)
|
||||
.It f
|
||||
synonym for
|
||||
.Sq u
|
||||
.It v
|
||||
default vertical span
|
||||
.It m
|
||||
width of rendered
|
||||
.Sq m
|
||||
.Pq em
|
||||
character
|
||||
.It n
|
||||
width of rendered
|
||||
.Sq n
|
||||
.Pq en
|
||||
character
|
||||
.It u
|
||||
default horizontal span
|
||||
.It M
|
||||
mini-em (~1/100 em)
|
||||
.El
|
||||
.Pp
|
||||
Using anything other than
|
||||
.Sq m ,
|
||||
.Sq n ,
|
||||
.Sq u ,
|
||||
or
|
||||
.Sq v
|
||||
is necessarily non-portable across output media.
|
||||
See
|
||||
.Sx COMPATIBILITY .
|
||||
.Pp
|
||||
If a scaling unit is not provided, the numerical value is interpreted
|
||||
under the default rules of
|
||||
.Sq v
|
||||
for vertical spaces and
|
||||
.Sq u
|
||||
for horizontal ones.
|
||||
.Pp
|
||||
Examples:
|
||||
.Bl -tag -width ".Bl -tag -width 2i" -offset indent -compact
|
||||
.It Li \&.Bl -tag -width 2i
|
||||
two-inch tagged list indentation in
|
||||
.Xr mdoc 7
|
||||
.It Li \&.HP 2i
|
||||
two-inch tagged list indentation in
|
||||
.Xr man 7
|
||||
.It Li \&.sp 2v
|
||||
two vertical spaces
|
||||
.El
|
||||
.Ss Sentence Spacing
|
||||
Each sentence should terminate at the end of an input line.
|
||||
By doing this, a formatter will be able to apply the proper amount of
|
||||
spacing after the end of sentence (unescaped) period, exclamation mark,
|
||||
or question mark followed by zero or more non-sentence closing
|
||||
delimiters
|
||||
.Po
|
||||
.Sq \&) ,
|
||||
.Sq \&] ,
|
||||
.Sq \&' ,
|
||||
.Sq \&"
|
||||
.Pc .
|
||||
.Pp
|
||||
The proper spacing is also intelligently preserved if a sentence ends at
|
||||
the boundary of a macro line.
|
||||
.Pp
|
||||
Examples:
|
||||
.Bd -literal -offset indent -compact
|
||||
Do not end sentences mid-line like this. Instead,
|
||||
end a sentence like this.
|
||||
A macro would end like this:
|
||||
\&.Xr mandoc 1 \&.
|
||||
.Ed
|
||||
.Sh REQUEST SYNTAX
|
||||
A request or macro line consists of:
|
||||
.Pp
|
||||
.Bl -enum -compact
|
||||
.It
|
||||
the control character
|
||||
.Sq \&.
|
||||
or
|
||||
.Sq \(aq
|
||||
at the beginning of the line,
|
||||
.It
|
||||
optionally an arbitrary amount of whitespace,
|
||||
.It
|
||||
the name of the request or the macro, which is one word of arbitrary
|
||||
length, terminated by whitespace,
|
||||
.It
|
||||
and zero or more arguments delimited by whitespace.
|
||||
.El
|
||||
.Pp
|
||||
Thus, the following request lines are all equivalent:
|
||||
.Bd -literal -offset indent
|
||||
\&.ig end
|
||||
\&.ig end
|
||||
\&. ig end
|
||||
.Ed
|
||||
.Sh MACRO SYNTAX
|
||||
Macros are provided by the
|
||||
.Xr mdoc 7
|
||||
and
|
||||
.Xr man 7
|
||||
languages and can be defined by the
|
||||
.Sx \&de
|
||||
request.
|
||||
When called, they follow the same syntax as requests, except that
|
||||
macro arguments may optionally be quoted by enclosing them
|
||||
in double quote characters
|
||||
.Pq Sq \(dq .
|
||||
Quoted text, even if it contains whitespace or would cause
|
||||
a macro invocation when unquoted, is always considered literal text.
|
||||
Inside quoted text, pairs of double quote characters
|
||||
.Pq Sq Qq
|
||||
resolve to single double quote characters.
|
||||
.Pp
|
||||
To be recognised as the beginning of a quoted argument, the opening
|
||||
quote character must be preceded by a space character.
|
||||
A quoted argument extends to the next double quote character that is not
|
||||
part of a pair, or to the end of the input line, whichever comes earlier.
|
||||
Leaving out the terminating double quote character at the end of the line
|
||||
is discouraged.
|
||||
For clarity, if more arguments follow on the same input line,
|
||||
it is recommended to follow the terminating double quote character
|
||||
by a space character; in case the next character after the terminating
|
||||
double quote character is anything else, it is regarded as the beginning
|
||||
of the next, unquoted argument.
|
||||
.Pp
|
||||
Both in quoted and unquoted arguments, pairs of backslashes
|
||||
.Pq Sq \e\e
|
||||
resolve to single backslashes.
|
||||
In unquoted arguments, space characters can alternatively be included
|
||||
by preceding them with a backslash
|
||||
.Pq Sq \e\~ ,
|
||||
but quoting is usually better for clarity.
|
||||
.Pp
|
||||
Examples:
|
||||
.Bl -tag -width Ds -offset indent -compact
|
||||
.It Li .Fn strlen \(dqconst char *s\(dq
|
||||
Group arguments
|
||||
.Qq const char *s
|
||||
into one function argument.
|
||||
If unspecified,
|
||||
.Qq const ,
|
||||
.Qq char ,
|
||||
and
|
||||
.Qq *s
|
||||
would be considered separate arguments.
|
||||
.It Li .Op \(dqFl a\(dq
|
||||
Consider
|
||||
.Qq \&Fl a
|
||||
as literal text instead of a flag macro.
|
||||
.El
|
||||
.Sh REQUEST REFERENCE
|
||||
The
|
||||
.Xr mandoc 1
|
||||
.Nm
|
||||
parser recognises the following requests.
|
||||
Note that the
|
||||
.Nm
|
||||
language defines many more requests not implemented in
|
||||
.Xr mandoc 1 .
|
||||
.Ss \&ad
|
||||
Set line adjustment mode.
|
||||
This line-scoped request is intended to have one argument to select
|
||||
normal, left, right, or centre adjustment for subsequent text.
|
||||
Currently, it is ignored including its arguments,
|
||||
and the number of arguments is not checked.
|
||||
.Ss \&am
|
||||
Append to a macro definition.
|
||||
The syntax of this request is the same as that of
|
||||
.Sx \&de .
|
||||
It is currently ignored by
|
||||
.Xr mandoc 1 ,
|
||||
as are its children.
|
||||
.Ss \&ami
|
||||
Append to a macro definition, specifying the macro name indirectly.
|
||||
The syntax of this request is the same as that of
|
||||
.Sx \&dei .
|
||||
It is currently ignored by
|
||||
.Xr mandoc 1 ,
|
||||
as are its children.
|
||||
.Ss \&am1
|
||||
Append to a macro definition, switching roff compatibility mode off
|
||||
during macro execution.
|
||||
The syntax of this request is the same as that of
|
||||
.Sx \&de1 .
|
||||
It is currently ignored by
|
||||
.Xr mandoc 1 ,
|
||||
as are its children.
|
||||
.Ss \&de
|
||||
Define a
|
||||
.Nm
|
||||
macro.
|
||||
Its syntax can be either
|
||||
.Bd -literal -offset indent
|
||||
.Pf . Cm \&de Ar name
|
||||
.Ar macro definition
|
||||
\&..
|
||||
.Ed
|
||||
.Pp
|
||||
or
|
||||
.Bd -literal -offset indent
|
||||
.Pf . Cm \&de Ar name Ar end
|
||||
.Ar macro definition
|
||||
.Pf . Ar end
|
||||
.Ed
|
||||
.Pp
|
||||
Both forms define or redefine the macro
|
||||
.Ar name
|
||||
to represent the
|
||||
.Ar macro definition ,
|
||||
which may consist of one or more input lines, including the newline
|
||||
characters terminating each line, optionally containing calls to
|
||||
.Nm
|
||||
requests,
|
||||
.Nm
|
||||
macros or high-level macros like
|
||||
.Xr man 7
|
||||
or
|
||||
.Xr mdoc 7
|
||||
macros, whichever applies to the document in question.
|
||||
.Pp
|
||||
Specifying a custom
|
||||
.Ar end
|
||||
macro works in the same way as for
|
||||
.Sx \&ig ;
|
||||
namely, the call to
|
||||
.Sq Pf . Ar end
|
||||
first ends the
|
||||
.Ar macro definition ,
|
||||
and after that, it is also evaluated as a
|
||||
.Nm
|
||||
request or
|
||||
.Nm
|
||||
macro, but not as a high-level macro.
|
||||
.Pp
|
||||
The macro can be invoked later using the syntax
|
||||
.Pp
|
||||
.D1 Pf . Ar name Op Ar argument Op Ar argument ...
|
||||
.Pp
|
||||
Regarding argument parsing, see
|
||||
.Sx MACRO SYNTAX
|
||||
above.
|
||||
.Pp
|
||||
The line invoking the macro will be replaced
|
||||
in the input stream by the
|
||||
.Ar macro definition ,
|
||||
replacing all occurrences of
|
||||
.No \e\e$ Ns Ar N ,
|
||||
where
|
||||
.Ar N
|
||||
is a digit, by the
|
||||
.Ar N Ns th Ar argument .
|
||||
For example,
|
||||
.Bd -literal -offset indent
|
||||
\&.de ZN
|
||||
\efI\e^\e\e$1\e^\efP\e\e$2
|
||||
\&..
|
||||
\&.ZN XtFree .
|
||||
.Ed
|
||||
.Pp
|
||||
produces
|
||||
.Pp
|
||||
.D1 \efI\e^XtFree\e^\efP.
|
||||
.Pp
|
||||
in the input stream, and thus in the output: \fI\^XtFree\^\fP.
|
||||
.Pp
|
||||
Since macros and user-defined strings share a common string table,
|
||||
defining a macro
|
||||
.Ar name
|
||||
clobbers the user-defined string
|
||||
.Ar name ,
|
||||
and the
|
||||
.Ar macro definition
|
||||
can also be printed using the
|
||||
.Sq \e*
|
||||
string interpolation syntax described below
|
||||
.Sx ds ,
|
||||
but this is rarely useful because every macro definition contains at least
|
||||
one explicit newline character.
|
||||
.Pp
|
||||
In order to prevent endless recursion, both groff and
|
||||
.Xr mandoc 1
|
||||
limit the stack depth for expanding macros and strings
|
||||
to a large, but finite number.
|
||||
Do not rely on the exact value of this limit.
|
||||
.Ss \&dei
|
||||
Define a
|
||||
.Nm
|
||||
macro, specifying the macro name indirectly.
|
||||
The syntax of this request is the same as that of
|
||||
.Sx \&de .
|
||||
It is currently ignored by
|
||||
.Xr mandoc 1 ,
|
||||
as are its children.
|
||||
.Ss \&de1
|
||||
Define a
|
||||
.Nm
|
||||
macro that will be executed with
|
||||
.Nm
|
||||
compatibility mode switched off during macro execution.
|
||||
This is a GNU extension not available in traditional
|
||||
.Nm
|
||||
implementations and not even in older versions of groff.
|
||||
Since
|
||||
.Xr mandoc 1
|
||||
does not implement
|
||||
.Nm
|
||||
compatibility mode at all, it handles this request as an alias for
|
||||
.Sx \&de .
|
||||
.Ss \&ds
|
||||
Define a user-defined string.
|
||||
Its syntax is as follows:
|
||||
.Pp
|
||||
.D1 Pf . Cm \&ds Ar name Oo \(dq Oc Ns Ar string
|
||||
.Pp
|
||||
The
|
||||
.Ar name
|
||||
and
|
||||
.Ar string
|
||||
arguments are space-separated.
|
||||
If the
|
||||
.Ar string
|
||||
begins with a double-quote character, that character will not be part
|
||||
of the string.
|
||||
All remaining characters on the input line form the
|
||||
.Ar string ,
|
||||
including whitespace and double-quote characters, even trailing ones.
|
||||
.Pp
|
||||
The
|
||||
.Ar string
|
||||
can be interpolated into subsequent text by using
|
||||
.No \e* Ns Bq Ar name
|
||||
for a
|
||||
.Ar name
|
||||
of arbitrary length, or \e*(NN or \e*N if the length of
|
||||
.Ar name
|
||||
is two or one characters, respectively.
|
||||
Interpolation can be prevented by escaping the leading backslash;
|
||||
that is, an asterisk preceded by an even number of backslashes
|
||||
does not trigger string interpolation.
|
||||
.Pp
|
||||
Since user-defined strings and macros share a common string table,
|
||||
defining a string
|
||||
.Ar name
|
||||
clobbers the macro
|
||||
.Ar name ,
|
||||
and the
|
||||
.Ar name
|
||||
used for defining a string can also be invoked as a macro,
|
||||
in which case the following input line will be appended to the
|
||||
.Ar string ,
|
||||
forming a new input line passed to the
|
||||
.Nm
|
||||
parser.
|
||||
For example,
|
||||
.Bd -literal -offset indent
|
||||
\&.ds badidea .S
|
||||
\&.badidea
|
||||
H SYNOPSIS
|
||||
.Ed
|
||||
.Pp
|
||||
invokes the
|
||||
.Cm SH
|
||||
macro when used in a
|
||||
.Xr man 7
|
||||
document.
|
||||
Such abuse is of course strongly discouraged.
|
||||
.Ss \&el
|
||||
The
|
||||
.Qq else
|
||||
half of an if/else conditional.
|
||||
Pops a result off the stack of conditional evaluations pushed by
|
||||
.Sx \&ie
|
||||
and uses it as its conditional.
|
||||
If no stack entries are present (e.g., due to no prior
|
||||
.Sx \&ie
|
||||
calls)
|
||||
then false is assumed.
|
||||
The syntax of this request is similar to
|
||||
.Sx \&if
|
||||
except that the conditional is missing.
|
||||
.Ss \&EN
|
||||
End an equation block.
|
||||
See
|
||||
.Sx \&EQ .
|
||||
.Ss \&EQ
|
||||
Begin an equation block.
|
||||
See
|
||||
.Xr eqn 7
|
||||
for a description of the equation language.
|
||||
.Ss \&hy
|
||||
Set automatic hyphenation mode.
|
||||
This line-scoped request is currently ignored.
|
||||
.Ss \&ie
|
||||
The
|
||||
.Qq if
|
||||
half of an if/else conditional.
|
||||
The result of the conditional is pushed into a stack used by subsequent
|
||||
invocations of
|
||||
.Sx \&el ,
|
||||
which may be separated by any intervening input (or not exist at all).
|
||||
Its syntax is equivalent to
|
||||
.Sx \&if .
|
||||
.Ss \&if
|
||||
Begins a conditional.
|
||||
Right now, the conditional evaluates to true
|
||||
if and only if it starts with the letter
|
||||
.Sy n ,
|
||||
indicating processing in nroff style as opposed to troff style.
|
||||
If a conditional is false, its children are not processed, but are
|
||||
syntactically interpreted to preserve the integrity of the input
|
||||
document.
|
||||
Thus,
|
||||
.Pp
|
||||
.D1 \&.if t .ig
|
||||
.Pp
|
||||
will discard the
|
||||
.Sq \&.ig ,
|
||||
which may lead to interesting results, but
|
||||
.Pp
|
||||
.D1 \&.if t .if t \e{\e
|
||||
.Pp
|
||||
will continue to syntactically interpret to the block close of the final
|
||||
conditional.
|
||||
Sub-conditionals, in this case, obviously inherit the truth value of
|
||||
the parent.
|
||||
This request has the following syntax:
|
||||
.Bd -literal -offset indent
|
||||
\&.if COND \e{\e
|
||||
BODY...
|
||||
\&.\e}
|
||||
.Ed
|
||||
.Bd -literal -offset indent
|
||||
\&.if COND \e{ BODY
|
||||
BODY... \e}
|
||||
.Ed
|
||||
.Bd -literal -offset indent
|
||||
\&.if COND \e{ BODY
|
||||
BODY...
|
||||
\&.\e}
|
||||
.Ed
|
||||
.Bd -literal -offset indent
|
||||
\&.if COND \e
|
||||
BODY
|
||||
.Ed
|
||||
.Pp
|
||||
COND is a conditional statement.
|
||||
roff allows for complicated conditionals; mandoc is much simpler.
|
||||
At this time, mandoc supports only
|
||||
.Sq n ,
|
||||
evaluating to true;
|
||||
and
|
||||
.Sq t ,
|
||||
.Sq e ,
|
||||
and
|
||||
.Sq o ,
|
||||
evaluating to false.
|
||||
All other invocations are read up to the next end of line or space and
|
||||
evaluate as false.
|
||||
.Pp
|
||||
If the BODY section is begun by an escaped brace
|
||||
.Sq \e{ ,
|
||||
scope continues until a closing-brace escape sequence
|
||||
.Sq \.\e} .
|
||||
If the BODY is not enclosed in braces, scope continues until
|
||||
the end of the line.
|
||||
If the COND is followed by a BODY on the same line, whether after a
|
||||
brace or not, then requests and macros
|
||||
.Em must
|
||||
begin with a control character.
|
||||
It is generally more intuitive, in this case, to write
|
||||
.Bd -literal -offset indent
|
||||
\&.if COND \e{\e
|
||||
\&.foo
|
||||
bar
|
||||
\&.\e}
|
||||
.Ed
|
||||
.Pp
|
||||
than having the request or macro follow as
|
||||
.Pp
|
||||
.D1 \&.if COND \e{ .foo
|
||||
.Pp
|
||||
The scope of a conditional is always parsed, but only executed if the
|
||||
conditional evaluates to true.
|
||||
.Pp
|
||||
Note that the
|
||||
.Sq \e}
|
||||
is converted into a zero-width escape sequence if not passed as a
|
||||
standalone macro
|
||||
.Sq \&.\e} .
|
||||
For example,
|
||||
.Pp
|
||||
.D1 \&.Fl a \e} b
|
||||
.Pp
|
||||
will result in
|
||||
.Sq \e}
|
||||
being considered an argument of the
|
||||
.Sq \&Fl
|
||||
macro.
|
||||
.Ss \&ig
|
||||
Ignore input.
|
||||
Its syntax can be either
|
||||
.Bd -literal -offset indent
|
||||
.Pf . Cm \&ig
|
||||
.Ar ignored text
|
||||
\&..
|
||||
.Ed
|
||||
.Pp
|
||||
or
|
||||
.Bd -literal -offset indent
|
||||
.Pf . Cm \&ig Ar end
|
||||
.Ar ignored text
|
||||
.Pf . Ar end
|
||||
.Ed
|
||||
.Pp
|
||||
In the first case, input is ignored until a
|
||||
.Sq \&..
|
||||
request is encountered on its own line.
|
||||
In the second case, input is ignored until the specified
|
||||
.Sq Pf . Ar end
|
||||
macro is encountered.
|
||||
Do not use the escape character
|
||||
.Sq \e
|
||||
anywhere in the definition of
|
||||
.Ar end ;
|
||||
it would cause very strange behaviour.
|
||||
.Pp
|
||||
When the
|
||||
.Ar end
|
||||
macro is a roff request or a roff macro, like in
|
||||
.Pp
|
||||
.D1 \&.ig if
|
||||
.Pp
|
||||
the subsequent invocation of
|
||||
.Sx \&if
|
||||
will first terminate the
|
||||
.Ar ignored text ,
|
||||
then be invoked as usual.
|
||||
Otherwise, it only terminates the
|
||||
.Ar ignored text ,
|
||||
and arguments following it or the
|
||||
.Sq \&..
|
||||
request are discarded.
|
||||
.Ss \&ne
|
||||
Declare the need for the specified minimum vertical space
|
||||
before the next trap or the bottom of the page.
|
||||
This line-scoped request is currently ignored.
|
||||
.Ss \&nh
|
||||
Turn off automatic hyphenation mode.
|
||||
This line-scoped request is currently ignored.
|
||||
.Ss \&rm
|
||||
Remove a request, macro or string.
|
||||
This request is intended to have one argument,
|
||||
the name of the request, macro or string to be undefined.
|
||||
Currently, it is ignored including its arguments,
|
||||
and the number of arguments is not checked.
|
||||
.Ss \&nr
|
||||
Define a register.
|
||||
A register is an arbitrary string value that defines some sort of state,
|
||||
which influences parsing and/or formatting.
|
||||
Its syntax is as follows:
|
||||
.Pp
|
||||
.D1 Pf \. Cm \&nr Ar name Ar value
|
||||
.Pp
|
||||
The
|
||||
.Ar value
|
||||
may, at the moment, only be an integer.
|
||||
So far, only the following register
|
||||
.Ar name
|
||||
is recognised:
|
||||
.Bl -tag -width Ds
|
||||
.It Cm nS
|
||||
If set to a positive integer value, certain
|
||||
.Xr mdoc 7
|
||||
macros will behave in the same way as in the
|
||||
.Em SYNOPSIS
|
||||
section.
|
||||
If set to 0, these macros will behave in the same way as outside the
|
||||
.Em SYNOPSIS
|
||||
section, even when called within the
|
||||
.Em SYNOPSIS
|
||||
section itself.
|
||||
Note that starting a new
|
||||
.Xr mdoc 7
|
||||
section with the
|
||||
.Cm \&Sh
|
||||
macro will reset this register.
|
||||
.El
|
||||
.Ss \&ns
|
||||
Turn on no-space mode.
|
||||
This line-scoped request is intended to take no arguments.
|
||||
Currently, it is ignored including its arguments,
|
||||
and the number of arguments is not checked.
|
||||
.Ss \&ps
|
||||
Change point size.
|
||||
This line-scoped request is intended to take one numerical argument.
|
||||
Currently, it is ignored including its arguments,
|
||||
and the number of arguments is not checked.
|
||||
.Ss \&so
|
||||
Include a source file.
|
||||
Its syntax is as follows:
|
||||
.Pp
|
||||
.D1 Pf \. Cm \&so Ar file
|
||||
.Pp
|
||||
The
|
||||
.Ar file
|
||||
will be read and its contents processed as input in place of the
|
||||
.Sq \&.so
|
||||
request line.
|
||||
To avoid inadvertent inclusion of unrelated files,
|
||||
.Xr mandoc 1
|
||||
only accepts relative paths not containing the strings
|
||||
.Qq ../
|
||||
and
|
||||
.Qq /.. .
|
||||
.Pp
|
||||
This request requires
|
||||
.Xr man 1
|
||||
to change to the right directory before calling
|
||||
.Xr mandoc 1 ,
|
||||
per convention to the root of the manual tree.
|
||||
Typical usage looks like:
|
||||
.Pp
|
||||
.Dl \&.so man3/Xcursor.3
|
||||
.Pp
|
||||
As the whole concept is rather fragile, the use of
|
||||
.Sx \&so
|
||||
is discouraged.
|
||||
Use
|
||||
.Xr ln 1
|
||||
instead.
|
||||
.Ss \&ta
|
||||
Set tab stops.
|
||||
This line-scoped request can take an arbitrary number of arguments.
|
||||
Currently, it is ignored including its arguments.
|
||||
.Ss \&tr
|
||||
Output character translation.
|
||||
Its syntax is as follows:
|
||||
.Pp
|
||||
.D1 Pf \. Cm \&tr Ar [ab]+
|
||||
.Pp
|
||||
Pairs of
|
||||
.Ar ab
|
||||
characters are replaced
|
||||
.Ar ( a
|
||||
for
|
||||
.Ar b ) .
|
||||
Replacement (or origin) characters may also be character escapes; thus,
|
||||
.Pp
|
||||
.Dl tr \e(xx\e(yy
|
||||
.Pp
|
||||
replaces all invocations of \e(xx with \e(yy.
|
||||
.Ss \&T&
|
||||
Re-start a table layout, retaining the options of the prior table
|
||||
invocation.
|
||||
See
|
||||
.Sx \&TS .
|
||||
.Ss \&TE
|
||||
End a table context.
|
||||
See
|
||||
.Sx \&TS .
|
||||
.Ss \&TS
|
||||
Begin a table, which formats input in aligned rows and columns.
|
||||
See
|
||||
.Xr tbl 7
|
||||
for a description of the tbl language.
|
||||
.Sh COMPATIBILITY
|
||||
This section documents compatibility between mandoc and other other
|
||||
.Nm
|
||||
implementations, at this time limited to GNU troff
|
||||
.Pq Qq groff .
|
||||
The term
|
||||
.Qq historic groff
|
||||
refers to groff version 1.15.
|
||||
.Pp
|
||||
.Bl -dash -compact
|
||||
.It
|
||||
In mandoc, the
|
||||
.Sx \&EQ ,
|
||||
.Sx \&TE ,
|
||||
.Sx \&TS ,
|
||||
and
|
||||
.Sx \&T& ,
|
||||
macros are considered regular macros.
|
||||
In all other
|
||||
.Nm
|
||||
implementations, these are special macros that must be specified without
|
||||
spacing between the control character (which must be a period) and the
|
||||
macro name.
|
||||
.It
|
||||
The
|
||||
.Cm nS
|
||||
register is only compatible with OpenBSD's groff-1.15.
|
||||
.It
|
||||
Historic groff did not accept white-space before a custom
|
||||
.Ar end
|
||||
macro for the
|
||||
.Sx \&ig
|
||||
request.
|
||||
.It
|
||||
The
|
||||
.Sx \&if
|
||||
and family would print funny white-spaces with historic groff when
|
||||
using the next-line syntax.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr mandoc 1 ,
|
||||
.Xr eqn 7 ,
|
||||
.Xr man 7 ,
|
||||
.Xr mandoc_char 7 ,
|
||||
.Xr mdoc 7 ,
|
||||
.Xr tbl 7
|
||||
.Rs
|
||||
.%A Joseph F. Ossanna
|
||||
.%A Brian W. Kernighan
|
||||
.%I AT&T Bell Laboratories
|
||||
.%T Troff User's Manual
|
||||
.%R Computing Science Technical Report
|
||||
.%N 54
|
||||
.%C Murray Hill, New Jersey
|
||||
.%D 1976 and 1992
|
||||
.%U http://www.kohala.com/start/troff/cstr54.ps
|
||||
.Re
|
||||
.Rs
|
||||
.%A Joseph F. Ossanna
|
||||
.%A Brian W. Kernighan
|
||||
.%A Gunnar Ritter
|
||||
.%T Heirloom Documentation Tools Nroff/Troff User's Manual
|
||||
.%D September 17, 2007
|
||||
.%U http://heirloom.sourceforge.net/doctools/troff.pdf
|
||||
.Re
|
||||
.Sh HISTORY
|
||||
The RUNOFF typesetting system, whose input forms the basis for
|
||||
.Nm ,
|
||||
was written in MAD and FAP for the CTSS operating system by Jerome E.
|
||||
Saltzer in 1964.
|
||||
Doug McIlroy rewrote it in BCPL in 1969, renaming it
|
||||
.Nm .
|
||||
Dennis M. Ritchie rewrote McIlroy's
|
||||
.Nm
|
||||
in PDP-11 assembly for
|
||||
.At v1 ,
|
||||
Joseph F. Ossanna improved roff and renamed it nroff
|
||||
for
|
||||
.At v2 ,
|
||||
then ported nroff to C as troff, which Brian W. Kernighan released with
|
||||
.At v7 .
|
||||
In 1989, James Clarke re-implemented troff in C++, naming it groff.
|
||||
.Sh AUTHORS
|
||||
.An -nosplit
|
||||
This
|
||||
.Nm
|
||||
reference was written by
|
||||
.An Kristaps Dzonsons ,
|
||||
.Mt kristaps@bsd.lv ;
|
||||
and
|
||||
.An Ingo Schwarze ,
|
||||
.Mt schwarze@openbsd.org .
|
1768
contrib/mdocml/roff.c
Normal file
1768
contrib/mdocml/roff.c
Normal file
File diff suppressed because it is too large
Load Diff
39
contrib/mdocml/st.c
Normal file
39
contrib/mdocml/st.c
Normal file
@ -0,0 +1,39 @@
|
||||
/* $Id: st.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "mdoc.h"
|
||||
#include "mandoc.h"
|
||||
#include "libmdoc.h"
|
||||
|
||||
#define LINE(x, y) \
|
||||
if (0 == strcmp(p, x)) return(y);
|
||||
|
||||
const char *
|
||||
mdoc_a2st(const char *p)
|
||||
{
|
||||
|
||||
#include "st.in"
|
||||
|
||||
return(NULL);
|
||||
}
|
78
contrib/mdocml/st.in
Normal file
78
contrib/mdocml/st.in
Normal file
@ -0,0 +1,78 @@
|
||||
/* $Id: st.in,v 1.19 2012/02/26 21:47:09 schwarze Exp $ */
|
||||
/*
|
||||
* 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file defines the .St macro arguments. If you add a new
|
||||
* standard, make sure that the left-and side corresponds to the .St
|
||||
* argument (like .St -p1003.1) and the right-hand side corresponds to
|
||||
* the formatted output string.
|
||||
*
|
||||
* Be sure to escape strings.
|
||||
* The non-breaking blanks prevent ending an output line right before
|
||||
* a number. Groff prevent line breaks at the same places.
|
||||
*
|
||||
* REMEMBER TO ADD NEW STANDARDS TO MDOC.7!
|
||||
*/
|
||||
|
||||
LINE("-p1003.1-88", "IEEE Std 1003.1-1988 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1-90", "IEEE Std 1003.1-1990 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1-96", "ISO/IEC 9945-1:1996 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1-2001", "IEEE Std 1003.1-2001 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1-2004", "IEEE Std 1003.1-2004 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1-2008", "IEEE Std 1003.1-2008 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1", "IEEE Std 1003.1 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1b", "IEEE Std 1003.1b (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1b-93", "IEEE Std 1003.1b-1993 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1c-95", "IEEE Std 1003.1c-1995 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1g-2000", "IEEE Std 1003.1g-2000 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1i-95", "IEEE Std 1003.1i-1995 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.2-92", "IEEE Std 1003.2-1992 (\\(lqPOSIX.2\\(rq)")
|
||||
LINE("-p1003.2a-92", "IEEE Std 1003.2a-1992 (\\(lqPOSIX.2\\(rq)")
|
||||
LINE("-p1387.2-95", "IEEE Std 1387.2-1995 (\\(lqPOSIX.7.2\\(rq)")
|
||||
LINE("-p1003.2", "IEEE Std 1003.2 (\\(lqPOSIX.2\\(rq)")
|
||||
LINE("-p1387.2", "IEEE Std 1387.2 (\\(lqPOSIX.7.2\\(rq)")
|
||||
LINE("-isoC", "ISO/IEC 9899:1990 (\\(lqISO\\~C90\\(rq)")
|
||||
LINE("-isoC-90", "ISO/IEC 9899:1990 (\\(lqISO\\~C90\\(rq)")
|
||||
LINE("-isoC-amd1", "ISO/IEC 9899/AMD1:1995 (\\(lqISO\\~C90, Amendment 1\\(rq)")
|
||||
LINE("-isoC-tcor1", "ISO/IEC 9899/TCOR1:1994 (\\(lqISO\\~C90, Technical Corrigendum 1\\(rq)")
|
||||
LINE("-isoC-tcor2", "ISO/IEC 9899/TCOR2:1995 (\\(lqISO\\~C90, Technical Corrigendum 2\\(rq)")
|
||||
LINE("-isoC-99", "ISO/IEC 9899:1999 (\\(lqISO\\~C99\\(rq)")
|
||||
LINE("-isoC-2011", "ISO/IEC 9899:2011 (\\(lqISO\\~C11\\(rq)")
|
||||
LINE("-iso9945-1-90", "ISO/IEC 9945-1:1990 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-iso9945-1-96", "ISO/IEC 9945-1:1996 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-iso9945-2-93", "ISO/IEC 9945-2:1993 (\\(lqPOSIX.2\\(rq)")
|
||||
LINE("-ansiC", "ANSI X3.159-1989 (\\(lqANSI\\~C89\\(rq)")
|
||||
LINE("-ansiC-89", "ANSI X3.159-1989 (\\(lqANSI\\~C89\\(rq)")
|
||||
LINE("-ansiC-99", "ANSI/ISO/IEC 9899-1999 (\\(lqANSI\\~C99\\(rq)")
|
||||
LINE("-ieee754", "IEEE Std 754-1985")
|
||||
LINE("-iso8802-3", "ISO 8802-3: 1989")
|
||||
LINE("-iso8601", "ISO 8601")
|
||||
LINE("-ieee1275-94", "IEEE Std 1275-1994 (\\(lqOpen Firmware\\(rq)")
|
||||
LINE("-xpg3", "X/Open Portability Guide Issue\\~3 (\\(lqXPG3\\(rq)")
|
||||
LINE("-xpg4", "X/Open Portability Guide Issue\\~4 (\\(lqXPG4\\(rq)")
|
||||
LINE("-xpg4.2", "X/Open Portability Guide Issue\\~4, Version\\~2 (\\(lqXPG4.2\\(rq)")
|
||||
LINE("-xpg4.3", "X/Open Portability Guide Issue\\~4, Version\\~3 (\\(lqXPG4.3\\(rq)")
|
||||
LINE("-xbd5", "X/Open Base Definitions Issue\\~5 (\\(lqXBD5\\(rq)")
|
||||
LINE("-xcu5", "X/Open Commands and Utilities Issue\\~5 (\\(lqXCU5\\(rq)")
|
||||
LINE("-xsh5", "X/Open System Interfaces and Headers Issue\\~5 (\\(lqXSH5\\(rq)")
|
||||
LINE("-xns5", "X/Open Networking Services Issue\\~5 (\\(lqXNS5\\(rq)")
|
||||
LINE("-xns5.2", "X/Open Networking Services Issue\\~5.2 (\\(lqXNS5.2\\(rq)")
|
||||
LINE("-xns5.2d2.0", "X/Open Networking Services Issue\\~5.2 Draft\\~2.0 (\\(lqXNS5.2D2.0\\(rq)")
|
||||
LINE("-xcurses4.2", "X/Open Curses Issue\\~4, Version\\~2 (\\(lqXCURSES4.2\\(rq)")
|
||||
LINE("-susv2", "Version\\~2 of the Single UNIX Specification")
|
||||
LINE("-susv3", "Version\\~3 of the Single UNIX Specification")
|
||||
LINE("-svid4", "System\\~V Interface Definition, Fourth Edition (\\(lqSVID4\\(rq)")
|
144
contrib/mdocml/style.css
Normal file
144
contrib/mdocml/style.css
Normal file
@ -0,0 +1,144 @@
|
||||
/* $Id: style.css,v 1.25 2011/08/26 09:03:17 kristaps Exp $ */
|
||||
|
||||
/*
|
||||
* This is an example style-sheet provided for mandoc(1) and the -Thtml
|
||||
* or -Txhtml output mode.
|
||||
*
|
||||
* It mimics the appearance of the traditional cvsweb output.
|
||||
*
|
||||
* See mdoc(7) and man(7) for macro explanations.
|
||||
*/
|
||||
|
||||
html { max-width: 880px; margin-left: 1em; }
|
||||
body { font-size: smaller; font-family: Helvetica,Arial,sans-serif; }
|
||||
h1 { margin-bottom: 1ex; font-size: 110%; margin-left: -4ex; } /* Section header (Sh, SH). */
|
||||
h2 { margin-bottom: 1ex; font-size: 105%; margin-left: -2ex; } /* Sub-section header (Ss, SS). */
|
||||
table { width: 100%; margin-top: 0ex; margin-bottom: 0ex; } /* All tables. */
|
||||
td { vertical-align: top; } /* All table cells. */
|
||||
p { } /* Paragraph: Pp, Lp. */
|
||||
blockquote { margin-left: 5ex; margin-top: 0ex; margin-bottom: 0ex; } /* D1. */
|
||||
div.section { margin-bottom: 2ex; margin-left: 5ex; } /* Sections (Sh, SH). */
|
||||
div.subsection { } /* Sub-sections (Ss, SS). */
|
||||
table.synopsis { } /* SYNOPSIS section table. */
|
||||
|
||||
/* Preamble structure. */
|
||||
|
||||
table.foot { font-size: smaller; margin-top: 1em; border-top: 1px dotted #dddddd; } /* Document footer. */
|
||||
td.foot-date { width: 50%; } /* Document footer: date. */
|
||||
td.foot-os { width: 50%; text-align: right; } /* Document footer: OS/source. */
|
||||
table.head { font-size: smaller; margin-bottom: 1em; border-bottom: 1px dotted #dddddd; } /* Document header. */
|
||||
td.head-ltitle { width: 10%; } /* Document header: left-title. */
|
||||
td.head-vol { width: 80%; text-align: center; } /* Document header: volume. */
|
||||
td.head-rtitle { width: 10%; text-align: right; } /* Document header: right-title. */
|
||||
|
||||
/* General font modes. */
|
||||
|
||||
i { } /* Italic: BI, IB, I, (implicit). */
|
||||
.emph { font-style: italic; font-weight: normal; } /* Emphasis: Em, Bl -emphasis. */
|
||||
b { } /* Bold: SB, BI, IB, BR, RB, B, (implicit). */
|
||||
.symb { font-style: normal; font-weight: bold; } /* Symbolic: Sy, Ms, Bf -symbolic. */
|
||||
small { } /* Small: SB, SM. */
|
||||
.lit { font-style: normal; font-weight: normal; font-family: monospace; } /* Literal: Dl, Li, Ql, Bf -literal, Bl -literal, Bl -unfilled. */
|
||||
|
||||
/* Block modes. */
|
||||
|
||||
.display { } /* Top of all Bd, D1, Dl. */
|
||||
.list { } /* Top of all Bl. */
|
||||
|
||||
/* Context-specific modes. */
|
||||
|
||||
i.addr { font-weight: normal; } /* Address (Ad). */
|
||||
i.arg { font-weight: normal; } /* Command argument (Ar). */
|
||||
span.author { } /* Author name (An). */
|
||||
b.cmd { font-style: normal; } /* Command (Cm). */
|
||||
b.config { font-style: normal; } /* Config statement (Cd). */
|
||||
span.define { } /* Defines (Dv). */
|
||||
span.desc { } /* Nd. After em-dash. */
|
||||
b.diag { font-style: normal; } /* Diagnostic (Bl -diag). */
|
||||
span.env { } /* Environment variables (Ev). */
|
||||
span.errno { } /* Error string (Er). */
|
||||
i.farg { font-weight: normal; } /* Function argument (Fa, Fn). */
|
||||
i.file { font-weight: normal; } /* File (Pa). */
|
||||
b.flag { font-style: normal; } /* Flag (Fl, Cm). */
|
||||
b.fname { font-style: normal; } /* Function name (Fa, Fn, Rv). */
|
||||
i.ftype { font-weight: normal; } /* Function types (Ft, Fn). */
|
||||
b.includes { font-style: normal; } /* Header includes (In). */
|
||||
span.lib { } /* Library (Lb). */
|
||||
i.link-sec { font-weight: normal; } /* Section links (Sx). */
|
||||
b.macro { font-style: normal; } /* Macro-ish thing (Fd). */
|
||||
b.name { font-style: normal; } /* Name of utility (Nm). */
|
||||
span.opt { } /* Options (Op, Oo/Oc). */
|
||||
span.ref { } /* Citations (Rs). */
|
||||
span.ref-auth { } /* Reference author (%A). */
|
||||
i.ref-book { font-weight: normal; } /* Reference book (%B). */
|
||||
span.ref-city { } /* Reference city (%C). */
|
||||
span.ref-date { } /* Reference date (%D). */
|
||||
i.ref-issue { font-weight: normal; } /* Reference issuer/publisher (%I). */
|
||||
i.ref-jrnl { font-weight: normal; } /* Reference journal (%J). */
|
||||
span.ref-num { } /* Reference number (%N). */
|
||||
span.ref-opt { } /* Reference optionals (%O). */
|
||||
span.ref-page { } /* Reference page (%P). */
|
||||
span.ref-corp { } /* Reference corporate/foreign author (%Q). */
|
||||
span.ref-rep { } /* Reference report (%R). */
|
||||
span.ref-title { text-decoration: underline; } /* Reference title (%T). */
|
||||
span.ref-vol { } /* Reference volume (%V). */
|
||||
span.type { font-style: italic; font-weight: normal; } /* Variable types (Vt). */
|
||||
span.unix { } /* Unices (Ux, Ox, Nx, Fx, Bx, Bsx, Dx). */
|
||||
b.utility { font-style: normal; } /* Name of utility (Ex). */
|
||||
b.var { font-style: normal; } /* Variables (Rv). */
|
||||
|
||||
a.link-ext { } /* Off-site link (Lk). */
|
||||
a.link-includes { } /* Include-file link (In). */
|
||||
a.link-mail { } /* Mailto links (Mt). */
|
||||
a.link-man { } /* Manual links (Xr). */
|
||||
a.link-ref { } /* Reference section links (%Q). */
|
||||
a.link-sec { } /* Section links (Sx). */
|
||||
|
||||
/* Formatting for lists. See mdoc(7). */
|
||||
|
||||
dl.list-diag { }
|
||||
dt.list-diag { }
|
||||
dd.list-diag { }
|
||||
|
||||
dl.list-hang { }
|
||||
dt.list-hang { }
|
||||
dd.list-hang { }
|
||||
|
||||
dl.list-inset { }
|
||||
dt.list-inset { }
|
||||
dd.list-inset { }
|
||||
|
||||
dl.list-ohang { }
|
||||
dt.list-ohang { }
|
||||
dd.list-ohang { margin-left: 0ex; }
|
||||
|
||||
dl.list-tag { }
|
||||
dt.list-tag { }
|
||||
dd.list-tag { }
|
||||
|
||||
table.list-col { }
|
||||
tr.list-col { }
|
||||
td.list-col { }
|
||||
|
||||
ul.list-bul { list-style-type: disc; padding-left: 1em; }
|
||||
li.list-bul { }
|
||||
|
||||
ul.list-dash { list-style-type: none; padding-left: 0em; }
|
||||
li.list-dash:before { content: "\2014 "; }
|
||||
|
||||
ul.list-hyph { list-style-type: none; padding-left: 0em; }
|
||||
li.list-hyph:before { content: "\2013 "; }
|
||||
|
||||
ul.list-item { list-style-type: none; padding-left: 0em; }
|
||||
li.list-item { }
|
||||
|
||||
ol.list-enum { padding-left: 2em; }
|
||||
li.list-enum { }
|
||||
|
||||
/* Equation modes. See eqn(7). */
|
||||
|
||||
span.eqn { }
|
||||
|
||||
/* Table modes. See tbl(7). */
|
||||
|
||||
table.tbl { }
|
348
contrib/mdocml/tbl.7
Normal file
348
contrib/mdocml/tbl.7
Normal file
@ -0,0 +1,348 @@
|
||||
.\" $Id: tbl.7,v 1.16 2011/09/03 00:29:21 kristaps Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2010, 2011 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.
|
||||
.\"
|
||||
.Dd $Mdocdate: September 3 2011 $
|
||||
.Dt TBL 7
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm tbl
|
||||
.Nd tbl language reference for mandoc
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm tbl
|
||||
language is a table-formatting language.
|
||||
It is used within
|
||||
.Xr mdoc 7
|
||||
and
|
||||
.Xr man 7
|
||||
.Ux
|
||||
manual pages.
|
||||
This manual describes the subset of the
|
||||
.Nm
|
||||
language accepted by the
|
||||
.Xr mandoc 1
|
||||
utility.
|
||||
.Pp
|
||||
Tables within
|
||||
.Xr mdoc 7
|
||||
or
|
||||
.Xr man 7
|
||||
are enclosed by the
|
||||
.Sq TS
|
||||
and
|
||||
.Sq TE
|
||||
macro tags, whose precise syntax is documented in
|
||||
.Xr roff 7 .
|
||||
Tables consist of a series of options on a single line, followed by the
|
||||
table layout, followed by data.
|
||||
.Pp
|
||||
For example, the following creates a boxed table with digits centred in
|
||||
the cells.
|
||||
.Bd -literal -offset indent
|
||||
\&.TS
|
||||
tab(:) box;
|
||||
c5 c5 c5.
|
||||
1:2:3
|
||||
4:5:6
|
||||
\&.TE
|
||||
.Ed
|
||||
.Pp
|
||||
When formatted, the following output is produced:
|
||||
.Bd -filled -offset indent -compact
|
||||
.TS
|
||||
tab(:) box;
|
||||
c5 c5 c5.
|
||||
1:2:3
|
||||
4:5:6
|
||||
.TE
|
||||
.Ed
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
implementation in
|
||||
.Xr mandoc 1
|
||||
is
|
||||
.Ud
|
||||
.Sh TABLE STRUCTURE
|
||||
Tables are enclosed by the
|
||||
.Sq TS
|
||||
and
|
||||
.Sq TE
|
||||
.Xr roff 7
|
||||
macros.
|
||||
A table consists of an optional single line of table
|
||||
.Sx Options
|
||||
terminated by a semicolon, followed by one or more lines of
|
||||
.Sx Layout
|
||||
specifications terminated by a period, then
|
||||
.Sx Data .
|
||||
All input must be 7-bit ASCII.
|
||||
Example:
|
||||
.Bd -literal -offset indent
|
||||
\&.TS
|
||||
box tab(:);
|
||||
c | c
|
||||
| c | c.
|
||||
1:2
|
||||
3:4
|
||||
\&.TE
|
||||
.Ed
|
||||
.Pp
|
||||
Table data is
|
||||
.Em pre-processed ,
|
||||
that is, data rows are parsed then inserted into the underlying stream
|
||||
of input data.
|
||||
This allows data rows to be interspersed by arbitrary
|
||||
.Xr roff 7 ,
|
||||
.Xr mdoc 7 ,
|
||||
and
|
||||
.Xr man 7
|
||||
macros such as
|
||||
.Bd -literal -offset indent
|
||||
\&.TS
|
||||
tab(:);
|
||||
c c c.
|
||||
1:2:3
|
||||
\&.Ao
|
||||
3:2:1
|
||||
\&.Ac
|
||||
\&.TE
|
||||
.Ed
|
||||
.Pp
|
||||
in the case of
|
||||
.Xr mdoc 7
|
||||
or
|
||||
.Bd -literal -offset indent
|
||||
\&.TS
|
||||
tab(:);
|
||||
c c c.
|
||||
\&.ds ab 2
|
||||
1:\e*(ab:3
|
||||
\&.I
|
||||
3:2:1
|
||||
\&.TE
|
||||
.Ed
|
||||
.Pp
|
||||
in the case of
|
||||
.Xr man 7 .
|
||||
.Ss Options
|
||||
The first line of a table consists of space-separated option keys and
|
||||
modifiers terminated by a semicolon.
|
||||
If the first line does not have a terminating semicolon, it is assumed
|
||||
that no options are specified and instead a
|
||||
.Sx Layout
|
||||
is processed.
|
||||
Some options accept arguments enclosed by parenthesis.
|
||||
The following case-insensitive options are available:
|
||||
.Bl -tag -width Ds
|
||||
.It Cm center
|
||||
This option is not supported by
|
||||
.Xr mandoc 1 .
|
||||
This may also be invoked with
|
||||
.Cm centre .
|
||||
.It Cm delim
|
||||
Accepts a two-character argument.
|
||||
This option is not supported by
|
||||
.Xr mandoc 1 .
|
||||
.It Cm expand
|
||||
This option is not supported by
|
||||
.Xr mandoc 1 .
|
||||
.It Cm box
|
||||
Draw a single-line box around the table.
|
||||
This may also be invoked with
|
||||
.Cm frame .
|
||||
.It Cm doublebox
|
||||
Draw a double-line box around the table.
|
||||
This may also be invoked with
|
||||
.Cm doubleframe .
|
||||
.It Cm allbox
|
||||
This option is not supported by
|
||||
.Xr mandoc 1 .
|
||||
.It Cm tab
|
||||
Accepts a single-character argument.
|
||||
This character is used as a delimiter between data cells, which otherwise
|
||||
defaults to the tab character.
|
||||
.It Cm linesize
|
||||
Accepts a natural number (all digits).
|
||||
This option is not supported by
|
||||
.Xr mandoc 1 .
|
||||
.It Cm nokeep
|
||||
This option is not supported by
|
||||
.Xr mandoc 1 .
|
||||
.It Cm decimalpoint
|
||||
Accepts a single-character argument.
|
||||
This character will be used as the decimal point with the
|
||||
.Cm n
|
||||
layout key.
|
||||
.It Cm nospaces
|
||||
This option is not supported by
|
||||
.Xr mandoc 1 .
|
||||
.El
|
||||
.Ss Layout
|
||||
The table layout follows
|
||||
.Sx Options
|
||||
or a
|
||||
.Sq \&T&
|
||||
macro invocation.
|
||||
Layout specifies how data rows are displayed on output.
|
||||
Each layout line corresponds to a line of data; the last layout line
|
||||
applies to all remaining data lines.
|
||||
Layout lines may also be separated by a comma.
|
||||
Each layout cell consists of one of the following case-insensitive keys:
|
||||
.Bl -tag -width Ds
|
||||
.It Cm c
|
||||
Centre a literal string within its column.
|
||||
.It Cm r
|
||||
Right-justify a literal string within its column.
|
||||
.It Cm l
|
||||
Left-justify a literal string within its column.
|
||||
.It Cm n
|
||||
Justify a number around its last decimal point.
|
||||
If the decimal point is not found on the number, it's assumed to trail
|
||||
the number.
|
||||
.It Cm s
|
||||
Horizontally span columns from the last
|
||||
.No non- Ns Cm s
|
||||
data cell.
|
||||
It is an error if spanning columns follow a
|
||||
.Cm \-
|
||||
or
|
||||
.Cm \(ba
|
||||
cell, or come first.
|
||||
This option is not supported by
|
||||
.Xr mandoc 1 .
|
||||
.It Cm a
|
||||
Left-justify a literal string and pad with one space.
|
||||
.It Cm ^
|
||||
Vertically span rows from the last
|
||||
.No non- Ns Cm ^
|
||||
data cell.
|
||||
It is an error to invoke a vertical span on the first layout row.
|
||||
Unlike a horizontal spanner, you must specify an empty cell (if it not
|
||||
empty, the data is discarded) in the corresponding data cell.
|
||||
.It Cm \-
|
||||
Replace the data cell (its contents will be lost) with a single
|
||||
horizontal line.
|
||||
This may also be invoked with
|
||||
.Cm _ .
|
||||
.It Cm =
|
||||
Replace the data cell (its contents will be lost) with a double
|
||||
horizontal line.
|
||||
.It Cm \(ba
|
||||
Emit a vertical bar instead of data.
|
||||
.It Cm \(ba\(ba
|
||||
Emit a double-vertical bar instead of data.
|
||||
.El
|
||||
.Pp
|
||||
Keys may be followed by a set of modifiers.
|
||||
A modifier is either a modifier key or a natural number for specifying
|
||||
the minimum width of a column.
|
||||
The following case-insensitive modifier keys are available:
|
||||
.Cm z ,
|
||||
.Cm u ,
|
||||
.Cm e ,
|
||||
.Cm t ,
|
||||
.Cm d ,
|
||||
.Cm b ,
|
||||
.Cm i ,
|
||||
.Cm r ,
|
||||
and
|
||||
.Cm f
|
||||
.Po
|
||||
followed by
|
||||
.Cm b ,
|
||||
.Cm i ,
|
||||
.Cm r ,
|
||||
.Cm 3 ,
|
||||
.Cm 2 ,
|
||||
or
|
||||
.Cm 1
|
||||
.Pc .
|
||||
All of these are ignored by
|
||||
.Xr mandoc 1 .
|
||||
.Pp
|
||||
For example, the following layout specifies a centre-justified column of
|
||||
minimum width 10, followed by vertical bar, followed by a left-justified
|
||||
column of minimum width 10, another vertical bar, then a column
|
||||
justified about the decimal point in numbers:
|
||||
.Pp
|
||||
.Dl c10 | l10 | n
|
||||
.Ss Data
|
||||
The data section follows the last layout row.
|
||||
By default, cells in a data section are delimited by a tab.
|
||||
This behaviour may be changed with the
|
||||
.Cm tab
|
||||
option.
|
||||
If
|
||||
.Cm _
|
||||
or
|
||||
.Cm =
|
||||
is specified, a single or double line, respectively, is drawn across the
|
||||
data field.
|
||||
If
|
||||
.Cm \e-
|
||||
or
|
||||
.Cm \e=
|
||||
is specified, a line is drawn within the data field (i.e. terminating
|
||||
within the cell and not draw to the border).
|
||||
If the last cell of a line is
|
||||
.Cm T{ ,
|
||||
all subsequent lines are included as part of the cell until
|
||||
.Cm T}
|
||||
is specified as its own data cell.
|
||||
It may then be followed by a tab
|
||||
.Pq or as designated by Cm tab
|
||||
or an end-of-line to terminate the row.
|
||||
.Sh COMPATIBILITY
|
||||
This section documents compatibility between mandoc and other
|
||||
.Nm
|
||||
implementations, at this time limited to GNU tbl.
|
||||
.Pp
|
||||
.Bl -dash -compact
|
||||
.It
|
||||
In GNU tbl, comments and macros are disallowed prior to the data block
|
||||
of a table.
|
||||
The
|
||||
.Xr mandoc 1
|
||||
implementation allows them.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr mandoc 1 ,
|
||||
.Xr man 7 ,
|
||||
.Xr mandoc_char 7 ,
|
||||
.Xr mdoc 7 ,
|
||||
.Xr roff 7
|
||||
.Rs
|
||||
.%A M. E. Lesk
|
||||
.%T Tbl\(emA Program to Format Tables
|
||||
.%D June 11, 1976
|
||||
.Re
|
||||
.Sh HISTORY
|
||||
The tbl utility, a preprocessor for troff, was originally written by M.
|
||||
E. Lesk at Bell Labs in 1975.
|
||||
The GNU reimplementation of tbl, part of the groff package, was released
|
||||
in 1990 by James Clark.
|
||||
A standalone tbl implementation was written by Kristaps Dzonsons in
|
||||
2010.
|
||||
This formed the basis of the implementation that is part of the
|
||||
.Xr mandoc 1
|
||||
utility.
|
||||
.Sh AUTHORS
|
||||
This
|
||||
.Nm
|
||||
reference was written by
|
||||
.An Kristaps Dzonsons ,
|
||||
.Mt kristaps@bsd.lv .
|
175
contrib/mdocml/tbl.c
Normal file
175
contrib/mdocml/tbl.c
Normal file
@ -0,0 +1,175 @@
|
||||
/* $Id: tbl.c,v 1.26 2011/07/25 15:37:00 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "libmandoc.h"
|
||||
#include "libroff.h"
|
||||
|
||||
enum rofferr
|
||||
tbl_read(struct tbl_node *tbl, int ln, const char *p, int offs)
|
||||
{
|
||||
int len;
|
||||
const char *cp;
|
||||
|
||||
cp = &p[offs];
|
||||
len = (int)strlen(cp);
|
||||
|
||||
/*
|
||||
* If we're in the options section and we don't have a
|
||||
* terminating semicolon, assume we've moved directly into the
|
||||
* layout section. No need to report a warning: this is,
|
||||
* apparently, standard behaviour.
|
||||
*/
|
||||
|
||||
if (TBL_PART_OPTS == tbl->part && len)
|
||||
if (';' != cp[len - 1])
|
||||
tbl->part = TBL_PART_LAYOUT;
|
||||
|
||||
/* Now process each logical section of the table. */
|
||||
|
||||
switch (tbl->part) {
|
||||
case (TBL_PART_OPTS):
|
||||
return(tbl_option(tbl, ln, p) ? ROFF_IGN : ROFF_ERR);
|
||||
case (TBL_PART_LAYOUT):
|
||||
return(tbl_layout(tbl, ln, p) ? ROFF_IGN : ROFF_ERR);
|
||||
case (TBL_PART_CDATA):
|
||||
return(tbl_cdata(tbl, ln, p) ? ROFF_TBL : ROFF_IGN);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* This only returns zero if the line is empty, so we ignore it
|
||||
* and continue on.
|
||||
*/
|
||||
return(tbl_data(tbl, ln, p) ? ROFF_TBL : ROFF_IGN);
|
||||
}
|
||||
|
||||
struct tbl_node *
|
||||
tbl_alloc(int pos, int line, struct mparse *parse)
|
||||
{
|
||||
struct tbl_node *p;
|
||||
|
||||
p = mandoc_calloc(1, sizeof(struct tbl_node));
|
||||
p->line = line;
|
||||
p->pos = pos;
|
||||
p->parse = parse;
|
||||
p->part = TBL_PART_OPTS;
|
||||
p->opts.tab = '\t';
|
||||
p->opts.linesize = 12;
|
||||
p->opts.decimal = '.';
|
||||
return(p);
|
||||
}
|
||||
|
||||
void
|
||||
tbl_free(struct tbl_node *p)
|
||||
{
|
||||
struct tbl_row *rp;
|
||||
struct tbl_cell *cp;
|
||||
struct tbl_span *sp;
|
||||
struct tbl_dat *dp;
|
||||
struct tbl_head *hp;
|
||||
|
||||
while (NULL != (rp = p->first_row)) {
|
||||
p->first_row = rp->next;
|
||||
while (rp->first) {
|
||||
cp = rp->first;
|
||||
rp->first = cp->next;
|
||||
free(cp);
|
||||
}
|
||||
free(rp);
|
||||
}
|
||||
|
||||
while (NULL != (sp = p->first_span)) {
|
||||
p->first_span = sp->next;
|
||||
while (sp->first) {
|
||||
dp = sp->first;
|
||||
sp->first = dp->next;
|
||||
if (dp->string)
|
||||
free(dp->string);
|
||||
free(dp);
|
||||
}
|
||||
free(sp);
|
||||
}
|
||||
|
||||
while (NULL != (hp = p->first_head)) {
|
||||
p->first_head = hp->next;
|
||||
free(hp);
|
||||
}
|
||||
|
||||
free(p);
|
||||
}
|
||||
|
||||
void
|
||||
tbl_restart(int line, int pos, struct tbl_node *tbl)
|
||||
{
|
||||
if (TBL_PART_CDATA == tbl->part)
|
||||
mandoc_msg(MANDOCERR_TBLBLOCK, tbl->parse,
|
||||
tbl->line, tbl->pos, NULL);
|
||||
|
||||
tbl->part = TBL_PART_LAYOUT;
|
||||
tbl->line = line;
|
||||
tbl->pos = pos;
|
||||
|
||||
if (NULL == tbl->first_span || NULL == tbl->first_span->first)
|
||||
mandoc_msg(MANDOCERR_TBLNODATA, tbl->parse,
|
||||
tbl->line, tbl->pos, NULL);
|
||||
}
|
||||
|
||||
const struct tbl_span *
|
||||
tbl_span(struct tbl_node *tbl)
|
||||
{
|
||||
struct tbl_span *span;
|
||||
|
||||
assert(tbl);
|
||||
span = tbl->current_span ? tbl->current_span->next
|
||||
: tbl->first_span;
|
||||
if (span)
|
||||
tbl->current_span = span;
|
||||
return(span);
|
||||
}
|
||||
|
||||
void
|
||||
tbl_end(struct tbl_node **tblp)
|
||||
{
|
||||
struct tbl_node *tbl;
|
||||
|
||||
tbl = *tblp;
|
||||
*tblp = NULL;
|
||||
|
||||
if (NULL == tbl->first_span || NULL == tbl->first_span->first)
|
||||
mandoc_msg(MANDOCERR_TBLNODATA, tbl->parse,
|
||||
tbl->line, tbl->pos, NULL);
|
||||
|
||||
if (tbl->last_span)
|
||||
tbl->last_span->flags |= TBL_SPAN_LAST;
|
||||
|
||||
if (TBL_PART_CDATA == tbl->part)
|
||||
mandoc_msg(MANDOCERR_TBLBLOCK, tbl->parse,
|
||||
tbl->line, tbl->pos, NULL);
|
||||
}
|
||||
|
276
contrib/mdocml/tbl_data.c
Normal file
276
contrib/mdocml/tbl_data.c
Normal file
@ -0,0 +1,276 @@
|
||||
/* $Id: tbl_data.c,v 1.24 2011/03/20 16:02:05 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "libmandoc.h"
|
||||
#include "libroff.h"
|
||||
|
||||
static int data(struct tbl_node *, struct tbl_span *,
|
||||
int, const char *, int *);
|
||||
static struct tbl_span *newspan(struct tbl_node *, int,
|
||||
struct tbl_row *);
|
||||
|
||||
static int
|
||||
data(struct tbl_node *tbl, struct tbl_span *dp,
|
||||
int ln, const char *p, int *pos)
|
||||
{
|
||||
struct tbl_dat *dat;
|
||||
struct tbl_cell *cp;
|
||||
int sv, spans;
|
||||
|
||||
cp = NULL;
|
||||
if (dp->last && dp->last->layout)
|
||||
cp = dp->last->layout->next;
|
||||
else if (NULL == dp->last)
|
||||
cp = dp->layout->first;
|
||||
|
||||
/*
|
||||
* Skip over spanners and vertical lines to data formats, since
|
||||
* we want to match data with data layout cells in the header.
|
||||
*/
|
||||
|
||||
while (cp && (TBL_CELL_VERT == cp->pos ||
|
||||
TBL_CELL_DVERT == cp->pos ||
|
||||
TBL_CELL_SPAN == cp->pos))
|
||||
cp = cp->next;
|
||||
|
||||
/*
|
||||
* Stop processing when we reach the end of the available layout
|
||||
* cells. This means that we have extra input.
|
||||
*/
|
||||
|
||||
if (NULL == cp) {
|
||||
mandoc_msg(MANDOCERR_TBLEXTRADAT,
|
||||
tbl->parse, ln, *pos, NULL);
|
||||
/* Skip to the end... */
|
||||
while (p[*pos])
|
||||
(*pos)++;
|
||||
return(1);
|
||||
}
|
||||
|
||||
dat = mandoc_calloc(1, sizeof(struct tbl_dat));
|
||||
dat->layout = cp;
|
||||
dat->pos = TBL_DATA_NONE;
|
||||
|
||||
assert(TBL_CELL_SPAN != cp->pos);
|
||||
|
||||
for (spans = 0, cp = cp->next; cp; cp = cp->next)
|
||||
if (TBL_CELL_SPAN == cp->pos)
|
||||
spans++;
|
||||
else
|
||||
break;
|
||||
|
||||
dat->spans = spans;
|
||||
|
||||
if (dp->last) {
|
||||
dp->last->next = dat;
|
||||
dp->last = dat;
|
||||
} else
|
||||
dp->last = dp->first = dat;
|
||||
|
||||
sv = *pos;
|
||||
while (p[*pos] && p[*pos] != tbl->opts.tab)
|
||||
(*pos)++;
|
||||
|
||||
/*
|
||||
* Check for a continued-data scope opening. This consists of a
|
||||
* trailing `T{' at the end of the line. Subsequent lines,
|
||||
* until a standalone `T}', are included in our cell.
|
||||
*/
|
||||
|
||||
if (*pos - sv == 2 && 'T' == p[sv] && '{' == p[sv + 1]) {
|
||||
tbl->part = TBL_PART_CDATA;
|
||||
return(0);
|
||||
}
|
||||
|
||||
assert(*pos - sv >= 0);
|
||||
|
||||
dat->string = mandoc_malloc((size_t)(*pos - sv + 1));
|
||||
memcpy(dat->string, &p[sv], (size_t)(*pos - sv));
|
||||
dat->string[*pos - sv] = '\0';
|
||||
|
||||
if (p[*pos])
|
||||
(*pos)++;
|
||||
|
||||
if ( ! strcmp(dat->string, "_"))
|
||||
dat->pos = TBL_DATA_HORIZ;
|
||||
else if ( ! strcmp(dat->string, "="))
|
||||
dat->pos = TBL_DATA_DHORIZ;
|
||||
else if ( ! strcmp(dat->string, "\\_"))
|
||||
dat->pos = TBL_DATA_NHORIZ;
|
||||
else if ( ! strcmp(dat->string, "\\="))
|
||||
dat->pos = TBL_DATA_NDHORIZ;
|
||||
else
|
||||
dat->pos = TBL_DATA_DATA;
|
||||
|
||||
if (TBL_CELL_HORIZ == dat->layout->pos ||
|
||||
TBL_CELL_DHORIZ == dat->layout->pos ||
|
||||
TBL_CELL_DOWN == dat->layout->pos)
|
||||
if (TBL_DATA_DATA == dat->pos && '\0' != *dat->string)
|
||||
mandoc_msg(MANDOCERR_TBLIGNDATA,
|
||||
tbl->parse, ln, sv, NULL);
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
tbl_cdata(struct tbl_node *tbl, int ln, const char *p)
|
||||
{
|
||||
struct tbl_dat *dat;
|
||||
size_t sz;
|
||||
int pos;
|
||||
|
||||
pos = 0;
|
||||
|
||||
dat = tbl->last_span->last;
|
||||
|
||||
if (p[pos] == 'T' && p[pos + 1] == '}') {
|
||||
pos += 2;
|
||||
if (p[pos] == tbl->opts.tab) {
|
||||
tbl->part = TBL_PART_DATA;
|
||||
pos++;
|
||||
return(data(tbl, tbl->last_span, ln, p, &pos));
|
||||
} else if ('\0' == p[pos]) {
|
||||
tbl->part = TBL_PART_DATA;
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* Fallthrough: T} is part of a word. */
|
||||
}
|
||||
|
||||
dat->pos = TBL_DATA_DATA;
|
||||
|
||||
if (dat->string) {
|
||||
sz = strlen(p) + strlen(dat->string) + 2;
|
||||
dat->string = mandoc_realloc(dat->string, sz);
|
||||
strlcat(dat->string, " ", sz);
|
||||
strlcat(dat->string, p, sz);
|
||||
} else
|
||||
dat->string = mandoc_strdup(p);
|
||||
|
||||
if (TBL_CELL_DOWN == dat->layout->pos)
|
||||
mandoc_msg(MANDOCERR_TBLIGNDATA,
|
||||
tbl->parse, ln, pos, NULL);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static struct tbl_span *
|
||||
newspan(struct tbl_node *tbl, int line, struct tbl_row *rp)
|
||||
{
|
||||
struct tbl_span *dp;
|
||||
|
||||
dp = mandoc_calloc(1, sizeof(struct tbl_span));
|
||||
dp->line = line;
|
||||
dp->tbl = &tbl->opts;
|
||||
dp->layout = rp;
|
||||
dp->head = tbl->first_head;
|
||||
|
||||
if (tbl->last_span) {
|
||||
tbl->last_span->next = dp;
|
||||
tbl->last_span = dp;
|
||||
} else {
|
||||
tbl->last_span = tbl->first_span = dp;
|
||||
tbl->current_span = NULL;
|
||||
dp->flags |= TBL_SPAN_FIRST;
|
||||
}
|
||||
|
||||
return(dp);
|
||||
}
|
||||
|
||||
int
|
||||
tbl_data(struct tbl_node *tbl, int ln, const char *p)
|
||||
{
|
||||
struct tbl_span *dp;
|
||||
struct tbl_row *rp;
|
||||
int pos;
|
||||
|
||||
pos = 0;
|
||||
|
||||
if ('\0' == p[pos]) {
|
||||
mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, pos, NULL);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Choose a layout row: take the one following the last parsed
|
||||
* span's. If that doesn't exist, use the last parsed span's.
|
||||
* If there's no last parsed span, use the first row. Lastly,
|
||||
* if the last span was a horizontal line, use the same layout
|
||||
* (it doesn't "consume" the layout).
|
||||
*/
|
||||
|
||||
if (tbl->last_span) {
|
||||
assert(tbl->last_span->layout);
|
||||
if (tbl->last_span->pos == TBL_SPAN_DATA) {
|
||||
for (rp = tbl->last_span->layout->next;
|
||||
rp && rp->first; rp = rp->next) {
|
||||
switch (rp->first->pos) {
|
||||
case (TBL_CELL_HORIZ):
|
||||
dp = newspan(tbl, ln, rp);
|
||||
dp->pos = TBL_SPAN_HORIZ;
|
||||
continue;
|
||||
case (TBL_CELL_DHORIZ):
|
||||
dp = newspan(tbl, ln, rp);
|
||||
dp->pos = TBL_SPAN_DHORIZ;
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else
|
||||
rp = tbl->last_span->layout;
|
||||
|
||||
if (NULL == rp)
|
||||
rp = tbl->last_span->layout;
|
||||
} else
|
||||
rp = tbl->first_row;
|
||||
|
||||
assert(rp);
|
||||
|
||||
dp = newspan(tbl, ln, rp);
|
||||
|
||||
if ( ! strcmp(p, "_")) {
|
||||
dp->pos = TBL_SPAN_HORIZ;
|
||||
return(1);
|
||||
} else if ( ! strcmp(p, "=")) {
|
||||
dp->pos = TBL_SPAN_DHORIZ;
|
||||
return(1);
|
||||
}
|
||||
|
||||
dp->pos = TBL_SPAN_DATA;
|
||||
|
||||
/* This returns 0 when TBL_PART_CDATA is entered. */
|
||||
|
||||
while ('\0' != p[pos])
|
||||
if ( ! data(tbl, dp, ln, p, &pos))
|
||||
return(0);
|
||||
|
||||
return(1);
|
||||
}
|
151
contrib/mdocml/tbl_html.c
Normal file
151
contrib/mdocml/tbl_html.c
Normal file
@ -0,0 +1,151 @@
|
||||
/* $Id: tbl_html.c,v 1.9 2011/09/18 14:14:15 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "out.h"
|
||||
#include "html.h"
|
||||
|
||||
static void html_tblopen(struct html *, const struct tbl_span *);
|
||||
static size_t html_tbl_len(size_t, void *);
|
||||
static size_t html_tbl_strlen(const char *, void *);
|
||||
|
||||
/* ARGSUSED */
|
||||
static size_t
|
||||
html_tbl_len(size_t sz, void *arg)
|
||||
{
|
||||
|
||||
return(sz);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static size_t
|
||||
html_tbl_strlen(const char *p, void *arg)
|
||||
{
|
||||
|
||||
return(strlen(p));
|
||||
}
|
||||
|
||||
static void
|
||||
html_tblopen(struct html *h, const struct tbl_span *sp)
|
||||
{
|
||||
const struct tbl_head *hp;
|
||||
struct htmlpair tag;
|
||||
struct roffsu su;
|
||||
struct roffcol *col;
|
||||
|
||||
if (TBL_SPAN_FIRST & sp->flags) {
|
||||
h->tbl.len = html_tbl_len;
|
||||
h->tbl.slen = html_tbl_strlen;
|
||||
tblcalc(&h->tbl, sp);
|
||||
}
|
||||
|
||||
assert(NULL == h->tblt);
|
||||
PAIR_CLASS_INIT(&tag, "tbl");
|
||||
h->tblt = print_otag(h, TAG_TABLE, 1, &tag);
|
||||
|
||||
for (hp = sp->head; hp; hp = hp->next) {
|
||||
bufinit(h);
|
||||
col = &h->tbl.cols[hp->ident];
|
||||
SCALE_HS_INIT(&su, col->width);
|
||||
bufcat_su(h, "width", &su);
|
||||
PAIR_STYLE_INIT(&tag, h);
|
||||
print_otag(h, TAG_COL, 1, &tag);
|
||||
}
|
||||
|
||||
print_otag(h, TAG_TBODY, 0, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
print_tblclose(struct html *h)
|
||||
{
|
||||
|
||||
assert(h->tblt);
|
||||
print_tagq(h, h->tblt);
|
||||
h->tblt = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
print_tbl(struct html *h, const struct tbl_span *sp)
|
||||
{
|
||||
const struct tbl_head *hp;
|
||||
const struct tbl_dat *dp;
|
||||
struct htmlpair tag;
|
||||
struct tag *tt;
|
||||
|
||||
/* Inhibit printing of spaces: we do padding ourselves. */
|
||||
|
||||
if (NULL == h->tblt)
|
||||
html_tblopen(h, sp);
|
||||
|
||||
assert(h->tblt);
|
||||
|
||||
h->flags |= HTML_NONOSPACE;
|
||||
h->flags |= HTML_NOSPACE;
|
||||
|
||||
tt = print_otag(h, TAG_TR, 0, NULL);
|
||||
|
||||
switch (sp->pos) {
|
||||
case (TBL_SPAN_HORIZ):
|
||||
/* FALLTHROUGH */
|
||||
case (TBL_SPAN_DHORIZ):
|
||||
PAIR_INIT(&tag, ATTR_COLSPAN, "0");
|
||||
print_otag(h, TAG_TD, 1, &tag);
|
||||
break;
|
||||
default:
|
||||
dp = sp->first;
|
||||
for (hp = sp->head; hp; hp = hp->next) {
|
||||
print_stagq(h, tt);
|
||||
print_otag(h, TAG_TD, 0, NULL);
|
||||
|
||||
switch (hp->pos) {
|
||||
case (TBL_HEAD_VERT):
|
||||
/* FALLTHROUGH */
|
||||
case (TBL_HEAD_DVERT):
|
||||
continue;
|
||||
case (TBL_HEAD_DATA):
|
||||
if (NULL == dp)
|
||||
break;
|
||||
if (TBL_CELL_DOWN != dp->layout->pos)
|
||||
if (dp->string)
|
||||
print_text(h, dp->string);
|
||||
dp = dp->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
print_tagq(h, tt);
|
||||
|
||||
h->flags &= ~HTML_NONOSPACE;
|
||||
|
||||
if (TBL_SPAN_LAST & sp->flags) {
|
||||
assert(h->tbl.cols);
|
||||
free(h->tbl.cols);
|
||||
h->tbl.cols = NULL;
|
||||
print_tblclose(h);
|
||||
}
|
||||
|
||||
}
|
472
contrib/mdocml/tbl_layout.c
Normal file
472
contrib/mdocml/tbl_layout.c
Normal file
@ -0,0 +1,472 @@
|
||||
/* $Id: tbl_layout.c,v 1.22 2011/09/18 14:14:15 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "libmandoc.h"
|
||||
#include "libroff.h"
|
||||
|
||||
struct tbl_phrase {
|
||||
char name;
|
||||
enum tbl_cellt key;
|
||||
};
|
||||
|
||||
/*
|
||||
* FIXME: we can make this parse a lot nicer by, when an error is
|
||||
* encountered in a layout key, bailing to the next key (i.e. to the
|
||||
* next whitespace then continuing).
|
||||
*/
|
||||
|
||||
#define KEYS_MAX 11
|
||||
|
||||
static const struct tbl_phrase keys[KEYS_MAX] = {
|
||||
{ 'c', TBL_CELL_CENTRE },
|
||||
{ 'r', TBL_CELL_RIGHT },
|
||||
{ 'l', TBL_CELL_LEFT },
|
||||
{ 'n', TBL_CELL_NUMBER },
|
||||
{ 's', TBL_CELL_SPAN },
|
||||
{ 'a', TBL_CELL_LONG },
|
||||
{ '^', TBL_CELL_DOWN },
|
||||
{ '-', TBL_CELL_HORIZ },
|
||||
{ '_', TBL_CELL_HORIZ },
|
||||
{ '=', TBL_CELL_DHORIZ },
|
||||
{ '|', TBL_CELL_VERT }
|
||||
};
|
||||
|
||||
static int mods(struct tbl_node *, struct tbl_cell *,
|
||||
int, const char *, int *);
|
||||
static int cell(struct tbl_node *, struct tbl_row *,
|
||||
int, const char *, int *);
|
||||
static void row(struct tbl_node *, int, const char *, int *);
|
||||
static struct tbl_cell *cell_alloc(struct tbl_node *,
|
||||
struct tbl_row *, enum tbl_cellt);
|
||||
static void head_adjust(const struct tbl_cell *,
|
||||
struct tbl_head *);
|
||||
|
||||
static int
|
||||
mods(struct tbl_node *tbl, struct tbl_cell *cp,
|
||||
int ln, const char *p, int *pos)
|
||||
{
|
||||
char buf[5];
|
||||
int i;
|
||||
|
||||
/* Not all types accept modifiers. */
|
||||
|
||||
switch (cp->pos) {
|
||||
case (TBL_CELL_DOWN):
|
||||
/* FALLTHROUGH */
|
||||
case (TBL_CELL_HORIZ):
|
||||
/* FALLTHROUGH */
|
||||
case (TBL_CELL_DHORIZ):
|
||||
/* FALLTHROUGH */
|
||||
case (TBL_CELL_VERT):
|
||||
/* FALLTHROUGH */
|
||||
case (TBL_CELL_DVERT):
|
||||
return(1);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
mod:
|
||||
/*
|
||||
* XXX: since, at least for now, modifiers are non-conflicting
|
||||
* (are separable by value, regardless of position), we let
|
||||
* modifiers come in any order. The existing tbl doesn't let
|
||||
* this happen.
|
||||
*/
|
||||
switch (p[*pos]) {
|
||||
case ('\0'):
|
||||
/* FALLTHROUGH */
|
||||
case (' '):
|
||||
/* FALLTHROUGH */
|
||||
case ('\t'):
|
||||
/* FALLTHROUGH */
|
||||
case (','):
|
||||
/* FALLTHROUGH */
|
||||
case ('.'):
|
||||
return(1);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Throw away parenthesised expression. */
|
||||
|
||||
if ('(' == p[*pos]) {
|
||||
(*pos)++;
|
||||
while (p[*pos] && ')' != p[*pos])
|
||||
(*pos)++;
|
||||
if (')' == p[*pos]) {
|
||||
(*pos)++;
|
||||
goto mod;
|
||||
}
|
||||
mandoc_msg(MANDOCERR_TBLLAYOUT,
|
||||
tbl->parse, ln, *pos, NULL);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Parse numerical spacing from modifier string. */
|
||||
|
||||
if (isdigit((unsigned char)p[*pos])) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
if ( ! isdigit((unsigned char)p[*pos + i]))
|
||||
break;
|
||||
buf[i] = p[*pos + i];
|
||||
}
|
||||
buf[i] = '\0';
|
||||
|
||||
/* No greater than 4 digits. */
|
||||
|
||||
if (4 == i) {
|
||||
mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
|
||||
ln, *pos, NULL);
|
||||
return(0);
|
||||
}
|
||||
|
||||
*pos += i;
|
||||
cp->spacing = (size_t)atoi(buf);
|
||||
|
||||
goto mod;
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/* TODO: GNU has many more extensions. */
|
||||
|
||||
switch (tolower((unsigned char)p[(*pos)++])) {
|
||||
case ('z'):
|
||||
cp->flags |= TBL_CELL_WIGN;
|
||||
goto mod;
|
||||
case ('u'):
|
||||
cp->flags |= TBL_CELL_UP;
|
||||
goto mod;
|
||||
case ('e'):
|
||||
cp->flags |= TBL_CELL_EQUAL;
|
||||
goto mod;
|
||||
case ('t'):
|
||||
cp->flags |= TBL_CELL_TALIGN;
|
||||
goto mod;
|
||||
case ('d'):
|
||||
cp->flags |= TBL_CELL_BALIGN;
|
||||
goto mod;
|
||||
case ('w'): /* XXX for now, ignore minimal column width */
|
||||
goto mod;
|
||||
case ('f'):
|
||||
break;
|
||||
case ('r'):
|
||||
/* FALLTHROUGH */
|
||||
case ('b'):
|
||||
/* FALLTHROUGH */
|
||||
case ('i'):
|
||||
(*pos)--;
|
||||
break;
|
||||
default:
|
||||
mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
|
||||
ln, *pos - 1, NULL);
|
||||
return(0);
|
||||
}
|
||||
|
||||
switch (tolower((unsigned char)p[(*pos)++])) {
|
||||
case ('3'):
|
||||
/* FALLTHROUGH */
|
||||
case ('b'):
|
||||
cp->flags |= TBL_CELL_BOLD;
|
||||
goto mod;
|
||||
case ('2'):
|
||||
/* FALLTHROUGH */
|
||||
case ('i'):
|
||||
cp->flags |= TBL_CELL_ITALIC;
|
||||
goto mod;
|
||||
case ('1'):
|
||||
/* FALLTHROUGH */
|
||||
case ('r'):
|
||||
goto mod;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
|
||||
ln, *pos - 1, NULL);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
cell(struct tbl_node *tbl, struct tbl_row *rp,
|
||||
int ln, const char *p, int *pos)
|
||||
{
|
||||
int i;
|
||||
enum tbl_cellt c;
|
||||
|
||||
/* Parse the column position (`r', `R', `|', ...). */
|
||||
|
||||
for (i = 0; i < KEYS_MAX; i++)
|
||||
if (tolower((unsigned char)p[*pos]) == keys[i].name)
|
||||
break;
|
||||
|
||||
if (KEYS_MAX == i) {
|
||||
mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
|
||||
ln, *pos, NULL);
|
||||
return(0);
|
||||
}
|
||||
|
||||
c = keys[i].key;
|
||||
|
||||
/*
|
||||
* If a span cell is found first, raise a warning and abort the
|
||||
* parse. If a span cell is found and the last layout element
|
||||
* isn't a "normal" layout, bail.
|
||||
*
|
||||
* FIXME: recover from this somehow?
|
||||
*/
|
||||
|
||||
if (TBL_CELL_SPAN == c) {
|
||||
if (NULL == rp->first) {
|
||||
mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
|
||||
ln, *pos, NULL);
|
||||
return(0);
|
||||
} else if (rp->last)
|
||||
switch (rp->last->pos) {
|
||||
case (TBL_CELL_VERT):
|
||||
case (TBL_CELL_DVERT):
|
||||
case (TBL_CELL_HORIZ):
|
||||
case (TBL_CELL_DHORIZ):
|
||||
mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
|
||||
ln, *pos, NULL);
|
||||
return(0);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If a vertical spanner is found, we may not be in the first
|
||||
* row.
|
||||
*/
|
||||
|
||||
if (TBL_CELL_DOWN == c && rp == tbl->first_row) {
|
||||
mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, ln, *pos, NULL);
|
||||
return(0);
|
||||
}
|
||||
|
||||
(*pos)++;
|
||||
|
||||
/* Extra check for the double-vertical. */
|
||||
|
||||
if (TBL_CELL_VERT == c && '|' == p[*pos]) {
|
||||
(*pos)++;
|
||||
c = TBL_CELL_DVERT;
|
||||
}
|
||||
|
||||
/* Disallow adjacent spacers. */
|
||||
|
||||
if (rp->last && (TBL_CELL_VERT == c || TBL_CELL_DVERT == c) &&
|
||||
(TBL_CELL_VERT == rp->last->pos ||
|
||||
TBL_CELL_DVERT == rp->last->pos)) {
|
||||
mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, ln, *pos - 1, NULL);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Allocate cell then parse its modifiers. */
|
||||
|
||||
return(mods(tbl, cell_alloc(tbl, rp, c), ln, p, pos));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
row(struct tbl_node *tbl, int ln, const char *p, int *pos)
|
||||
{
|
||||
struct tbl_row *rp;
|
||||
|
||||
row: /*
|
||||
* EBNF describing this section:
|
||||
*
|
||||
* row ::= row_list [:space:]* [.]?[\n]
|
||||
* row_list ::= [:space:]* row_elem row_tail
|
||||
* row_tail ::= [:space:]*[,] row_list |
|
||||
* epsilon
|
||||
* row_elem ::= [\t\ ]*[:alpha:]+
|
||||
*/
|
||||
|
||||
rp = mandoc_calloc(1, sizeof(struct tbl_row));
|
||||
if (tbl->last_row) {
|
||||
tbl->last_row->next = rp;
|
||||
tbl->last_row = rp;
|
||||
} else
|
||||
tbl->last_row = tbl->first_row = rp;
|
||||
|
||||
cell:
|
||||
while (isspace((unsigned char)p[*pos]))
|
||||
(*pos)++;
|
||||
|
||||
/* Safely exit layout context. */
|
||||
|
||||
if ('.' == p[*pos]) {
|
||||
tbl->part = TBL_PART_DATA;
|
||||
if (NULL == tbl->first_row)
|
||||
mandoc_msg(MANDOCERR_TBLNOLAYOUT, tbl->parse,
|
||||
ln, *pos, NULL);
|
||||
(*pos)++;
|
||||
return;
|
||||
}
|
||||
|
||||
/* End (and possibly restart) a row. */
|
||||
|
||||
if (',' == p[*pos]) {
|
||||
(*pos)++;
|
||||
goto row;
|
||||
} else if ('\0' == p[*pos])
|
||||
return;
|
||||
|
||||
if ( ! cell(tbl, rp, ln, p, pos))
|
||||
return;
|
||||
|
||||
goto cell;
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
int
|
||||
tbl_layout(struct tbl_node *tbl, int ln, const char *p)
|
||||
{
|
||||
int pos;
|
||||
|
||||
pos = 0;
|
||||
row(tbl, ln, p, &pos);
|
||||
|
||||
/* Always succeed. */
|
||||
return(1);
|
||||
}
|
||||
|
||||
static struct tbl_cell *
|
||||
cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos)
|
||||
{
|
||||
struct tbl_cell *p, *pp;
|
||||
struct tbl_head *h, *hp;
|
||||
|
||||
p = mandoc_calloc(1, sizeof(struct tbl_cell));
|
||||
|
||||
if (NULL != (pp = rp->last)) {
|
||||
rp->last->next = p;
|
||||
rp->last = p;
|
||||
} else
|
||||
rp->last = rp->first = p;
|
||||
|
||||
p->pos = pos;
|
||||
|
||||
/*
|
||||
* This is a little bit complicated. Here we determine the
|
||||
* header the corresponds to a cell. We add headers dynamically
|
||||
* when need be or re-use them, otherwise. As an example, given
|
||||
* the following:
|
||||
*
|
||||
* 1 c || l
|
||||
* 2 | c | l
|
||||
* 3 l l
|
||||
* 3 || c | l |.
|
||||
*
|
||||
* We first add the new headers (as there are none) in (1); then
|
||||
* in (2) we insert the first spanner (as it doesn't match up
|
||||
* with the header); then we re-use the prior data headers,
|
||||
* skipping over the spanners; then we re-use everything and add
|
||||
* a last spanner. Note that VERT headers are made into DVERT
|
||||
* ones.
|
||||
*/
|
||||
|
||||
h = pp ? pp->head->next : tbl->first_head;
|
||||
|
||||
if (h) {
|
||||
/* Re-use data header. */
|
||||
if (TBL_HEAD_DATA == h->pos &&
|
||||
(TBL_CELL_VERT != p->pos &&
|
||||
TBL_CELL_DVERT != p->pos)) {
|
||||
p->head = h;
|
||||
return(p);
|
||||
}
|
||||
|
||||
/* Re-use spanner header. */
|
||||
if (TBL_HEAD_DATA != h->pos &&
|
||||
(TBL_CELL_VERT == p->pos ||
|
||||
TBL_CELL_DVERT == p->pos)) {
|
||||
head_adjust(p, h);
|
||||
p->head = h;
|
||||
return(p);
|
||||
}
|
||||
|
||||
/* Right-shift headers with a new spanner. */
|
||||
if (TBL_HEAD_DATA == h->pos &&
|
||||
(TBL_CELL_VERT == p->pos ||
|
||||
TBL_CELL_DVERT == p->pos)) {
|
||||
hp = mandoc_calloc(1, sizeof(struct tbl_head));
|
||||
hp->ident = tbl->opts.cols++;
|
||||
hp->prev = h->prev;
|
||||
if (h->prev)
|
||||
h->prev->next = hp;
|
||||
if (h == tbl->first_head)
|
||||
tbl->first_head = hp;
|
||||
h->prev = hp;
|
||||
hp->next = h;
|
||||
head_adjust(p, hp);
|
||||
p->head = hp;
|
||||
return(p);
|
||||
}
|
||||
|
||||
if (NULL != (h = h->next)) {
|
||||
head_adjust(p, h);
|
||||
p->head = h;
|
||||
return(p);
|
||||
}
|
||||
|
||||
/* Fall through to default case... */
|
||||
}
|
||||
|
||||
hp = mandoc_calloc(1, sizeof(struct tbl_head));
|
||||
hp->ident = tbl->opts.cols++;
|
||||
|
||||
if (tbl->last_head) {
|
||||
hp->prev = tbl->last_head;
|
||||
tbl->last_head->next = hp;
|
||||
tbl->last_head = hp;
|
||||
} else
|
||||
tbl->last_head = tbl->first_head = hp;
|
||||
|
||||
head_adjust(p, hp);
|
||||
p->head = hp;
|
||||
return(p);
|
||||
}
|
||||
|
||||
static void
|
||||
head_adjust(const struct tbl_cell *cellp, struct tbl_head *head)
|
||||
{
|
||||
if (TBL_CELL_VERT != cellp->pos &&
|
||||
TBL_CELL_DVERT != cellp->pos) {
|
||||
head->pos = TBL_HEAD_DATA;
|
||||
return;
|
||||
}
|
||||
|
||||
if (TBL_CELL_VERT == cellp->pos)
|
||||
if (TBL_HEAD_DVERT != head->pos)
|
||||
head->pos = TBL_HEAD_VERT;
|
||||
|
||||
if (TBL_CELL_DVERT == cellp->pos)
|
||||
head->pos = TBL_HEAD_DVERT;
|
||||
}
|
||||
|
270
contrib/mdocml/tbl_opts.c
Normal file
270
contrib/mdocml/tbl_opts.c
Normal file
@ -0,0 +1,270 @@
|
||||
/* $Id: tbl_opts.c,v 1.12 2011/09/18 14:14:15 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "libmandoc.h"
|
||||
#include "libroff.h"
|
||||
|
||||
enum tbl_ident {
|
||||
KEY_CENTRE = 0,
|
||||
KEY_DELIM,
|
||||
KEY_EXPAND,
|
||||
KEY_BOX,
|
||||
KEY_DBOX,
|
||||
KEY_ALLBOX,
|
||||
KEY_TAB,
|
||||
KEY_LINESIZE,
|
||||
KEY_NOKEEP,
|
||||
KEY_DPOINT,
|
||||
KEY_NOSPACE,
|
||||
KEY_FRAME,
|
||||
KEY_DFRAME,
|
||||
KEY_MAX
|
||||
};
|
||||
|
||||
struct tbl_phrase {
|
||||
const char *name;
|
||||
int key;
|
||||
enum tbl_ident ident;
|
||||
};
|
||||
|
||||
/* Handle Commonwealth/American spellings. */
|
||||
#define KEY_MAXKEYS 14
|
||||
|
||||
/* Maximum length of key name string. */
|
||||
#define KEY_MAXNAME 13
|
||||
|
||||
/* Maximum length of key number size. */
|
||||
#define KEY_MAXNUMSZ 10
|
||||
|
||||
static const struct tbl_phrase keys[KEY_MAXKEYS] = {
|
||||
{ "center", TBL_OPT_CENTRE, KEY_CENTRE},
|
||||
{ "centre", TBL_OPT_CENTRE, KEY_CENTRE},
|
||||
{ "delim", 0, KEY_DELIM},
|
||||
{ "expand", TBL_OPT_EXPAND, KEY_EXPAND},
|
||||
{ "box", TBL_OPT_BOX, KEY_BOX},
|
||||
{ "doublebox", TBL_OPT_DBOX, KEY_DBOX},
|
||||
{ "allbox", TBL_OPT_ALLBOX, KEY_ALLBOX},
|
||||
{ "frame", TBL_OPT_BOX, KEY_FRAME},
|
||||
{ "doubleframe", TBL_OPT_DBOX, KEY_DFRAME},
|
||||
{ "tab", 0, KEY_TAB},
|
||||
{ "linesize", 0, KEY_LINESIZE},
|
||||
{ "nokeep", TBL_OPT_NOKEEP, KEY_NOKEEP},
|
||||
{ "decimalpoint", 0, KEY_DPOINT},
|
||||
{ "nospaces", TBL_OPT_NOSPACE, KEY_NOSPACE},
|
||||
};
|
||||
|
||||
static int arg(struct tbl_node *, int,
|
||||
const char *, int *, enum tbl_ident);
|
||||
static void opt(struct tbl_node *, int,
|
||||
const char *, int *);
|
||||
|
||||
static int
|
||||
arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key)
|
||||
{
|
||||
int i;
|
||||
char buf[KEY_MAXNUMSZ];
|
||||
|
||||
while (isspace((unsigned char)p[*pos]))
|
||||
(*pos)++;
|
||||
|
||||
/* Arguments always begin with a parenthesis. */
|
||||
|
||||
if ('(' != p[*pos]) {
|
||||
mandoc_msg(MANDOCERR_TBL, tbl->parse,
|
||||
ln, *pos, NULL);
|
||||
return(0);
|
||||
}
|
||||
|
||||
(*pos)++;
|
||||
|
||||
/*
|
||||
* The arguments can be ANY value, so we can't just stop at the
|
||||
* next close parenthesis (the argument can be a closed
|
||||
* parenthesis itself).
|
||||
*/
|
||||
|
||||
switch (key) {
|
||||
case (KEY_DELIM):
|
||||
if ('\0' == p[(*pos)++]) {
|
||||
mandoc_msg(MANDOCERR_TBL, tbl->parse,
|
||||
ln, *pos - 1, NULL);
|
||||
return(0);
|
||||
}
|
||||
|
||||
if ('\0' == p[(*pos)++]) {
|
||||
mandoc_msg(MANDOCERR_TBL, tbl->parse,
|
||||
ln, *pos - 1, NULL);
|
||||
return(0);
|
||||
}
|
||||
break;
|
||||
case (KEY_TAB):
|
||||
if ('\0' != (tbl->opts.tab = p[(*pos)++]))
|
||||
break;
|
||||
|
||||
mandoc_msg(MANDOCERR_TBL, tbl->parse,
|
||||
ln, *pos - 1, NULL);
|
||||
return(0);
|
||||
case (KEY_LINESIZE):
|
||||
for (i = 0; i < KEY_MAXNUMSZ && p[*pos]; i++, (*pos)++) {
|
||||
buf[i] = p[*pos];
|
||||
if ( ! isdigit((unsigned char)buf[i]))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < KEY_MAXNUMSZ) {
|
||||
buf[i] = '\0';
|
||||
tbl->opts.linesize = atoi(buf);
|
||||
break;
|
||||
}
|
||||
|
||||
mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos, NULL);
|
||||
return(0);
|
||||
case (KEY_DPOINT):
|
||||
if ('\0' != (tbl->opts.decimal = p[(*pos)++]))
|
||||
break;
|
||||
|
||||
mandoc_msg(MANDOCERR_TBL, tbl->parse,
|
||||
ln, *pos - 1, NULL);
|
||||
return(0);
|
||||
default:
|
||||
abort();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/* End with a close parenthesis. */
|
||||
|
||||
if (')' == p[(*pos)++])
|
||||
return(1);
|
||||
|
||||
mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos - 1, NULL);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void
|
||||
opt(struct tbl_node *tbl, int ln, const char *p, int *pos)
|
||||
{
|
||||
int i, sv;
|
||||
char buf[KEY_MAXNAME];
|
||||
|
||||
/*
|
||||
* Parse individual options from the stream as surrounded by
|
||||
* this goto. Each pass through the routine parses out a single
|
||||
* option and registers it. Option arguments are processed in
|
||||
* the arg() function.
|
||||
*/
|
||||
|
||||
again: /*
|
||||
* EBNF describing this section:
|
||||
*
|
||||
* options ::= option_list [:space:]* [;][\n]
|
||||
* option_list ::= option option_tail
|
||||
* option_tail ::= [:space:]+ option_list |
|
||||
* ::= epsilon
|
||||
* option ::= [:alpha:]+ args
|
||||
* args ::= [:space:]* [(] [:alpha:]+ [)]
|
||||
*/
|
||||
|
||||
while (isspace((unsigned char)p[*pos]))
|
||||
(*pos)++;
|
||||
|
||||
/* Safe exit point. */
|
||||
|
||||
if (';' == p[*pos])
|
||||
return;
|
||||
|
||||
/* Copy up to first non-alpha character. */
|
||||
|
||||
for (sv = *pos, i = 0; i < KEY_MAXNAME; i++, (*pos)++) {
|
||||
buf[i] = (char)tolower((unsigned char)p[*pos]);
|
||||
if ( ! isalpha((unsigned char)buf[i]))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Exit if buffer is empty (or overrun). */
|
||||
|
||||
if (KEY_MAXNAME == i || 0 == i) {
|
||||
mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
buf[i] = '\0';
|
||||
|
||||
while (isspace((unsigned char)p[*pos]))
|
||||
(*pos)++;
|
||||
|
||||
/*
|
||||
* Look through all of the available keys to find one that
|
||||
* matches the input. FIXME: hashtable this.
|
||||
*/
|
||||
|
||||
for (i = 0; i < KEY_MAXKEYS; i++) {
|
||||
if (strcmp(buf, keys[i].name))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Note: this is more difficult to recover from, as we
|
||||
* can be anywhere in the option sequence and it's
|
||||
* harder to jump to the next. Meanwhile, just bail out
|
||||
* of the sequence altogether.
|
||||
*/
|
||||
|
||||
if (keys[i].key)
|
||||
tbl->opts.opts |= keys[i].key;
|
||||
else if ( ! arg(tbl, ln, p, pos, keys[i].ident))
|
||||
return;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow us to recover from bad options by continuing to another
|
||||
* parse sequence.
|
||||
*/
|
||||
|
||||
if (KEY_MAXKEYS == i)
|
||||
mandoc_msg(MANDOCERR_TBLOPT, tbl->parse, ln, sv, NULL);
|
||||
|
||||
goto again;
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
int
|
||||
tbl_option(struct tbl_node *tbl, int ln, const char *p)
|
||||
{
|
||||
int pos;
|
||||
|
||||
/*
|
||||
* Table options are always on just one line, so automatically
|
||||
* switch into the next input mode here.
|
||||
*/
|
||||
tbl->part = TBL_PART_LAYOUT;
|
||||
|
||||
pos = 0;
|
||||
opt(tbl, ln, p, &pos);
|
||||
|
||||
/* Always succeed. */
|
||||
return(1);
|
||||
}
|
444
contrib/mdocml/tbl_term.c
Normal file
444
contrib/mdocml/tbl_term.c
Normal file
@ -0,0 +1,444 @@
|
||||
/* $Id: tbl_term.c,v 1.21 2011/09/20 23:05:49 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "out.h"
|
||||
#include "term.h"
|
||||
|
||||
static size_t term_tbl_len(size_t, void *);
|
||||
static size_t term_tbl_strlen(const char *, void *);
|
||||
static void tbl_char(struct termp *, char, size_t);
|
||||
static void tbl_data(struct termp *, const struct tbl *,
|
||||
const struct tbl_dat *,
|
||||
const struct roffcol *);
|
||||
static size_t tbl_rulewidth(struct termp *, const struct tbl_head *);
|
||||
static void tbl_hframe(struct termp *, const struct tbl_span *, int);
|
||||
static void tbl_literal(struct termp *, const struct tbl_dat *,
|
||||
const struct roffcol *);
|
||||
static void tbl_number(struct termp *, const struct tbl *,
|
||||
const struct tbl_dat *,
|
||||
const struct roffcol *);
|
||||
static void tbl_hrule(struct termp *, const struct tbl_span *);
|
||||
static void tbl_vrule(struct termp *, const struct tbl_head *);
|
||||
|
||||
|
||||
static size_t
|
||||
term_tbl_strlen(const char *p, void *arg)
|
||||
{
|
||||
|
||||
return(term_strlen((const struct termp *)arg, p));
|
||||
}
|
||||
|
||||
static size_t
|
||||
term_tbl_len(size_t sz, void *arg)
|
||||
{
|
||||
|
||||
return(term_len((const struct termp *)arg, sz));
|
||||
}
|
||||
|
||||
void
|
||||
term_tbl(struct termp *tp, const struct tbl_span *sp)
|
||||
{
|
||||
const struct tbl_head *hp;
|
||||
const struct tbl_dat *dp;
|
||||
struct roffcol *col;
|
||||
int spans;
|
||||
size_t rmargin, maxrmargin;
|
||||
|
||||
rmargin = tp->rmargin;
|
||||
maxrmargin = tp->maxrmargin;
|
||||
|
||||
tp->rmargin = tp->maxrmargin = TERM_MAXMARGIN;
|
||||
|
||||
/* Inhibit printing of spaces: we do padding ourselves. */
|
||||
|
||||
tp->flags |= TERMP_NONOSPACE;
|
||||
tp->flags |= TERMP_NOSPACE;
|
||||
|
||||
/*
|
||||
* The first time we're invoked for a given table block,
|
||||
* calculate the table widths and decimal positions.
|
||||
*/
|
||||
|
||||
if (TBL_SPAN_FIRST & sp->flags) {
|
||||
term_flushln(tp);
|
||||
|
||||
tp->tbl.len = term_tbl_len;
|
||||
tp->tbl.slen = term_tbl_strlen;
|
||||
tp->tbl.arg = tp;
|
||||
|
||||
tblcalc(&tp->tbl, sp);
|
||||
}
|
||||
|
||||
/* Horizontal frame at the start of boxed tables. */
|
||||
|
||||
if (TBL_SPAN_FIRST & sp->flags) {
|
||||
if (TBL_OPT_DBOX & sp->tbl->opts)
|
||||
tbl_hframe(tp, sp, 1);
|
||||
if (TBL_OPT_DBOX & sp->tbl->opts ||
|
||||
TBL_OPT_BOX & sp->tbl->opts)
|
||||
tbl_hframe(tp, sp, 0);
|
||||
}
|
||||
|
||||
/* Vertical frame at the start of each row. */
|
||||
|
||||
if (TBL_OPT_BOX & sp->tbl->opts || TBL_OPT_DBOX & sp->tbl->opts)
|
||||
term_word(tp, TBL_SPAN_HORIZ == sp->pos ||
|
||||
TBL_SPAN_DHORIZ == sp->pos ? "+" : "|");
|
||||
|
||||
/*
|
||||
* Now print the actual data itself depending on the span type.
|
||||
* Spanner spans get a horizontal rule; data spanners have their
|
||||
* data printed by matching data to header.
|
||||
*/
|
||||
|
||||
switch (sp->pos) {
|
||||
case (TBL_SPAN_HORIZ):
|
||||
/* FALLTHROUGH */
|
||||
case (TBL_SPAN_DHORIZ):
|
||||
tbl_hrule(tp, sp);
|
||||
break;
|
||||
case (TBL_SPAN_DATA):
|
||||
/* Iterate over template headers. */
|
||||
dp = sp->first;
|
||||
spans = 0;
|
||||
for (hp = sp->head; hp; hp = hp->next) {
|
||||
/*
|
||||
* If the current data header is invoked during
|
||||
* a spanner ("spans" > 0), don't emit anything
|
||||
* at all.
|
||||
*/
|
||||
switch (hp->pos) {
|
||||
case (TBL_HEAD_VERT):
|
||||
/* FALLTHROUGH */
|
||||
case (TBL_HEAD_DVERT):
|
||||
if (spans <= 0)
|
||||
tbl_vrule(tp, hp);
|
||||
continue;
|
||||
case (TBL_HEAD_DATA):
|
||||
break;
|
||||
}
|
||||
|
||||
if (--spans >= 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* All cells get a leading blank, except the
|
||||
* first one and those after double rulers.
|
||||
*/
|
||||
|
||||
if (hp->prev && TBL_HEAD_DVERT != hp->prev->pos)
|
||||
tbl_char(tp, ASCII_NBRSP, 1);
|
||||
|
||||
col = &tp->tbl.cols[hp->ident];
|
||||
tbl_data(tp, sp->tbl, dp, col);
|
||||
|
||||
/* No trailing blanks. */
|
||||
|
||||
if (NULL == hp->next)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Add another blank between cells,
|
||||
* or two when there is no vertical ruler.
|
||||
*/
|
||||
|
||||
tbl_char(tp, ASCII_NBRSP,
|
||||
TBL_HEAD_VERT == hp->next->pos ||
|
||||
TBL_HEAD_DVERT == hp->next->pos ? 1 : 2);
|
||||
|
||||
/*
|
||||
* Go to the next data cell and assign the
|
||||
* number of subsequent spans, if applicable.
|
||||
*/
|
||||
|
||||
if (dp) {
|
||||
spans = dp->spans;
|
||||
dp = dp->next;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Vertical frame at the end of each row. */
|
||||
|
||||
if (TBL_OPT_BOX & sp->tbl->opts || TBL_OPT_DBOX & sp->tbl->opts)
|
||||
term_word(tp, TBL_SPAN_HORIZ == sp->pos ||
|
||||
TBL_SPAN_DHORIZ == sp->pos ? "+" : " |");
|
||||
term_flushln(tp);
|
||||
|
||||
/*
|
||||
* If we're the last row, clean up after ourselves: clear the
|
||||
* existing table configuration and set it to NULL.
|
||||
*/
|
||||
|
||||
if (TBL_SPAN_LAST & sp->flags) {
|
||||
if (TBL_OPT_DBOX & sp->tbl->opts ||
|
||||
TBL_OPT_BOX & sp->tbl->opts)
|
||||
tbl_hframe(tp, sp, 0);
|
||||
if (TBL_OPT_DBOX & sp->tbl->opts)
|
||||
tbl_hframe(tp, sp, 1);
|
||||
assert(tp->tbl.cols);
|
||||
free(tp->tbl.cols);
|
||||
tp->tbl.cols = NULL;
|
||||
}
|
||||
|
||||
tp->flags &= ~TERMP_NONOSPACE;
|
||||
tp->rmargin = rmargin;
|
||||
tp->maxrmargin = maxrmargin;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Horizontal rules extend across the entire table.
|
||||
* Calculate the width by iterating over columns.
|
||||
*/
|
||||
static size_t
|
||||
tbl_rulewidth(struct termp *tp, const struct tbl_head *hp)
|
||||
{
|
||||
size_t width;
|
||||
|
||||
width = tp->tbl.cols[hp->ident].width;
|
||||
if (TBL_HEAD_DATA == hp->pos) {
|
||||
/* Account for leading blanks. */
|
||||
if (hp->prev && TBL_HEAD_DVERT != hp->prev->pos)
|
||||
width++;
|
||||
/* Account for trailing blanks. */
|
||||
width++;
|
||||
if (hp->next &&
|
||||
TBL_HEAD_VERT != hp->next->pos &&
|
||||
TBL_HEAD_DVERT != hp->next->pos)
|
||||
width++;
|
||||
}
|
||||
return(width);
|
||||
}
|
||||
|
||||
/*
|
||||
* Rules inside the table can be single or double
|
||||
* and have crossings with vertical rules marked with pluses.
|
||||
*/
|
||||
static void
|
||||
tbl_hrule(struct termp *tp, const struct tbl_span *sp)
|
||||
{
|
||||
const struct tbl_head *hp;
|
||||
char c;
|
||||
|
||||
c = '-';
|
||||
if (TBL_SPAN_DHORIZ == sp->pos)
|
||||
c = '=';
|
||||
|
||||
for (hp = sp->head; hp; hp = hp->next)
|
||||
tbl_char(tp,
|
||||
TBL_HEAD_DATA == hp->pos ? c : '+',
|
||||
tbl_rulewidth(tp, hp));
|
||||
}
|
||||
|
||||
/*
|
||||
* Rules above and below the table are always single
|
||||
* and have an additional plus at the beginning and end.
|
||||
* For double frames, this function is called twice,
|
||||
* and the outer one does not have crossings.
|
||||
*/
|
||||
static void
|
||||
tbl_hframe(struct termp *tp, const struct tbl_span *sp, int outer)
|
||||
{
|
||||
const struct tbl_head *hp;
|
||||
|
||||
term_word(tp, "+");
|
||||
for (hp = sp->head; hp; hp = hp->next)
|
||||
tbl_char(tp,
|
||||
outer || TBL_HEAD_DATA == hp->pos ? '-' : '+',
|
||||
tbl_rulewidth(tp, hp));
|
||||
term_word(tp, "+");
|
||||
term_flushln(tp);
|
||||
}
|
||||
|
||||
static void
|
||||
tbl_data(struct termp *tp, const struct tbl *tbl,
|
||||
const struct tbl_dat *dp,
|
||||
const struct roffcol *col)
|
||||
{
|
||||
|
||||
if (NULL == dp) {
|
||||
tbl_char(tp, ASCII_NBRSP, col->width);
|
||||
return;
|
||||
}
|
||||
assert(dp->layout);
|
||||
|
||||
switch (dp->pos) {
|
||||
case (TBL_DATA_NONE):
|
||||
tbl_char(tp, ASCII_NBRSP, col->width);
|
||||
return;
|
||||
case (TBL_DATA_HORIZ):
|
||||
/* FALLTHROUGH */
|
||||
case (TBL_DATA_NHORIZ):
|
||||
tbl_char(tp, '-', col->width);
|
||||
return;
|
||||
case (TBL_DATA_NDHORIZ):
|
||||
/* FALLTHROUGH */
|
||||
case (TBL_DATA_DHORIZ):
|
||||
tbl_char(tp, '=', col->width);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (dp->layout->pos) {
|
||||
case (TBL_CELL_HORIZ):
|
||||
tbl_char(tp, '-', col->width);
|
||||
break;
|
||||
case (TBL_CELL_DHORIZ):
|
||||
tbl_char(tp, '=', col->width);
|
||||
break;
|
||||
case (TBL_CELL_LONG):
|
||||
/* FALLTHROUGH */
|
||||
case (TBL_CELL_CENTRE):
|
||||
/* FALLTHROUGH */
|
||||
case (TBL_CELL_LEFT):
|
||||
/* FALLTHROUGH */
|
||||
case (TBL_CELL_RIGHT):
|
||||
tbl_literal(tp, dp, col);
|
||||
break;
|
||||
case (TBL_CELL_NUMBER):
|
||||
tbl_number(tp, tbl, dp, col);
|
||||
break;
|
||||
case (TBL_CELL_DOWN):
|
||||
tbl_char(tp, ASCII_NBRSP, col->width);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tbl_vrule(struct termp *tp, const struct tbl_head *hp)
|
||||
{
|
||||
|
||||
switch (hp->pos) {
|
||||
case (TBL_HEAD_VERT):
|
||||
term_word(tp, "|");
|
||||
break;
|
||||
case (TBL_HEAD_DVERT):
|
||||
term_word(tp, "||");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tbl_char(struct termp *tp, char c, size_t len)
|
||||
{
|
||||
size_t i, sz;
|
||||
char cp[2];
|
||||
|
||||
cp[0] = c;
|
||||
cp[1] = '\0';
|
||||
|
||||
sz = term_strlen(tp, cp);
|
||||
|
||||
for (i = 0; i < len; i += sz)
|
||||
term_word(tp, cp);
|
||||
}
|
||||
|
||||
static void
|
||||
tbl_literal(struct termp *tp, const struct tbl_dat *dp,
|
||||
const struct roffcol *col)
|
||||
{
|
||||
size_t len, padl, padr;
|
||||
|
||||
assert(dp->string);
|
||||
len = term_strlen(tp, dp->string);
|
||||
padr = col->width > len ? col->width - len : 0;
|
||||
padl = 0;
|
||||
|
||||
switch (dp->layout->pos) {
|
||||
case (TBL_CELL_LONG):
|
||||
padl = term_len(tp, 1);
|
||||
padr = padr > padl ? padr - padl : 0;
|
||||
break;
|
||||
case (TBL_CELL_CENTRE):
|
||||
if (2 > padr)
|
||||
break;
|
||||
padl = padr / 2;
|
||||
padr -= padl;
|
||||
break;
|
||||
case (TBL_CELL_RIGHT):
|
||||
padl = padr;
|
||||
padr = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
tbl_char(tp, ASCII_NBRSP, padl);
|
||||
term_word(tp, dp->string);
|
||||
tbl_char(tp, ASCII_NBRSP, padr);
|
||||
}
|
||||
|
||||
static void
|
||||
tbl_number(struct termp *tp, const struct tbl *tbl,
|
||||
const struct tbl_dat *dp,
|
||||
const struct roffcol *col)
|
||||
{
|
||||
char *cp;
|
||||
char buf[2];
|
||||
size_t sz, psz, ssz, d, padl;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* See calc_data_number(). Left-pad by taking the offset of our
|
||||
* and the maximum decimal; right-pad by the remaining amount.
|
||||
*/
|
||||
|
||||
assert(dp->string);
|
||||
|
||||
sz = term_strlen(tp, dp->string);
|
||||
|
||||
buf[0] = tbl->decimal;
|
||||
buf[1] = '\0';
|
||||
|
||||
psz = term_strlen(tp, buf);
|
||||
|
||||
if (NULL != (cp = strrchr(dp->string, tbl->decimal))) {
|
||||
buf[1] = '\0';
|
||||
for (ssz = 0, i = 0; cp != &dp->string[i]; i++) {
|
||||
buf[0] = dp->string[i];
|
||||
ssz += term_strlen(tp, buf);
|
||||
}
|
||||
d = ssz + psz;
|
||||
} else
|
||||
d = sz + psz;
|
||||
|
||||
padl = col->decimal - d;
|
||||
|
||||
tbl_char(tp, ASCII_NBRSP, padl);
|
||||
term_word(tp, dp->string);
|
||||
if (col->width > sz + padl)
|
||||
tbl_char(tp, ASCII_NBRSP, col->width - sz - padl);
|
||||
}
|
||||
|
736
contrib/mdocml/term.c
Normal file
736
contrib/mdocml/term.c
Normal file
@ -0,0 +1,736 @@
|
||||
/* $Id: term.c,v 1.201 2011/09/21 09:57:13 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2010, 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "out.h"
|
||||
#include "term.h"
|
||||
#include "main.h"
|
||||
|
||||
static void adjbuf(struct termp *p, int);
|
||||
static void bufferc(struct termp *, char);
|
||||
static void encode(struct termp *, const char *, size_t);
|
||||
static void encode1(struct termp *, int);
|
||||
|
||||
void
|
||||
term_free(struct termp *p)
|
||||
{
|
||||
|
||||
if (p->buf)
|
||||
free(p->buf);
|
||||
if (p->symtab)
|
||||
mchars_free(p->symtab);
|
||||
|
||||
free(p);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
term_begin(struct termp *p, term_margin head,
|
||||
term_margin foot, const void *arg)
|
||||
{
|
||||
|
||||
p->headf = head;
|
||||
p->footf = foot;
|
||||
p->argf = arg;
|
||||
(*p->begin)(p);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
term_end(struct termp *p)
|
||||
{
|
||||
|
||||
(*p->end)(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush a line of text. A "line" is loosely defined as being something
|
||||
* that should be followed by a newline, regardless of whether it's
|
||||
* broken apart by newlines getting there. A line can also be a
|
||||
* fragment of a columnar list (`Bl -tag' or `Bl -column'), which does
|
||||
* not have a trailing newline.
|
||||
*
|
||||
* The following flags may be specified:
|
||||
*
|
||||
* - TERMP_NOBREAK: this is the most important and is used when making
|
||||
* columns. In short: don't print a newline and instead expect the
|
||||
* next call to do the padding up to the start of the next column.
|
||||
*
|
||||
* - TERMP_TWOSPACE: make sure there is room for at least two space
|
||||
* characters of padding. Otherwise, rather break the line.
|
||||
*
|
||||
* - TERMP_DANGLE: don't newline when TERMP_NOBREAK is specified and
|
||||
* the line is overrun, and don't pad-right if it's underrun.
|
||||
*
|
||||
* - TERMP_HANG: like TERMP_DANGLE, but doesn't newline when
|
||||
* overrunning, instead save the position and continue at that point
|
||||
* when the next invocation.
|
||||
*
|
||||
* In-line line breaking:
|
||||
*
|
||||
* If TERMP_NOBREAK is specified and the line overruns the right
|
||||
* margin, it will break and pad-right to the right margin after
|
||||
* writing. If maxrmargin is violated, it will break and continue
|
||||
* writing from the right-margin, which will lead to the above scenario
|
||||
* upon exit. Otherwise, the line will break at the right margin.
|
||||
*/
|
||||
void
|
||||
term_flushln(struct termp *p)
|
||||
{
|
||||
int i; /* current input position in p->buf */
|
||||
size_t vis; /* current visual position on output */
|
||||
size_t vbl; /* number of blanks to prepend to output */
|
||||
size_t vend; /* end of word visual position on output */
|
||||
size_t bp; /* visual right border position */
|
||||
size_t dv; /* temporary for visual pos calculations */
|
||||
int j; /* temporary loop index for p->buf */
|
||||
int jhy; /* last hyph before overflow w/r/t j */
|
||||
size_t maxvis; /* output position of visible boundary */
|
||||
size_t mmax; /* used in calculating bp */
|
||||
|
||||
/*
|
||||
* First, establish the maximum columns of "visible" content.
|
||||
* This is usually the difference between the right-margin and
|
||||
* an indentation, but can be, for tagged lists or columns, a
|
||||
* small set of values.
|
||||
*/
|
||||
assert (p->rmargin >= p->offset);
|
||||
dv = p->rmargin - p->offset;
|
||||
maxvis = (int)dv > p->overstep ? dv - (size_t)p->overstep : 0;
|
||||
dv = p->maxrmargin - p->offset;
|
||||
mmax = (int)dv > p->overstep ? dv - (size_t)p->overstep : 0;
|
||||
|
||||
bp = TERMP_NOBREAK & p->flags ? mmax : maxvis;
|
||||
|
||||
/*
|
||||
* Calculate the required amount of padding.
|
||||
*/
|
||||
vbl = p->offset + p->overstep > p->viscol ?
|
||||
p->offset + p->overstep - p->viscol : 0;
|
||||
|
||||
vis = vend = 0;
|
||||
i = 0;
|
||||
|
||||
while (i < p->col) {
|
||||
/*
|
||||
* Handle literal tab characters: collapse all
|
||||
* subsequent tabs into a single huge set of spaces.
|
||||
*/
|
||||
while (i < p->col && '\t' == p->buf[i]) {
|
||||
vend = (vis / p->tabwidth + 1) * p->tabwidth;
|
||||
vbl += vend - vis;
|
||||
vis = vend;
|
||||
i++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Count up visible word characters. Control sequences
|
||||
* (starting with the CSI) aren't counted. A space
|
||||
* generates a non-printing word, which is valid (the
|
||||
* space is printed according to regular spacing rules).
|
||||
*/
|
||||
|
||||
for (j = i, jhy = 0; j < p->col; j++) {
|
||||
if ((j && ' ' == p->buf[j]) || '\t' == p->buf[j])
|
||||
break;
|
||||
|
||||
/* Back over the the last printed character. */
|
||||
if (8 == p->buf[j]) {
|
||||
assert(j);
|
||||
vend -= (*p->width)(p, p->buf[j - 1]);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Regular word. */
|
||||
/* Break at the hyphen point if we overrun. */
|
||||
if (vend > vis && vend < bp &&
|
||||
ASCII_HYPH == p->buf[j])
|
||||
jhy = j;
|
||||
|
||||
vend += (*p->width)(p, p->buf[j]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find out whether we would exceed the right margin.
|
||||
* If so, break to the next line.
|
||||
*/
|
||||
if (vend > bp && 0 == jhy && vis > 0) {
|
||||
vend -= vis;
|
||||
(*p->endline)(p);
|
||||
p->viscol = 0;
|
||||
if (TERMP_NOBREAK & p->flags) {
|
||||
vbl = p->rmargin;
|
||||
vend += p->rmargin - p->offset;
|
||||
} else
|
||||
vbl = p->offset;
|
||||
|
||||
/* Remove the p->overstep width. */
|
||||
|
||||
bp += (size_t)p->overstep;
|
||||
p->overstep = 0;
|
||||
}
|
||||
|
||||
/* Write out the [remaining] word. */
|
||||
for ( ; i < p->col; i++) {
|
||||
if (vend > bp && jhy > 0 && i > jhy)
|
||||
break;
|
||||
if ('\t' == p->buf[i])
|
||||
break;
|
||||
if (' ' == p->buf[i]) {
|
||||
j = i;
|
||||
while (' ' == p->buf[i])
|
||||
i++;
|
||||
dv = (size_t)(i - j) * (*p->width)(p, ' ');
|
||||
vbl += dv;
|
||||
vend += dv;
|
||||
break;
|
||||
}
|
||||
if (ASCII_NBRSP == p->buf[i]) {
|
||||
vbl += (*p->width)(p, ' ');
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we definitely know there will be
|
||||
* printable characters to output,
|
||||
* so write preceding white space now.
|
||||
*/
|
||||
if (vbl) {
|
||||
(*p->advance)(p, vbl);
|
||||
p->viscol += vbl;
|
||||
vbl = 0;
|
||||
}
|
||||
|
||||
if (ASCII_HYPH == p->buf[i]) {
|
||||
(*p->letter)(p, '-');
|
||||
p->viscol += (*p->width)(p, '-');
|
||||
continue;
|
||||
}
|
||||
|
||||
(*p->letter)(p, p->buf[i]);
|
||||
if (8 == p->buf[i])
|
||||
p->viscol -= (*p->width)(p, p->buf[i-1]);
|
||||
else
|
||||
p->viscol += (*p->width)(p, p->buf[i]);
|
||||
}
|
||||
vis = vend;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there was trailing white space, it was not printed;
|
||||
* so reset the cursor position accordingly.
|
||||
*/
|
||||
if (vis)
|
||||
vis -= vbl;
|
||||
|
||||
p->col = 0;
|
||||
p->overstep = 0;
|
||||
|
||||
if ( ! (TERMP_NOBREAK & p->flags)) {
|
||||
p->viscol = 0;
|
||||
(*p->endline)(p);
|
||||
return;
|
||||
}
|
||||
|
||||
if (TERMP_HANG & p->flags) {
|
||||
/* We need one blank after the tag. */
|
||||
p->overstep = (int)(vis - maxvis + (*p->width)(p, ' '));
|
||||
|
||||
/*
|
||||
* Behave exactly the same way as groff:
|
||||
* If we have overstepped the margin, temporarily move
|
||||
* it to the right and flag the rest of the line to be
|
||||
* shorter.
|
||||
* If we landed right at the margin, be happy.
|
||||
* If we are one step before the margin, temporarily
|
||||
* move it one step LEFT and flag the rest of the line
|
||||
* to be longer.
|
||||
*/
|
||||
if (p->overstep < -1)
|
||||
p->overstep = 0;
|
||||
return;
|
||||
|
||||
} else if (TERMP_DANGLE & p->flags)
|
||||
return;
|
||||
|
||||
/* If the column was overrun, break the line. */
|
||||
if (maxvis <= vis +
|
||||
((TERMP_TWOSPACE & p->flags) ? (*p->width)(p, ' ') : 0)) {
|
||||
(*p->endline)(p);
|
||||
p->viscol = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* A newline only breaks an existing line; it won't assert vertical
|
||||
* space. All data in the output buffer is flushed prior to the newline
|
||||
* assertion.
|
||||
*/
|
||||
void
|
||||
term_newln(struct termp *p)
|
||||
{
|
||||
|
||||
p->flags |= TERMP_NOSPACE;
|
||||
if (p->col || p->viscol)
|
||||
term_flushln(p);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Asserts a vertical space (a full, empty line-break between lines).
|
||||
* Note that if used twice, this will cause two blank spaces and so on.
|
||||
* All data in the output buffer is flushed prior to the newline
|
||||
* assertion.
|
||||
*/
|
||||
void
|
||||
term_vspace(struct termp *p)
|
||||
{
|
||||
|
||||
term_newln(p);
|
||||
p->viscol = 0;
|
||||
(*p->endline)(p);
|
||||
}
|
||||
|
||||
void
|
||||
term_fontlast(struct termp *p)
|
||||
{
|
||||
enum termfont f;
|
||||
|
||||
f = p->fontl;
|
||||
p->fontl = p->fontq[p->fonti];
|
||||
p->fontq[p->fonti] = f;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
term_fontrepl(struct termp *p, enum termfont f)
|
||||
{
|
||||
|
||||
p->fontl = p->fontq[p->fonti];
|
||||
p->fontq[p->fonti] = f;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
term_fontpush(struct termp *p, enum termfont f)
|
||||
{
|
||||
|
||||
assert(p->fonti + 1 < 10);
|
||||
p->fontl = p->fontq[p->fonti];
|
||||
p->fontq[++p->fonti] = f;
|
||||
}
|
||||
|
||||
|
||||
const void *
|
||||
term_fontq(struct termp *p)
|
||||
{
|
||||
|
||||
return(&p->fontq[p->fonti]);
|
||||
}
|
||||
|
||||
|
||||
enum termfont
|
||||
term_fonttop(struct termp *p)
|
||||
{
|
||||
|
||||
return(p->fontq[p->fonti]);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
term_fontpopq(struct termp *p, const void *key)
|
||||
{
|
||||
|
||||
while (p->fonti >= 0 && key != &p->fontq[p->fonti])
|
||||
p->fonti--;
|
||||
assert(p->fonti >= 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
term_fontpop(struct termp *p)
|
||||
{
|
||||
|
||||
assert(p->fonti);
|
||||
p->fonti--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle pwords, partial words, which may be either a single word or a
|
||||
* phrase that cannot be broken down (such as a literal string). This
|
||||
* handles word styling.
|
||||
*/
|
||||
void
|
||||
term_word(struct termp *p, const char *word)
|
||||
{
|
||||
const char *seq, *cp;
|
||||
char c;
|
||||
int sz, uc;
|
||||
size_t ssz;
|
||||
enum mandoc_esc esc;
|
||||
|
||||
if ( ! (TERMP_NOSPACE & p->flags)) {
|
||||
if ( ! (TERMP_KEEP & p->flags)) {
|
||||
if (TERMP_PREKEEP & p->flags)
|
||||
p->flags |= TERMP_KEEP;
|
||||
bufferc(p, ' ');
|
||||
if (TERMP_SENTENCE & p->flags)
|
||||
bufferc(p, ' ');
|
||||
} else
|
||||
bufferc(p, ASCII_NBRSP);
|
||||
}
|
||||
|
||||
if ( ! (p->flags & TERMP_NONOSPACE))
|
||||
p->flags &= ~TERMP_NOSPACE;
|
||||
else
|
||||
p->flags |= TERMP_NOSPACE;
|
||||
|
||||
p->flags &= ~(TERMP_SENTENCE | TERMP_IGNDELIM);
|
||||
|
||||
while ('\0' != *word) {
|
||||
if ((ssz = strcspn(word, "\\")) > 0)
|
||||
encode(p, word, ssz);
|
||||
|
||||
word += (int)ssz;
|
||||
if ('\\' != *word)
|
||||
continue;
|
||||
|
||||
word++;
|
||||
esc = mandoc_escape(&word, &seq, &sz);
|
||||
if (ESCAPE_ERROR == esc)
|
||||
break;
|
||||
|
||||
if (TERMENC_ASCII != p->enc)
|
||||
switch (esc) {
|
||||
case (ESCAPE_UNICODE):
|
||||
uc = mchars_num2uc(seq + 1, sz - 1);
|
||||
if ('\0' == uc)
|
||||
break;
|
||||
encode1(p, uc);
|
||||
continue;
|
||||
case (ESCAPE_SPECIAL):
|
||||
uc = mchars_spec2cp(p->symtab, seq, sz);
|
||||
if (uc <= 0)
|
||||
break;
|
||||
encode1(p, uc);
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (esc) {
|
||||
case (ESCAPE_UNICODE):
|
||||
encode1(p, '?');
|
||||
break;
|
||||
case (ESCAPE_NUMBERED):
|
||||
c = mchars_num2char(seq, sz);
|
||||
if ('\0' != c)
|
||||
encode(p, &c, 1);
|
||||
break;
|
||||
case (ESCAPE_SPECIAL):
|
||||
cp = mchars_spec2str(p->symtab, seq, sz, &ssz);
|
||||
if (NULL != cp)
|
||||
encode(p, cp, ssz);
|
||||
else if (1 == ssz)
|
||||
encode(p, seq, sz);
|
||||
break;
|
||||
case (ESCAPE_FONTBOLD):
|
||||
term_fontrepl(p, TERMFONT_BOLD);
|
||||
break;
|
||||
case (ESCAPE_FONTITALIC):
|
||||
term_fontrepl(p, TERMFONT_UNDER);
|
||||
break;
|
||||
case (ESCAPE_FONT):
|
||||
/* FALLTHROUGH */
|
||||
case (ESCAPE_FONTROMAN):
|
||||
term_fontrepl(p, TERMFONT_NONE);
|
||||
break;
|
||||
case (ESCAPE_FONTPREV):
|
||||
term_fontlast(p);
|
||||
break;
|
||||
case (ESCAPE_NOSPACE):
|
||||
if ('\0' == *word)
|
||||
p->flags |= TERMP_NOSPACE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
adjbuf(struct termp *p, int sz)
|
||||
{
|
||||
|
||||
if (0 == p->maxcols)
|
||||
p->maxcols = 1024;
|
||||
while (sz >= p->maxcols)
|
||||
p->maxcols <<= 2;
|
||||
|
||||
p->buf = mandoc_realloc
|
||||
(p->buf, sizeof(int) * (size_t)p->maxcols);
|
||||
}
|
||||
|
||||
static void
|
||||
bufferc(struct termp *p, char c)
|
||||
{
|
||||
|
||||
if (p->col + 1 >= p->maxcols)
|
||||
adjbuf(p, p->col + 1);
|
||||
|
||||
p->buf[p->col++] = c;
|
||||
}
|
||||
|
||||
/*
|
||||
* See encode().
|
||||
* Do this for a single (probably unicode) value.
|
||||
* Does not check for non-decorated glyphs.
|
||||
*/
|
||||
static void
|
||||
encode1(struct termp *p, int c)
|
||||
{
|
||||
enum termfont f;
|
||||
|
||||
if (p->col + 4 >= p->maxcols)
|
||||
adjbuf(p, p->col + 4);
|
||||
|
||||
f = term_fonttop(p);
|
||||
|
||||
if (TERMFONT_NONE == f) {
|
||||
p->buf[p->col++] = c;
|
||||
return;
|
||||
} else if (TERMFONT_UNDER == f) {
|
||||
p->buf[p->col++] = '_';
|
||||
} else
|
||||
p->buf[p->col++] = c;
|
||||
|
||||
p->buf[p->col++] = 8;
|
||||
p->buf[p->col++] = c;
|
||||
}
|
||||
|
||||
static void
|
||||
encode(struct termp *p, const char *word, size_t sz)
|
||||
{
|
||||
enum termfont f;
|
||||
int i, len;
|
||||
|
||||
/* LINTED */
|
||||
len = sz;
|
||||
|
||||
/*
|
||||
* Encode and buffer a string of characters. If the current
|
||||
* font mode is unset, buffer directly, else encode then buffer
|
||||
* character by character.
|
||||
*/
|
||||
|
||||
if (TERMFONT_NONE == (f = term_fonttop(p))) {
|
||||
if (p->col + len >= p->maxcols)
|
||||
adjbuf(p, p->col + len);
|
||||
for (i = 0; i < len; i++)
|
||||
p->buf[p->col++] = word[i];
|
||||
return;
|
||||
}
|
||||
|
||||
/* Pre-buffer, assuming worst-case. */
|
||||
|
||||
if (p->col + 1 + (len * 3) >= p->maxcols)
|
||||
adjbuf(p, p->col + 1 + (len * 3));
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (ASCII_HYPH != word[i] &&
|
||||
! isgraph((unsigned char)word[i])) {
|
||||
p->buf[p->col++] = word[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (TERMFONT_UNDER == f)
|
||||
p->buf[p->col++] = '_';
|
||||
else if (ASCII_HYPH == word[i])
|
||||
p->buf[p->col++] = '-';
|
||||
else
|
||||
p->buf[p->col++] = word[i];
|
||||
|
||||
p->buf[p->col++] = 8;
|
||||
p->buf[p->col++] = word[i];
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
term_len(const struct termp *p, size_t sz)
|
||||
{
|
||||
|
||||
return((*p->width)(p, ' ') * sz);
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
term_strlen(const struct termp *p, const char *cp)
|
||||
{
|
||||
size_t sz, rsz, i;
|
||||
int ssz, c;
|
||||
const char *seq, *rhs;
|
||||
enum mandoc_esc esc;
|
||||
static const char rej[] = { '\\', ASCII_HYPH, ASCII_NBRSP, '\0' };
|
||||
|
||||
/*
|
||||
* Account for escaped sequences within string length
|
||||
* calculations. This follows the logic in term_word() as we
|
||||
* must calculate the width of produced strings.
|
||||
*/
|
||||
|
||||
sz = 0;
|
||||
while ('\0' != *cp) {
|
||||
rsz = strcspn(cp, rej);
|
||||
for (i = 0; i < rsz; i++)
|
||||
sz += (*p->width)(p, *cp++);
|
||||
|
||||
c = 0;
|
||||
switch (*cp) {
|
||||
case ('\\'):
|
||||
cp++;
|
||||
esc = mandoc_escape(&cp, &seq, &ssz);
|
||||
if (ESCAPE_ERROR == esc)
|
||||
return(sz);
|
||||
|
||||
if (TERMENC_ASCII != p->enc)
|
||||
switch (esc) {
|
||||
case (ESCAPE_UNICODE):
|
||||
c = mchars_num2uc
|
||||
(seq + 1, ssz - 1);
|
||||
if ('\0' == c)
|
||||
break;
|
||||
sz += (*p->width)(p, c);
|
||||
continue;
|
||||
case (ESCAPE_SPECIAL):
|
||||
c = mchars_spec2cp
|
||||
(p->symtab, seq, ssz);
|
||||
if (c <= 0)
|
||||
break;
|
||||
sz += (*p->width)(p, c);
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
rhs = NULL;
|
||||
|
||||
switch (esc) {
|
||||
case (ESCAPE_UNICODE):
|
||||
sz += (*p->width)(p, '?');
|
||||
break;
|
||||
case (ESCAPE_NUMBERED):
|
||||
c = mchars_num2char(seq, ssz);
|
||||
if ('\0' != c)
|
||||
sz += (*p->width)(p, c);
|
||||
break;
|
||||
case (ESCAPE_SPECIAL):
|
||||
rhs = mchars_spec2str
|
||||
(p->symtab, seq, ssz, &rsz);
|
||||
|
||||
if (ssz != 1 || rhs)
|
||||
break;
|
||||
|
||||
rhs = seq;
|
||||
rsz = ssz;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (NULL == rhs)
|
||||
break;
|
||||
|
||||
for (i = 0; i < rsz; i++)
|
||||
sz += (*p->width)(p, *rhs++);
|
||||
break;
|
||||
case (ASCII_NBRSP):
|
||||
sz += (*p->width)(p, ' ');
|
||||
cp++;
|
||||
break;
|
||||
case (ASCII_HYPH):
|
||||
sz += (*p->width)(p, '-');
|
||||
cp++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(sz);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
size_t
|
||||
term_vspan(const struct termp *p, const struct roffsu *su)
|
||||
{
|
||||
double r;
|
||||
|
||||
switch (su->unit) {
|
||||
case (SCALE_CM):
|
||||
r = su->scale * 2;
|
||||
break;
|
||||
case (SCALE_IN):
|
||||
r = su->scale * 6;
|
||||
break;
|
||||
case (SCALE_PC):
|
||||
r = su->scale;
|
||||
break;
|
||||
case (SCALE_PT):
|
||||
r = su->scale / 8;
|
||||
break;
|
||||
case (SCALE_MM):
|
||||
r = su->scale / 1000;
|
||||
break;
|
||||
case (SCALE_VS):
|
||||
r = su->scale;
|
||||
break;
|
||||
default:
|
||||
r = su->scale - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (r < 0.0)
|
||||
r = 0.0;
|
||||
return(/* LINTED */(size_t)
|
||||
r);
|
||||
}
|
||||
|
||||
size_t
|
||||
term_hspan(const struct termp *p, const struct roffsu *su)
|
||||
{
|
||||
double v;
|
||||
|
||||
v = ((*p->hspan)(p, su));
|
||||
if (v < 0.0)
|
||||
v = 0.0;
|
||||
return((size_t) /* LINTED */
|
||||
v);
|
||||
}
|
128
contrib/mdocml/term.h
Normal file
128
contrib/mdocml/term.h
Normal file
@ -0,0 +1,128 @@
|
||||
/* $Id: term.h,v 1.90 2011/12/04 23:10:52 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 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 TERM_H
|
||||
#define TERM_H
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
struct termp;
|
||||
|
||||
enum termenc {
|
||||
TERMENC_ASCII,
|
||||
TERMENC_LOCALE,
|
||||
TERMENC_UTF8
|
||||
};
|
||||
|
||||
enum termtype {
|
||||
TERMTYPE_CHAR,
|
||||
TERMTYPE_PS,
|
||||
TERMTYPE_PDF
|
||||
};
|
||||
|
||||
enum termfont {
|
||||
TERMFONT_NONE = 0,
|
||||
TERMFONT_BOLD,
|
||||
TERMFONT_UNDER,
|
||||
TERMFONT__MAX
|
||||
};
|
||||
|
||||
#define TERM_MAXMARGIN 100000 /* FIXME */
|
||||
|
||||
typedef void (*term_margin)(struct termp *, const void *);
|
||||
|
||||
struct termp_tbl {
|
||||
int width; /* width in fixed chars */
|
||||
int decimal; /* decimal point position */
|
||||
};
|
||||
|
||||
struct termp {
|
||||
enum termtype type;
|
||||
struct rofftbl tbl; /* table configuration */
|
||||
int mdocstyle; /* imitate mdoc(7) output */
|
||||
size_t defindent; /* Default indent for text. */
|
||||
size_t defrmargin; /* Right margin of the device. */
|
||||
size_t rmargin; /* Current right margin. */
|
||||
size_t maxrmargin; /* Max right margin. */
|
||||
int maxcols; /* Max size of buf. */
|
||||
size_t offset; /* Margin offest. */
|
||||
size_t tabwidth; /* Distance of tab positions. */
|
||||
int col; /* Bytes in buf. */
|
||||
size_t viscol; /* Chars on current line. */
|
||||
int overstep; /* See termp_flushln(). */
|
||||
int flags;
|
||||
#define TERMP_SENTENCE (1 << 1) /* Space before a sentence. */
|
||||
#define TERMP_NOSPACE (1 << 2) /* No space before words. */
|
||||
#define TERMP_NOBREAK (1 << 4) /* See term_flushln(). */
|
||||
#define TERMP_IGNDELIM (1 << 6) /* Delims like regulars. */
|
||||
#define TERMP_NONOSPACE (1 << 7) /* No space (no autounset). */
|
||||
#define TERMP_DANGLE (1 << 8) /* See term_flushln(). */
|
||||
#define TERMP_HANG (1 << 9) /* See term_flushln(). */
|
||||
#define TERMP_TWOSPACE (1 << 10) /* See term_flushln(). */
|
||||
#define TERMP_NOSPLIT (1 << 11) /* See termp_an_pre/post(). */
|
||||
#define TERMP_SPLIT (1 << 12) /* See termp_an_pre/post(). */
|
||||
#define TERMP_ANPREC (1 << 13) /* See termp_an_pre(). */
|
||||
#define TERMP_KEEP (1 << 14) /* Keep words together. */
|
||||
#define TERMP_PREKEEP (1 << 15) /* ...starting with the next one. */
|
||||
int *buf; /* Output buffer. */
|
||||
enum termenc enc; /* Type of encoding. */
|
||||
struct mchars *symtab; /* Encoded-symbol table. */
|
||||
enum termfont fontl; /* Last font set. */
|
||||
enum termfont fontq[10]; /* Symmetric fonts. */
|
||||
int fonti; /* Index of font stack. */
|
||||
term_margin headf; /* invoked to print head */
|
||||
term_margin footf; /* invoked to print foot */
|
||||
void (*letter)(struct termp *, int);
|
||||
void (*begin)(struct termp *);
|
||||
void (*end)(struct termp *);
|
||||
void (*endline)(struct termp *);
|
||||
void (*advance)(struct termp *, size_t);
|
||||
size_t (*width)(const struct termp *, int);
|
||||
double (*hspan)(const struct termp *,
|
||||
const struct roffsu *);
|
||||
const void *argf; /* arg for headf/footf */
|
||||
struct termp_ps *ps;
|
||||
};
|
||||
|
||||
void term_eqn(struct termp *, const struct eqn *);
|
||||
void term_tbl(struct termp *, const struct tbl_span *);
|
||||
void term_free(struct termp *);
|
||||
void term_newln(struct termp *);
|
||||
void term_vspace(struct termp *);
|
||||
void term_word(struct termp *, const char *);
|
||||
void term_flushln(struct termp *);
|
||||
void term_begin(struct termp *, term_margin,
|
||||
term_margin, const void *);
|
||||
void term_end(struct termp *);
|
||||
|
||||
size_t term_hspan(const struct termp *,
|
||||
const struct roffsu *);
|
||||
size_t term_vspan(const struct termp *,
|
||||
const struct roffsu *);
|
||||
size_t term_strlen(const struct termp *, const char *);
|
||||
size_t term_len(const struct termp *, size_t);
|
||||
|
||||
enum termfont term_fonttop(struct termp *);
|
||||
const void *term_fontq(struct termp *);
|
||||
void term_fontpush(struct termp *, enum termfont);
|
||||
void term_fontpop(struct termp *);
|
||||
void term_fontpopq(struct termp *, const void *);
|
||||
void term_fontrepl(struct termp *, enum termfont);
|
||||
void term_fontlast(struct termp *);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /*!TERM_H*/
|
289
contrib/mdocml/term_ascii.c
Normal file
289
contrib/mdocml/term_ascii.c
Normal file
@ -0,0 +1,289 @@
|
||||
/* $Id: term_ascii.c,v 1.20 2011/12/04 23:10:52 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2010, 2011 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#ifdef USE_WCHAR
|
||||
# include <locale.h>
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#ifdef USE_WCHAR
|
||||
# include <wchar.h>
|
||||
#endif
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "out.h"
|
||||
#include "term.h"
|
||||
#include "main.h"
|
||||
|
||||
/*
|
||||
* Sadly, this doesn't seem to be defined on systems even when they
|
||||
* support it. For the time being, remove it and let those compiling
|
||||
* the software decide for themselves what to use.
|
||||
*/
|
||||
#if 0
|
||||
#if ! defined(__STDC_ISO_10646__)
|
||||
# undef USE_WCHAR
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static struct termp *ascii_init(enum termenc, char *);
|
||||
static double ascii_hspan(const struct termp *,
|
||||
const struct roffsu *);
|
||||
static size_t ascii_width(const struct termp *, int);
|
||||
static void ascii_advance(struct termp *, size_t);
|
||||
static void ascii_begin(struct termp *);
|
||||
static void ascii_end(struct termp *);
|
||||
static void ascii_endline(struct termp *);
|
||||
static void ascii_letter(struct termp *, int);
|
||||
|
||||
#ifdef USE_WCHAR
|
||||
static void locale_advance(struct termp *, size_t);
|
||||
static void locale_endline(struct termp *);
|
||||
static void locale_letter(struct termp *, int);
|
||||
static size_t locale_width(const struct termp *, int);
|
||||
#endif
|
||||
|
||||
static struct termp *
|
||||
ascii_init(enum termenc enc, char *outopts)
|
||||
{
|
||||
const char *toks[4];
|
||||
char *v;
|
||||
struct termp *p;
|
||||
|
||||
p = mandoc_calloc(1, sizeof(struct termp));
|
||||
p->enc = enc;
|
||||
|
||||
p->tabwidth = 5;
|
||||
p->defrmargin = 78;
|
||||
|
||||
p->begin = ascii_begin;
|
||||
p->end = ascii_end;
|
||||
p->hspan = ascii_hspan;
|
||||
p->type = TERMTYPE_CHAR;
|
||||
|
||||
p->enc = TERMENC_ASCII;
|
||||
p->advance = ascii_advance;
|
||||
p->endline = ascii_endline;
|
||||
p->letter = ascii_letter;
|
||||
p->width = ascii_width;
|
||||
|
||||
#ifdef USE_WCHAR
|
||||
if (TERMENC_ASCII != enc) {
|
||||
v = TERMENC_LOCALE == enc ?
|
||||
setlocale(LC_ALL, "") :
|
||||
setlocale(LC_CTYPE, "UTF-8");
|
||||
if (NULL != v && MB_CUR_MAX > 1) {
|
||||
p->enc = enc;
|
||||
p->advance = locale_advance;
|
||||
p->endline = locale_endline;
|
||||
p->letter = locale_letter;
|
||||
p->width = locale_width;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
toks[0] = "indent";
|
||||
toks[1] = "width";
|
||||
toks[2] = "mdoc";
|
||||
toks[3] = NULL;
|
||||
|
||||
while (outopts && *outopts)
|
||||
switch (getsubopt(&outopts, UNCONST(toks), &v)) {
|
||||
case (0):
|
||||
p->defindent = (size_t)atoi(v);
|
||||
break;
|
||||
case (1):
|
||||
p->defrmargin = (size_t)atoi(v);
|
||||
break;
|
||||
case (2):
|
||||
/*
|
||||
* Temporary, undocumented mode
|
||||
* to imitate mdoc(7) output style.
|
||||
*/
|
||||
p->mdocstyle = 1;
|
||||
p->defindent = 5;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Enforce a lower boundary. */
|
||||
if (p->defrmargin < 58)
|
||||
p->defrmargin = 58;
|
||||
|
||||
return(p);
|
||||
}
|
||||
|
||||
void *
|
||||
ascii_alloc(char *outopts)
|
||||
{
|
||||
|
||||
return(ascii_init(TERMENC_ASCII, outopts));
|
||||
}
|
||||
|
||||
void *
|
||||
utf8_alloc(char *outopts)
|
||||
{
|
||||
|
||||
return(ascii_init(TERMENC_UTF8, outopts));
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
locale_alloc(char *outopts)
|
||||
{
|
||||
|
||||
return(ascii_init(TERMENC_LOCALE, outopts));
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static size_t
|
||||
ascii_width(const struct termp *p, int c)
|
||||
{
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
void
|
||||
ascii_free(void *arg)
|
||||
{
|
||||
|
||||
term_free((struct termp *)arg);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
ascii_letter(struct termp *p, int c)
|
||||
{
|
||||
|
||||
putchar(c);
|
||||
}
|
||||
|
||||
static void
|
||||
ascii_begin(struct termp *p)
|
||||
{
|
||||
|
||||
(*p->headf)(p, p->argf);
|
||||
}
|
||||
|
||||
static void
|
||||
ascii_end(struct termp *p)
|
||||
{
|
||||
|
||||
(*p->footf)(p, p->argf);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
ascii_endline(struct termp *p)
|
||||
{
|
||||
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
ascii_advance(struct termp *p, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#ifdef USE_WCHAR
|
||||
/* ARGSUSED */
|
||||
static size_t
|
||||
locale_width(const struct termp *p, int c)
|
||||
{
|
||||
int rc;
|
||||
|
||||
return((rc = wcwidth(c)) < 0 ? 0 : rc);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
locale_advance(struct termp *p, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
putwchar(L' ');
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
locale_endline(struct termp *p)
|
||||
{
|
||||
|
||||
putwchar(L'\n');
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
locale_letter(struct termp *p, int c)
|
||||
{
|
||||
|
||||
putwchar(c);
|
||||
}
|
||||
#endif
|
1185
contrib/mdocml/term_ps.c
Normal file
1185
contrib/mdocml/term_ps.c
Normal file
File diff suppressed because it is too large
Load Diff
349
contrib/mdocml/tree.c
Normal file
349
contrib/mdocml/tree.c
Normal file
@ -0,0 +1,349 @@
|
||||
/* $Id: tree.c,v 1.47 2011/09/18 14:14:15 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2011 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "mdoc.h"
|
||||
#include "man.h"
|
||||
#include "main.h"
|
||||
|
||||
static void print_box(const struct eqn_box *, int);
|
||||
static void print_man(const struct man_node *, int);
|
||||
static void print_mdoc(const struct mdoc_node *, int);
|
||||
static void print_span(const struct tbl_span *, int);
|
||||
|
||||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
tree_mdoc(void *arg, const struct mdoc *mdoc)
|
||||
{
|
||||
|
||||
print_mdoc(mdoc_node(mdoc), 0);
|
||||
}
|
||||
|
||||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
tree_man(void *arg, const struct man *man)
|
||||
{
|
||||
|
||||
print_man(man_node(man), 0);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
print_mdoc(const struct mdoc_node *n, int indent)
|
||||
{
|
||||
const char *p, *t;
|
||||
int i, j;
|
||||
size_t argc, sz;
|
||||
char **params;
|
||||
struct mdoc_argv *argv;
|
||||
|
||||
argv = NULL;
|
||||
argc = sz = 0;
|
||||
params = NULL;
|
||||
t = p = NULL;
|
||||
|
||||
switch (n->type) {
|
||||
case (MDOC_ROOT):
|
||||
t = "root";
|
||||
break;
|
||||
case (MDOC_BLOCK):
|
||||
t = "block";
|
||||
break;
|
||||
case (MDOC_HEAD):
|
||||
t = "block-head";
|
||||
break;
|
||||
case (MDOC_BODY):
|
||||
if (n->end)
|
||||
t = "body-end";
|
||||
else
|
||||
t = "block-body";
|
||||
break;
|
||||
case (MDOC_TAIL):
|
||||
t = "block-tail";
|
||||
break;
|
||||
case (MDOC_ELEM):
|
||||
t = "elem";
|
||||
break;
|
||||
case (MDOC_TEXT):
|
||||
t = "text";
|
||||
break;
|
||||
case (MDOC_TBL):
|
||||
/* FALLTHROUGH */
|
||||
case (MDOC_EQN):
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
switch (n->type) {
|
||||
case (MDOC_TEXT):
|
||||
p = n->string;
|
||||
break;
|
||||
case (MDOC_BODY):
|
||||
p = mdoc_macronames[n->tok];
|
||||
break;
|
||||
case (MDOC_HEAD):
|
||||
p = mdoc_macronames[n->tok];
|
||||
break;
|
||||
case (MDOC_TAIL):
|
||||
p = mdoc_macronames[n->tok];
|
||||
break;
|
||||
case (MDOC_ELEM):
|
||||
p = mdoc_macronames[n->tok];
|
||||
if (n->args) {
|
||||
argv = n->args->argv;
|
||||
argc = n->args->argc;
|
||||
}
|
||||
break;
|
||||
case (MDOC_BLOCK):
|
||||
p = mdoc_macronames[n->tok];
|
||||
if (n->args) {
|
||||
argv = n->args->argv;
|
||||
argc = n->args->argc;
|
||||
}
|
||||
break;
|
||||
case (MDOC_TBL):
|
||||
/* FALLTHROUGH */
|
||||
case (MDOC_EQN):
|
||||
break;
|
||||
case (MDOC_ROOT):
|
||||
p = "root";
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
if (n->span) {
|
||||
assert(NULL == p && NULL == t);
|
||||
print_span(n->span, indent);
|
||||
} else if (n->eqn) {
|
||||
assert(NULL == p && NULL == t);
|
||||
print_box(n->eqn->root, indent);
|
||||
} else {
|
||||
for (i = 0; i < indent; i++)
|
||||
putchar('\t');
|
||||
|
||||
printf("%s (%s)", p, t);
|
||||
|
||||
for (i = 0; i < (int)argc; i++) {
|
||||
printf(" -%s", mdoc_argnames[argv[i].arg]);
|
||||
if (argv[i].sz > 0)
|
||||
printf(" [");
|
||||
for (j = 0; j < (int)argv[i].sz; j++)
|
||||
printf(" [%s]", argv[i].value[j]);
|
||||
if (argv[i].sz > 0)
|
||||
printf(" ]");
|
||||
}
|
||||
|
||||
for (i = 0; i < (int)sz; i++)
|
||||
printf(" [%s]", params[i]);
|
||||
|
||||
printf(" %d:%d\n", n->line, n->pos);
|
||||
}
|
||||
|
||||
if (n->child)
|
||||
print_mdoc(n->child, indent + 1);
|
||||
if (n->next)
|
||||
print_mdoc(n->next, indent);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
print_man(const struct man_node *n, int indent)
|
||||
{
|
||||
const char *p, *t;
|
||||
int i;
|
||||
|
||||
t = p = NULL;
|
||||
|
||||
switch (n->type) {
|
||||
case (MAN_ROOT):
|
||||
t = "root";
|
||||
break;
|
||||
case (MAN_ELEM):
|
||||
t = "elem";
|
||||
break;
|
||||
case (MAN_TEXT):
|
||||
t = "text";
|
||||
break;
|
||||
case (MAN_BLOCK):
|
||||
t = "block";
|
||||
break;
|
||||
case (MAN_HEAD):
|
||||
t = "block-head";
|
||||
break;
|
||||
case (MAN_BODY):
|
||||
t = "block-body";
|
||||
break;
|
||||
case (MAN_TAIL):
|
||||
t = "block-tail";
|
||||
break;
|
||||
case (MAN_TBL):
|
||||
/* FALLTHROUGH */
|
||||
case (MAN_EQN):
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
switch (n->type) {
|
||||
case (MAN_TEXT):
|
||||
p = n->string;
|
||||
break;
|
||||
case (MAN_ELEM):
|
||||
/* FALLTHROUGH */
|
||||
case (MAN_BLOCK):
|
||||
/* FALLTHROUGH */
|
||||
case (MAN_HEAD):
|
||||
/* FALLTHROUGH */
|
||||
case (MAN_TAIL):
|
||||
/* FALLTHROUGH */
|
||||
case (MAN_BODY):
|
||||
p = man_macronames[n->tok];
|
||||
break;
|
||||
case (MAN_ROOT):
|
||||
p = "root";
|
||||
break;
|
||||
case (MAN_TBL):
|
||||
/* FALLTHROUGH */
|
||||
case (MAN_EQN):
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
if (n->span) {
|
||||
assert(NULL == p && NULL == t);
|
||||
print_span(n->span, indent);
|
||||
} else if (n->eqn) {
|
||||
assert(NULL == p && NULL == t);
|
||||
print_box(n->eqn->root, indent);
|
||||
} else {
|
||||
for (i = 0; i < indent; i++)
|
||||
putchar('\t');
|
||||
printf("%s (%s) %d:%d\n", p, t, n->line, n->pos);
|
||||
}
|
||||
|
||||
if (n->child)
|
||||
print_man(n->child, indent + 1);
|
||||
if (n->next)
|
||||
print_man(n->next, indent);
|
||||
}
|
||||
|
||||
static void
|
||||
print_box(const struct eqn_box *ep, int indent)
|
||||
{
|
||||
int i;
|
||||
const char *t;
|
||||
|
||||
if (NULL == ep)
|
||||
return;
|
||||
for (i = 0; i < indent; i++)
|
||||
putchar('\t');
|
||||
|
||||
t = NULL;
|
||||
switch (ep->type) {
|
||||
case (EQN_ROOT):
|
||||
t = "eqn-root";
|
||||
break;
|
||||
case (EQN_LIST):
|
||||
t = "eqn-list";
|
||||
break;
|
||||
case (EQN_SUBEXPR):
|
||||
t = "eqn-expr";
|
||||
break;
|
||||
case (EQN_TEXT):
|
||||
t = "eqn-text";
|
||||
break;
|
||||
case (EQN_MATRIX):
|
||||
t = "eqn-matrix";
|
||||
break;
|
||||
}
|
||||
|
||||
assert(t);
|
||||
printf("%s(%d, %d, %d, %d, %d, \"%s\", \"%s\") %s\n",
|
||||
t, EQN_DEFSIZE == ep->size ? 0 : ep->size,
|
||||
ep->pos, ep->font, ep->mark, ep->pile,
|
||||
ep->left ? ep->left : "",
|
||||
ep->right ? ep->right : "",
|
||||
ep->text ? ep->text : "");
|
||||
|
||||
print_box(ep->first, indent + 1);
|
||||
print_box(ep->next, indent);
|
||||
}
|
||||
|
||||
static void
|
||||
print_span(const struct tbl_span *sp, int indent)
|
||||
{
|
||||
const struct tbl_dat *dp;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < indent; i++)
|
||||
putchar('\t');
|
||||
|
||||
switch (sp->pos) {
|
||||
case (TBL_SPAN_HORIZ):
|
||||
putchar('-');
|
||||
return;
|
||||
case (TBL_SPAN_DHORIZ):
|
||||
putchar('=');
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (dp = sp->first; dp; dp = dp->next) {
|
||||
switch (dp->pos) {
|
||||
case (TBL_DATA_HORIZ):
|
||||
/* FALLTHROUGH */
|
||||
case (TBL_DATA_NHORIZ):
|
||||
putchar('-');
|
||||
continue;
|
||||
case (TBL_DATA_DHORIZ):
|
||||
/* FALLTHROUGH */
|
||||
case (TBL_DATA_NDHORIZ):
|
||||
putchar('=');
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
printf("[\"%s\"", dp->string ? dp->string : "");
|
||||
if (dp->spans)
|
||||
printf("(%d)", dp->spans);
|
||||
if (NULL == dp->layout)
|
||||
putchar('*');
|
||||
putchar(']');
|
||||
putchar(' ');
|
||||
}
|
||||
|
||||
printf("(tbl) %d:1\n", sp->line);
|
||||
}
|
39
contrib/mdocml/vol.c
Normal file
39
contrib/mdocml/vol.c
Normal file
@ -0,0 +1,39 @@
|
||||
/* $Id: vol.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "mdoc.h"
|
||||
#include "mandoc.h"
|
||||
#include "libmdoc.h"
|
||||
|
||||
#define LINE(x, y) \
|
||||
if (0 == strcmp(p, x)) return(y);
|
||||
|
||||
const char *
|
||||
mdoc_a2vol(const char *p)
|
||||
{
|
||||
|
||||
#include "vol.in"
|
||||
|
||||
return(NULL);
|
||||
}
|
35
contrib/mdocml/vol.in
Normal file
35
contrib/mdocml/vol.in
Normal file
@ -0,0 +1,35 @@
|
||||
/* $Id: vol.in,v 1.6 2010/06/19 20:46:28 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file defines volume titles for .Dt.
|
||||
*
|
||||
* Be sure to escape strings.
|
||||
*/
|
||||
|
||||
LINE("USD", "User\'s Supplementary Documents")
|
||||
LINE("PS1", "Programmer\'s Supplementary Documents")
|
||||
LINE("AMD", "Ancestral Manual Documents")
|
||||
LINE("SMM", "System Manager\'s Manual")
|
||||
LINE("URM", "User\'s Reference Manual")
|
||||
LINE("PRM", "Programmer\'s Manual")
|
||||
LINE("KM", "Kernel Manual")
|
||||
LINE("IND", "Manual Master Index")
|
||||
LINE("MMI", "Manual Master Index")
|
||||
LINE("LOCAL", "Local Manual")
|
||||
LINE("LOC", "Local Manual")
|
||||
LINE("CON", "Contributed Software Manual")
|
@ -944,6 +944,8 @@
|
||||
man9
|
||||
..
|
||||
..
|
||||
mdocml
|
||||
..
|
||||
misc
|
||||
fonts
|
||||
..
|
||||
|
20
lib/libmandoc/Makefile
Normal file
20
lib/libmandoc/Makefile
Normal file
@ -0,0 +1,20 @@
|
||||
# $FreeBSD$
|
||||
|
||||
MDOCMLDIR= ${.CURDIR}/../../contrib/mdocml
|
||||
.PATH: ${MDOCMLDIR}
|
||||
|
||||
LIB= mandoc
|
||||
#NO_PIC=
|
||||
INTERNALLIB=
|
||||
MAN= mandoc.3
|
||||
SRCS= arch.c att.c chars.c \
|
||||
compat_fgetln.c compat_getsubopt.c compat_strlcat.c compat_strlcpy.c \
|
||||
eqn.c lib.c man.c man_hash.c man_macro.c man_validate.c mandoc.c \
|
||||
mdoc.c mdoc_argv.c mdoc_hash.c mdoc_macro.c mdoc_validate.c \
|
||||
msec.c read.c roff.c st.c \
|
||||
tbl.c tbl_data.c tbl_layout.c tbl_opts.c vol.c
|
||||
|
||||
WARNS?= 3
|
||||
CFLAGS+= -DHAVE_CONFIG_H -DVERSION="\"1.12.1\""
|
||||
|
||||
.include <bsd.lib.mk>
|
22
usr.bin/mandoc/Makefile
Normal file
22
usr.bin/mandoc/Makefile
Normal file
@ -0,0 +1,22 @@
|
||||
# $FreeBSD$
|
||||
|
||||
MDOCMLDIR= ${.CURDIR}/../../contrib/mdocml
|
||||
LIBMANDOC= ${.OBJDIR}/../../lib/libmandoc/libmandoc.a
|
||||
.PATH: ${MDOCMLDIR}
|
||||
|
||||
PROG= mandoc
|
||||
FILES= example.style.css external.png style.css
|
||||
FILESDIR= ${SHAREDIR}/mdocml
|
||||
LINKS= mdocml
|
||||
MAN= mandoc.1 eqn.7 mandoc_char.7 tbl.7 # man.7 mdoc.7 roff.7
|
||||
MLINKS= mandoc.1 mdocml.1
|
||||
SRCS= eqn_html.c eqn_term.c html.c main.c man_html.c man_term.c mdoc_html.c \
|
||||
mdoc_man.c mdoc_term.c out.c tbl_html.c tbl_term.c term.c \
|
||||
term_ascii.c term_ps.c tree.c
|
||||
|
||||
WARNS?= 3
|
||||
CFLAGS+= -DHAVE_CONFIG_H -DVERSION="\"1.12.1\""
|
||||
DPADD= ${LIBMANDOC}
|
||||
LDADD= ${LIBMANDOC}
|
||||
|
||||
.include <bsd.prog.mk>
|
Loading…
x
Reference in New Issue
Block a user